From 2283aaffad6ed6b179133928120679474e6dee5f Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 19 Mar 2019 14:29:02 +0300 Subject: [PATCH] Fixed descriptors --- .../dataforge/descriptors/NodeDescriptor.kt | 64 ++++----- .../dataforge/descriptors/ValueDescriptor.kt | 27 +++- .../hep/dataforge/descriptors/annotations.kt | 14 +- .../hep/dataforge/meta/ConfigDelegates.kt | 24 ++-- .../kotlin/hep/dataforge/meta/Delegates.kt | 122 +++++++++--------- .../hep/dataforge/meta/ExtraMetaDelegates.kt | 2 +- .../kotlin/hep/dataforge/meta/MutableMeta.kt | 2 + .../hep/dataforge/meta/Specification.kt | 2 +- .../kotlin/hep/dataforge/meta/Styled.kt | 2 +- .../kotlin/hep/dataforge/meta/jsMeta.kt | 2 - 10 files changed, 137 insertions(+), 124 deletions(-) diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/NodeDescriptor.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/NodeDescriptor.kt index 2d7fa6be..bf09cf70 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/NodeDescriptor.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/NodeDescriptor.kt @@ -22,6 +22,7 @@ package hep.dataforge.descriptors import hep.dataforge.meta.* +import hep.dataforge.names.NameToken import hep.dataforge.names.toName /** @@ -39,6 +40,14 @@ class NodeDescriptor(override val config: Config) : Specification { */ var name: String by string { error("Anonymous descriptors are not allowed") } + + /** + * The default for this node. Null if there is no default. + * + * @return + */ + var default: Meta? by node() + /** * True if multiple children with this nodes name are allowed. Anonymous * nodes are always single @@ -52,7 +61,7 @@ class NodeDescriptor(override val config: Config) : Specification { * * @return */ - var required: Boolean by boolean(false) + var required: Boolean by boolean { default == null } /** * The node description @@ -78,6 +87,18 @@ class NodeDescriptor(override val config: Config) : Specification { name to ValueDescriptor.wrap(node.node ?: error("Value descriptor must be a node")) } + fun value(name: String, descriptor: ValueDescriptor) { + val token = NameToken("value", name) + config[token] = descriptor.config + } + + /** + * Add a value descriptor using block for + */ + fun value(name: String, block: ValueDescriptor.() -> Unit) { + value(name, ValueDescriptor.build { this.name = name }.apply(block)) + } + /** * The map of children node descriptors */ @@ -87,43 +108,15 @@ class NodeDescriptor(override val config: Config) : Specification { } - /** - * Check if this node has default - * - * @return - */ - fun hasDefault(): Boolean { - return meta.hasMeta("default") + fun node(name: String, descriptor: NodeDescriptor) { + val token = NameToken("node", name) + config[token] = descriptor.config } - /** - * The default meta for this node (could be multiple). Null if not defined - * - * @return - */ - val default: List by nodeList(def = emptyList()) - - /** - * Identify if this descriptor has child value descriptor with default - * - * @param name - * @return - */ - fun hasDefaultForValue(name: String): Boolean { - return getValueDescriptor(name)?.hasDefault() ?: false + fun node(name: String, block: NodeDescriptor.() -> Unit) { + node(name, NodeDescriptor.build { this.name = name }.apply(block)) } - /** - * The key of the value which is used to display this node in case it is - * multiple. By default, the key is empty which means that node index is - * used. - * - * @return - */ - val key: String by stringValue(def = "") - - - fun builder(): DescriptorBuilder = DescriptorBuilder(this.name, Configuration(this.meta)) //override val descriptor: NodeDescriptor = empty("descriptor") @@ -131,8 +124,5 @@ class NodeDescriptor(override val config: Config) : Specification { override fun wrap(config: Config): NodeDescriptor = NodeDescriptor(config) - fun empty(nodeName: String): NodeDescriptor { - return NodeDescriptor(Meta.buildEmpty(nodeName)) - } } } diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/ValueDescriptor.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/ValueDescriptor.kt index 3416b55b..7f066e99 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/ValueDescriptor.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/ValueDescriptor.kt @@ -17,7 +17,10 @@ package hep.dataforge.descriptors import hep.dataforge.meta.* -import hep.dataforge.values.* +import hep.dataforge.values.False +import hep.dataforge.values.True +import hep.dataforge.values.Value +import hep.dataforge.values.ValueType /** * A descriptor for meta value @@ -35,6 +38,10 @@ class ValueDescriptor(override val config: Config) : Specification { */ var default: Value? by value() + fun default(v: Any) { + this.default = Value.of(v) + } + /** * True if multiple values with this name are allowed. * @@ -72,6 +79,10 @@ class ValueDescriptor(override val config: Config) : Specification { it?.list?.map { v -> ValueType.valueOf(v.string) } ?: emptyList() } + fun type(vararg t: ValueType) { + this.type = listOf(*t) + } + var tags: List by value().map { value -> value?.list?.map { it.string } ?: emptyList() } @@ -103,10 +114,24 @@ class ValueDescriptor(override val config: Config) : Specification { } } + /** + * Allow given list of value and forbid others + */ + fun allow(vararg v: Any) { + this.allowedValues = v.map { Value.of(it) } + } + companion object : SpecificationCompanion { override fun wrap(config: Config): ValueDescriptor = ValueDescriptor(config) + inline fun > enum(name: String) = + ValueDescriptor.build { + this.name = name + type(ValueType.STRING) + this.allowedValues = enumValues().map { Value.of(it.name) } + } + // /** // * Build a value descriptor from annotation // */ diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/annotations.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/annotations.kt index 25349ea7..d65a0e79 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/annotations.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/annotations.kt @@ -23,14 +23,14 @@ import kotlin.reflect.KClass @MustBeDocumented annotation class ValueDef( val key: String, - val type: Array = [ValueType.STRING], + val type: Array = arrayOf(ValueType.STRING), val multiple: Boolean = false, val def: String = "", val info: String = "", val required: Boolean = true, - val allowed: Array = [], + val allowed: Array = emptyArray(), val enumeration: KClass<*> = Any::class, - val tags: Array = [] + val tags: Array = emptyArray() ) @MustBeDocumented @@ -39,11 +39,11 @@ annotation class NodeDef( val info: String = "", val multiple: Boolean = false, val required: Boolean = false, - val tags: Array = [], + val tags: Array = emptyArray(), /** * A list of child value descriptors */ - val values: Array = [], + val values: Array = emptyArray(), /** * A target class for this node to describe * @return @@ -135,11 +135,11 @@ annotation class DescriptorValue(val def: ValueDef) @MustBeDocumented annotation class ValueProperty( val name: String = "", - val type: Array = [ValueType.STRING], + val type: Array = arrayOf(ValueType.STRING), val multiple: Boolean = false, val def: String = "", val enumeration: KClass<*> = Any::class, - val tags: Array = [] + val tags: Array = emptyArray() ) diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ConfigDelegates.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ConfigDelegates.kt index 8e717948..9a5f15cb 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ConfigDelegates.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ConfigDelegates.kt @@ -11,45 +11,45 @@ import kotlin.jvm.JvmName * A property delegate that uses custom key */ fun Configurable.value(default: Any = Null, key: String? = null) = - ValueConfigDelegate(config, key, Value.of(default)) + MutableValueDelegate(config, key, Value.of(default)) fun Configurable.string(default: String? = null, key: String? = null) = - StringConfigDelegate(config, key, default) + MutableStringDelegate(config, key, default) fun Configurable.boolean(default: Boolean? = null, key: String? = null) = - BooleanConfigDelegate(config, key, default) + MutableBooleanDelegate(config, key, default) fun Configurable.number(default: Number? = null, key: String? = null) = - NumberConfigDelegate(config, key, default) + MutableNumberDelegate(config, key, default) -fun Configurable.child(key: String? = null) = MetaNodeDelegate(config, key) +fun Configurable.node(key: String? = null) = MutableNodeDelegate(config, key) //fun Configurable.spec(spec: Specification, key: String? = null) = ChildConfigDelegate(key) { spec.wrap(this) } @JvmName("safeString") fun Configurable.string(default: String, key: String? = null) = - SafeStringConfigDelegate(config, key) { default } + MutableSafeStringDelegate(config, key) { default } @JvmName("safeBoolean") fun Configurable.boolean(default: Boolean, key: String? = null) = - SafeBooleanConfigDelegate(config, key) { default } + MutableSafeBooleanDelegate(config, key) { default } @JvmName("safeNumber") fun Configurable.number(default: Number, key: String? = null) = - SafeNumberConfigDelegate(config, key) { default } + MutableSafeNumberDelegate(config, key) { default } @JvmName("safeString") fun Configurable.string(key: String? = null, default: () -> String) = - SafeStringConfigDelegate(config, key, default) + MutableSafeStringDelegate(config, key, default) @JvmName("safeBoolean") fun Configurable.boolean(key: String? = null, default: () -> Boolean) = - SafeBooleanConfigDelegate(config, key, default) + MutableSafeBooleanDelegate(config, key, default) @JvmName("safeNumber") fun Configurable.number(key: String? = null, default: () -> Number) = - SafeNumberConfigDelegate(config, key, default) + MutableSafeNumberDelegate(config, key, default) inline fun > Configurable.enum(default: E, key: String? = null) = - SafeEnumvConfigDelegate(config, key, default) { enumValueOf(it) } \ No newline at end of file + MutableSafeEnumvDelegate(config, key, default) { enumValueOf(it) } \ No newline at end of file diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Delegates.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Delegates.kt index 5a7e845d..119b78b0 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Delegates.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Delegates.kt @@ -164,23 +164,23 @@ inline fun > Meta.enum(default: E, key: String? = null) = SafeEnumDelegate(this, key, default) { enumValueOf(it) } -/* Config delegates */ +/* Read-write delegates */ -class ValueConfigDelegate>( - val config: M, +class MutableValueDelegate>( + val meta: M, private val key: String? = null, private val default: Value? = null ) : ReadWriteProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): Value? { - return config[key ?: property.name]?.value ?: default + return meta[key ?: property.name]?.value ?: default } override fun setValue(thisRef: Any?, property: KProperty<*>, value: Value?) { val name = key ?: property.name if (value == null) { - config.remove(name) + meta.remove(name) } else { - config.setValue(name, value) + meta.setValue(name, value) } } @@ -188,59 +188,59 @@ class ValueConfigDelegate>( ReadWriteDelegateWrapper(this, reader, writer) } -class StringConfigDelegate>( - val config: M, +class MutableStringDelegate>( + val meta: M, private val key: String? = null, private val default: String? = null ) : ReadWriteProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): String? { - return config[key ?: property.name]?.string ?: default + return meta[key ?: property.name]?.string ?: default } override fun setValue(thisRef: Any?, property: KProperty<*>, value: String?) { val name = key ?: property.name if (value == null) { - config.remove(name) + meta.remove(name) } else { - config.setValue(name, value.asValue()) + meta.setValue(name, value.asValue()) } } } -class BooleanConfigDelegate>( - val config: M, +class MutableBooleanDelegate>( + val meta: M, private val key: String? = null, private val default: Boolean? = null ) : ReadWriteProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean? { - return config[key ?: property.name]?.boolean ?: default + return meta[key ?: property.name]?.boolean ?: default } override fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean?) { val name = key ?: property.name if (value == null) { - config.remove(name) + meta.remove(name) } else { - config.setValue(name, value.asValue()) + meta.setValue(name, value.asValue()) } } } -class NumberConfigDelegate>( - val config: M, +class MutableNumberDelegate>( + val meta: M, private val key: String? = null, private val default: Number? = null ) : ReadWriteProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): Number? { - return config[key ?: property.name]?.number ?: default + return meta[key ?: property.name]?.number ?: default } override fun setValue(thisRef: Any?, property: KProperty<*>, value: Number?) { val name = key ?: property.name if (value == null) { - config.remove(name) + meta.remove(name) } else { - config.setValue(name, value.asValue()) + meta.setValue(name, value.asValue()) } } @@ -252,8 +252,8 @@ class NumberConfigDelegate>( //Delegates with non-null values -class SafeStringConfigDelegate>( - val config: M, +class MutableSafeStringDelegate>( + val meta: M, private val key: String? = null, default: () -> String ) : ReadWriteProperty { @@ -261,16 +261,16 @@ class SafeStringConfigDelegate>( private val default: String by lazy(default) override fun getValue(thisRef: Any?, property: KProperty<*>): String { - return config[key ?: property.name]?.string ?: default + return meta[key ?: property.name]?.string ?: default } override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { - config.setValue(key ?: property.name, value.asValue()) + meta.setValue(key ?: property.name, value.asValue()) } } -class SafeBooleanConfigDelegate>( - val config: M, +class MutableSafeBooleanDelegate>( + val meta: M, private val key: String? = null, default: () -> Boolean ) : ReadWriteProperty { @@ -278,16 +278,16 @@ class SafeBooleanConfigDelegate>( private val default: Boolean by lazy(default) override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean { - return config[key ?: property.name]?.boolean ?: default + return meta[key ?: property.name]?.boolean ?: default } override fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean) { - config.setValue(key ?: property.name, value.asValue()) + meta.setValue(key ?: property.name, value.asValue()) } } -class SafeNumberConfigDelegate>( - val config: M, +class MutableSafeNumberDelegate>( + val meta: M, private val key: String? = null, default: () -> Number ) : ReadWriteProperty { @@ -295,11 +295,11 @@ class SafeNumberConfigDelegate>( private val default: Number by lazy(default) override fun getValue(thisRef: Any?, property: KProperty<*>): Number { - return config[key ?: property.name]?.number ?: default + return meta[key ?: property.name]?.number ?: default } override fun setValue(thisRef: Any?, property: KProperty<*>, value: Number) { - config.setValue(key ?: property.name, value.asValue()) + meta.setValue(key ?: property.name, value.asValue()) } val double get() = ReadWriteDelegateWrapper(this, reader = { it.toDouble() }, writer = { it }) @@ -308,48 +308,48 @@ class SafeNumberConfigDelegate>( val long get() = ReadWriteDelegateWrapper(this, reader = { it.toLong() }, writer = { it }) } -class SafeEnumvConfigDelegate, E : Enum>( - val config: M, +class MutableSafeEnumvDelegate, E : Enum>( + val meta: M, private val key: String? = null, private val default: E, private val resolver: (String) -> E ) : ReadWriteProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): E { - return (config[key ?: property.name]?.string)?.let { resolver(it) } ?: default + return (meta[key ?: property.name]?.string)?.let { resolver(it) } ?: default } override fun setValue(thisRef: Any?, property: KProperty<*>, value: E) { - config.setValue(key ?: property.name, value.name.asValue()) + meta.setValue(key ?: property.name, value.name.asValue()) } } //Child node delegate -class MetaNodeDelegate>( - val config: M, +class MutableNodeDelegate>( + val meta: M, private val key: String? = null -) : ReadWriteProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): Meta { - return config[key ?: property.name]?.node ?: EmptyMeta +) : ReadWriteProperty { + override fun getValue(thisRef: Any?, property: KProperty<*>): Meta? { + return meta[key ?: property.name]?.node } - override fun setValue(thisRef: Any?, property: KProperty<*>, value: Meta) { - config[key ?: property.name] = value + override fun setValue(thisRef: Any?, property: KProperty<*>, value: Meta?) { + meta[key ?: property.name] = value } } -class ChildConfigDelegate, T : Configurable>( - val config: M, +class MutableMorphDelegate, T : Configurable>( + val meta: M, private val key: String? = null, private val converter: (Meta) -> T ) : ReadWriteProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): T { - return converter(config[key ?: property.name]?.node ?: EmptyMeta) + return converter(meta[key ?: property.name]?.node ?: EmptyMeta) } override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { - config[key ?: property.name] = value.config + meta[key ?: property.name] = value.config } } @@ -374,45 +374,43 @@ class ReadWriteDelegateWrapper( * A property delegate that uses custom key */ fun > M.value(default: Value = Null, key: String? = null) = - ValueConfigDelegate(this, key, default) + MutableValueDelegate(this, key, default) fun > M.string(default: String? = null, key: String? = null) = - StringConfigDelegate(this, key, default) + MutableStringDelegate(this, key, default) fun > M.boolean(default: Boolean? = null, key: String? = null) = - BooleanConfigDelegate(this, key, default) + MutableBooleanDelegate(this, key, default) fun > M.number(default: Number? = null, key: String? = null) = - NumberConfigDelegate(this, key, default) + MutableNumberDelegate(this, key, default) -fun > M.child(key: String? = null) = MetaNodeDelegate(this, key) - -//fun Configurable.spec(spec: Specification, key: String? = null) = ChildConfigDelegate(key) { spec.wrap(this) } +fun > M.node(key: String? = null) = MutableNodeDelegate(this, key) @JvmName("safeString") fun > M.string(default: String, key: String? = null) = - SafeStringConfigDelegate(this, key) { default } + MutableSafeStringDelegate(this, key) { default } @JvmName("safeBoolean") fun > M.boolean(default: Boolean, key: String? = null) = - SafeBooleanConfigDelegate(this, key) { default } + MutableSafeBooleanDelegate(this, key) { default } @JvmName("safeNumber") fun > M.number(default: Number, key: String? = null) = - SafeNumberConfigDelegate(this, key) { default } + MutableSafeNumberDelegate(this, key) { default } @JvmName("safeString") fun > M.string(key: String? = null, default: () -> String) = - SafeStringConfigDelegate(this, key, default) + MutableSafeStringDelegate(this, key, default) @JvmName("safeBoolean") fun > M.boolean(key: String? = null, default: () -> Boolean) = - SafeBooleanConfigDelegate(this, key, default) + MutableSafeBooleanDelegate(this, key, default) @JvmName("safeNumber") fun > M.number(key: String? = null, default: () -> Number) = - SafeNumberConfigDelegate(this, key, default) + MutableSafeNumberDelegate(this, key, default) inline fun , reified E : Enum> M.enum(default: E, key: String? = null) = - SafeEnumvConfigDelegate(this, key, default) { enumValueOf(it) } + MutableSafeEnumvDelegate(this, key, default) { enumValueOf(it) } diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ExtraMetaDelegates.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ExtraMetaDelegates.kt index d0eaa54e..6e24c6d0 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ExtraMetaDelegates.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ExtraMetaDelegates.kt @@ -33,4 +33,4 @@ fun Configurable.stringList(vararg default: String = emptyArray(), key: String? fun Metoid.child(key: String? = null, converter: (Meta) -> T) = ChildDelegate(meta, key, converter) fun Configurable.child(key: String? = null, converter: (Meta) -> T) = - ChildConfigDelegate(config, key, converter) + MutableMorphDelegate(config, key, converter) diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt index 2e7f452f..1d26b2b7 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt @@ -125,6 +125,8 @@ operator fun > M.set(name: Name, value: Any?) { } } +operator fun > M.set(name: NameToken, value: Any?) = set(Name(key), value) + operator fun > M.set(key: String, value: Any?) = set(key.toName(), value) /** diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Specification.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Specification.kt index f1e2beaf..a578b119 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Specification.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Specification.kt @@ -59,4 +59,4 @@ fun , C : Specification> Specification.spec( spec: SpecificationCompanion, key: String? = null ) = - ChildConfigDelegate(config, key) { spec.wrap(config) } \ No newline at end of file + MutableMorphDelegate(config, key) { spec.wrap(config) } \ No newline at end of file diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Styled.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Styled.kt index ba802f5f..dcc36a5a 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Styled.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Styled.kt @@ -48,7 +48,7 @@ class Styled(val base: Meta, val style: Config = Config().empty()) : MutableMeta } } -fun Styled.configure(meta: Meta) = apply { style.update(style) } +fun Styled.configure(meta: Meta) = apply { style.update(meta) } fun Meta.withStyle(style: Meta = EmptyMeta) = if (this is Styled) { this.apply { this.configure(style) } diff --git a/dataforge-meta/src/jsMain/kotlin/hep/dataforge/meta/jsMeta.kt b/dataforge-meta/src/jsMain/kotlin/hep/dataforge/meta/jsMeta.kt index 9002fec1..0858f67a 100644 --- a/dataforge-meta/src/jsMain/kotlin/hep/dataforge/meta/jsMeta.kt +++ b/dataforge-meta/src/jsMain/kotlin/hep/dataforge/meta/jsMeta.kt @@ -1,8 +1,6 @@ package hep.dataforge.meta - - fun Meta.toDynamic(): dynamic { fun MetaItem<*>.toDynamic(): dynamic = when (this) { is MetaItem.ValueItem -> this.value.value.asDynamic()