From fe6760eee62a0d7733f54a60d84cac3a707ccf5d Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 10 Jan 2020 11:14:18 +0300 Subject: [PATCH] Refactor Meta delegates --- .../dataforge/descriptors/ItemDescriptor.kt | 2 +- .../kotlin/hep/dataforge/meta/Configurable.kt | 11 +- ...leDelegates.kt => ConfigurableDelegate.kt} | 45 +- .../kotlin/hep/dataforge/meta/Laminate.kt | 1 + .../kotlin/hep/dataforge/meta/MetaDelegate.kt | 98 +++++ .../hep/dataforge/meta/MutableMetaDelegate.kt | 108 +++++ .../kotlin/hep/dataforge/meta/Scheme.kt | 20 +- .../kotlin/hep/dataforge/meta/mapMeta.kt | 8 - .../hep/dataforge/meta/metaDelegates.kt | 414 ------------------ .../kotlin/hep/dataforge/meta/metaMatcher.kt | 19 +- .../kotlin/hep/dataforge/meta/SchemeTest.kt | 2 +- 11 files changed, 241 insertions(+), 487 deletions(-) rename dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/{configurableDelegates.kt => ConfigurableDelegate.kt} (80%) create mode 100644 dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaDelegate.kt create mode 100644 dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMetaDelegate.kt delete mode 100644 dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/metaDelegates.kt diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/ItemDescriptor.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/ItemDescriptor.kt index 99b3e850..514349fe 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/ItemDescriptor.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/ItemDescriptor.kt @@ -61,7 +61,7 @@ class NodeDescriptor : ItemDescriptor() { * * @return */ - var default: Config? by nullableConfig() + var default: Config? by config() /** * The map of children node descriptors diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt index c13a6214..e95b5564 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt @@ -1,5 +1,9 @@ package hep.dataforge.meta +import hep.dataforge.descriptors.Described +import hep.dataforge.descriptors.NodeDescriptor +import hep.dataforge.descriptors.defaultItem +import hep.dataforge.descriptors.get import hep.dataforge.names.Name import hep.dataforge.names.toName @@ -9,7 +13,7 @@ import hep.dataforge.names.toName * It is not possible to know if some property is declared by provider just by looking on [Configurable], * this information should be provided externally. */ -interface Configurable { +interface Configurable : Described { /** * Backing config */ @@ -19,12 +23,15 @@ interface Configurable { * Default meta item provider */ fun getDefaultItem(name: Name): MetaItem<*>? = null + + override val descriptor: NodeDescriptor? get() = null } /** * Get a property with default */ -fun Configurable.getProperty(name: Name): MetaItem<*>? = config[name] ?: getDefaultItem(name) +fun Configurable.getProperty(name: Name): MetaItem<*>? = + config[name] ?: getDefaultItem(name) ?: descriptor?.get(name)?.defaultItem() fun Configurable.getProperty(key: String) = getProperty(key.toName()) diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/configurableDelegates.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ConfigurableDelegate.kt similarity index 80% rename from dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/configurableDelegates.kt rename to dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ConfigurableDelegate.kt index 313ddd0b..31cc2c9c 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/configurableDelegates.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ConfigurableDelegate.kt @@ -28,19 +28,6 @@ open class ConfigurableDelegate( val name = key ?: property.name.asName() owner.setProperty(name, value) } - - fun transform( - writer: (T) -> MetaItem<*>? = { MetaItem.of(it) }, - reader: (MetaItem<*>?) -> T - ): ReadWriteProperty = object : ReadWriteProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): T { - return reader(this@ConfigurableDelegate.getValue(thisRef, property)) - } - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { - this@ConfigurableDelegate.setValue(thisRef, property, writer(value)) - } - } } class LazyConfigurableDelegate( @@ -55,7 +42,7 @@ class LazyConfigurableDelegate( * A property delegate that uses custom key */ fun Configurable.item(default: Any?, key: Name? = null): ConfigurableDelegate = - ConfigurableDelegate(this, key, MetaItem.of(default)) + ConfigurableDelegate(this, key, default?.let { MetaItem.of(it) }) /** * Generation of item delegate with lazy default. @@ -70,7 +57,7 @@ fun Configurable.item( writer: (T) -> MetaItem<*>? = { MetaItem.of(it) }, reader: (MetaItem<*>?) -> T ): ReadWriteProperty = - ConfigurableDelegate(this, key, default?.let { MetaItem.of(it) }).transform(reader = reader, writer = writer) + ConfigurableDelegate(this, key, default?.let { MetaItem.of(it) }).map(reader = reader, writer = writer) fun Configurable.value(default: Any? = null, key: Name? = null): ReadWriteProperty = item(default, key).transform { it.value } @@ -81,7 +68,7 @@ fun Configurable.value( writer: (T) -> Value? = { Value.of(it) }, reader: (Value?) -> T ): ReadWriteProperty = - ConfigurableDelegate(this, key, default?.let { MetaItem.of(it) }).transform( + ConfigurableDelegate(this, key, default?.let { MetaItem.of(it) }).map( reader = { reader(it.value) }, writer = { writer(it)?.let { MetaItem.ValueItem(it) } } ) @@ -194,31 +181,9 @@ fun Configurable.doubleArray(vararg doubles: Double, key: Name? = null): ReadWri /* Node delegates */ -fun Configurable.nullableConfig(key: Name? = null): ReadWriteProperty = - object : ReadWriteProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): Config? { - val name = key ?: property.name.asName() - return config[name].node - } +fun Configurable.config(key: Name? = null): ReadWriteProperty = + config.node(key) - override fun setValue(thisRef: Any?, property: KProperty<*>, value: Config?) { - val name = key ?: property.name.asName() - config[name] = value - } - } - -fun Configurable.config(key: Name? = null, default: Config.() -> Unit = {}): ReadWriteProperty = - object : ReadWriteProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): Config { - val name = key ?: property.name.asName() - return config[name].node ?: Config().apply(default).also { config[name] = it } - } - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: Config) { - val name = key ?: property.name.asName() - config[name] = value - } - } fun Configurable.spec(spec: Specification, key: Name? = null): ReadWriteProperty = object : ReadWriteProperty { diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Laminate.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Laminate.kt index c6d69967..beda1732 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Laminate.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Laminate.kt @@ -5,6 +5,7 @@ import hep.dataforge.names.NameToken /** * A meta laminate consisting of multiple immutable meta layers. For mutable front layer, use [Scheme]. + * If [layers] list contains a [Laminate] it is flat-mapped. */ class Laminate(layers: List) : MetaBase() { diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaDelegate.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaDelegate.kt new file mode 100644 index 00000000..50764a7c --- /dev/null +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaDelegate.kt @@ -0,0 +1,98 @@ +package hep.dataforge.meta + +import hep.dataforge.names.Name +import hep.dataforge.names.asName +import hep.dataforge.values.Value +import kotlin.jvm.JvmName +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KProperty + +/* Meta delegates */ + +open class MetaDelegate( + open val owner: Meta, + val key: Name? = null, + open val default: MetaItem<*>? = null +) : ReadOnlyProperty?> { + override fun getValue(thisRef: Any?, property: KProperty<*>): MetaItem<*>? { + return owner[key ?: property.name.asName()] ?: default + } +} + +class LazyMetaDelegate( + owner: Meta, + key: Name? = null, + defaultProvider: () -> MetaItem<*>? = { null } +) : MetaDelegate(owner, key) { + override val default by lazy(defaultProvider) +} + +class DelegateWrapper( + val delegate: ReadOnlyProperty, + val reader: (T) -> R +) : ReadOnlyProperty { + override fun getValue(thisRef: Any?, property: KProperty<*>): R { + return reader(delegate.getValue(thisRef, property)) + } +} + +fun ReadOnlyProperty.map(reader: (T) -> R): DelegateWrapper = + DelegateWrapper(this, reader) + + +fun Meta.item(default: Any? = null, key: Name? = null): MetaDelegate = + MetaDelegate(this, key, default?.let { MetaItem.of(it) }) + +fun Meta.lazyItem(key: Name? = null, defaultProvider: () -> Any?): LazyMetaDelegate = + LazyMetaDelegate(this, key) { defaultProvider()?.let { MetaItem.of(it) } } + +//TODO add caching for sealed nodes + + +//Read-only delegates for Metas + +/** + * A property delegate that uses custom key + */ +fun Meta.value(default: Value? = null, key: Name? = null) = + item(default, key).map { it.value } + +fun Meta.string(default: String? = null, key: Name? = null) = + item(default, key).map { it.string } + +fun Meta.boolean(default: Boolean? = null, key: Name? = null) = + item(default, key).map { it.boolean } + +fun Meta.number(default: Number? = null, key: Name? = null) = + item(default, key).map { it.number } + +fun Meta.node(key: Name? = null) = + item(key).map { it.node } + +@JvmName("safeString") +fun Meta.string(default: String, key: Name? = null) = + item(default, key).map { it.string!! } + +@JvmName("safeBoolean") +fun Meta.boolean(default: Boolean, key: Name? = null) = + item(default, key).map { it.boolean!! } + +@JvmName("safeNumber") +fun Meta.number(default: Number, key: Name? = null) = + item(default, key).map { it.number!! } + +@JvmName("lazyString") +fun Meta.string(key: Name? = null, default: () -> String) = + lazyItem(key, default).map { it.string!! } + +@JvmName("lazyBoolean") +fun Meta.boolean(key: Name? = null, default: () -> Boolean) = + lazyItem(key, default).map { it.boolean!! } + +@JvmName("lazyNumber") +fun Meta.number(key: Name? = null, default: () -> Number) = + lazyItem(key, default).map { it.number!! } + + +inline fun > Meta.enum(default: E, key: Name? = null) = + item(default, key).map { it.enum()!! } \ No newline at end of file diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMetaDelegate.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMetaDelegate.kt new file mode 100644 index 00000000..5ab6ba0c --- /dev/null +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMetaDelegate.kt @@ -0,0 +1,108 @@ +package hep.dataforge.meta + +import hep.dataforge.names.Name +import hep.dataforge.names.asName +import hep.dataforge.values.Value +import kotlin.jvm.JvmName +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty + +/* Read-write delegates */ + +open class MutableMetaDelegate>( + override val owner: M, + key: Name? = null, + default: MetaItem<*>? = null +) : MetaDelegate(owner, key, default), ReadWriteProperty?> { + + override fun setValue(thisRef: Any?, property: KProperty<*>, value: MetaItem<*>?) { + val name = key ?: property.name.asName() + owner.setItem(name, value) + } +} + +class LazyMutableMetaDelegate>( + owner: M, + key: Name? = null, + defaultProvider: () -> MetaItem<*>? = { null } +) : MutableMetaDelegate(owner, key) { + override val default by lazy(defaultProvider) +} + +class ReadWriteDelegateWrapper( + val delegate: ReadWriteProperty, + val reader: (T) -> R, + val writer: (R) -> T +) : ReadWriteProperty { + override fun getValue(thisRef: Any?, property: KProperty<*>): R { + return reader(delegate.getValue(thisRef, property)) + } + + override fun setValue(thisRef: Any?, property: KProperty<*>, value: R) { + delegate.setValue(thisRef, property, writer(value)) + } +} + +fun ReadWriteProperty.map(reader: (T) -> R, writer: (R) -> T): ReadWriteDelegateWrapper = + ReadWriteDelegateWrapper(this, reader, writer) + +fun ReadWriteProperty?>.transform(reader: (MetaItem<*>?) -> R): ReadWriteProperty = + map(reader = reader, writer = { MetaItem.of(it) }) + +fun ReadWriteProperty.transform(reader: (Value?) -> R) = + map(reader = reader, writer = { Value.of(it) }) + + +fun > M.item(default: Any? = null, key: Name? = null): MutableMetaDelegate = + MutableMetaDelegate(this, key, default?.let { MetaItem.of(it) }) + +fun > M.lazyItem(key: Name? = null, defaultProvider: () -> Any?): LazyMutableMetaDelegate = + LazyMutableMetaDelegate(this, key) { defaultProvider()?.let { MetaItem.of(it) } } + +//Read-write delegates + +/** + * A property delegate that uses custom key + */ +fun > M.value(default: Value? = null, key: Name? = null): ReadWriteProperty = + item(default, key).transform { it.value } + +fun > M.string(default: String? = null, key: Name? = null): ReadWriteProperty = + item(default, key).transform { it.string } + +fun > M.boolean(default: Boolean? = null, key: Name? = null): ReadWriteProperty = + item(default, key).transform { it.boolean } + +fun > M.number(default: Number? = null, key: Name? = null): ReadWriteProperty = + item(default, key).transform { it.number } + +inline fun > M.node(key: Name? = null) = + item(this, key).transform { it.node as? M } + +@JvmName("safeString") +fun > M.string(default: String, key: Name? = null) = + item(default, key).transform { it.string!! } + +@JvmName("safeBoolean") +fun > M.boolean(default: Boolean, key: Name? = null) = + item(default, key).transform { it.boolean!! } + +@JvmName("safeNumber") +fun > M.number(default: Number, key: Name? = null) = + item(default, key).transform { it.number!! } + +@JvmName("lazyString") +fun > M.string(key: Name? = null, default: () -> String) = + lazyItem(key, default).transform { it.string!! } + +@JvmName("safeBoolean") +fun > M.boolean(key: Name? = null, default: () -> Boolean) = + lazyItem(key, default).transform { it.boolean!! } + +@JvmName("safeNumber") +fun > M.number(key: Name? = null, default: () -> Number) = + lazyItem(key, default).transform { it.number!! } + + +inline fun , reified E : Enum> M.enum(default: E, key: Name? = null) = + item(default, key).transform { it.enum()!! } \ No newline at end of file diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Scheme.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Scheme.kt index 2de46dc0..84b350f1 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Scheme.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Scheme.kt @@ -5,6 +5,9 @@ import hep.dataforge.names.Name import hep.dataforge.names.NameToken import hep.dataforge.names.plus +/** + * A base for delegate-based or descriptor-based scheme. [Scheme] has an empty constructor to simplify usage from [Specification]. + */ open class Scheme() : Configurable, Described { constructor(config: Config, defaultProvider: (Name) -> MetaItem<*>?) : this() { this.config = config @@ -14,13 +17,14 @@ open class Scheme() : Configurable, Described { //constructor(config: Config, default: Meta) : this(config, { default[it] }) constructor(config: Config) : this(config, { null }) - final override lateinit var config: Config + final override var config: Config = Config() internal set lateinit var defaultProvider: (Name) -> MetaItem<*>? internal set - override val descriptor: NodeDescriptor? = null + final override var descriptor: NodeDescriptor? = null + internal set override fun getDefaultItem(name: Name): MetaItem<*>? { return defaultProvider(name) ?: descriptor?.get(name)?.defaultItem() @@ -60,15 +64,21 @@ open class SchemeSpec(val builder: () -> T) : Specification { } } +/** + * A scheme that uses [Meta] as a default layer + */ open class MetaScheme( val meta: Meta, - override val descriptor: NodeDescriptor? = null, + descriptor: NodeDescriptor? = null, config: Config = Config() ) : Scheme(config, meta::get) { - override val defaultLayer: Meta get() = meta + init { + this.descriptor = descriptor + } + override val defaultLayer: Meta get() = Laminate(meta, descriptor?.defaultItem().node) } -fun Meta.toScheme() = MetaScheme(this) +fun Meta.asScheme() = MetaScheme(this) fun Meta.toScheme(spec: Specification, block: T.() -> Unit) = spec.wrap(this).apply(block) diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/mapMeta.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/mapMeta.kt index b0d8162c..ab68212c 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/mapMeta.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/mapMeta.kt @@ -3,14 +3,6 @@ package hep.dataforge.meta import hep.dataforge.descriptors.NodeDescriptor import hep.dataforge.values.Value -///** -// * Find all elements with given body -// */ -//private fun Meta.byBody(body: String): Map> = -// items.filter { it.key.body == body }.mapKeys { it.key.index } -// -//private fun Meta.distinctNames() = items.keys.map { it.body }.distinct() - /** * Convert meta to map of maps */ diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/metaDelegates.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/metaDelegates.kt deleted file mode 100644 index 7c8d2026..00000000 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/metaDelegates.kt +++ /dev/null @@ -1,414 +0,0 @@ -package hep.dataforge.meta - -import hep.dataforge.names.Name -import hep.dataforge.names.asName -import hep.dataforge.values.Null -import hep.dataforge.values.Value -import hep.dataforge.values.asValue -import kotlin.jvm.JvmName -import kotlin.properties.ReadOnlyProperty -import kotlin.properties.ReadWriteProperty -import kotlin.reflect.KProperty - -/* Meta delegates */ - -//TODO add caching for sealed nodes - -class ValueDelegate(val meta: Meta, private val key: String? = null, private val default: Value? = null) : - ReadOnlyProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): Value? { - return meta[key ?: property.name]?.value ?: default - } -} - -class StringDelegate(val meta: Meta, private val key: String? = null, private val default: String? = null) : - ReadOnlyProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): String? { - return meta[key ?: property.name]?.string ?: default - } -} - -class BooleanDelegate( - val meta: Meta, - private val key: String? = null, - private val default: Boolean? = null -) : ReadOnlyProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean? { - return meta[key ?: property.name]?.boolean ?: default - } -} - -class NumberDelegate( - val meta: Meta, - private val key: String? = null, - private val default: Number? = null -) : ReadOnlyProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): Number? { - return meta[key ?: property.name]?.number ?: default - } - - //delegates for number transformation - - val double get() = DelegateWrapper(this) { it?.toDouble() } - val int get() = DelegateWrapper(this) { it?.toInt() } - val short get() = DelegateWrapper(this) { it?.toShort() } - val long get() = DelegateWrapper(this) { it?.toLong() } -} - -class DelegateWrapper(val delegate: ReadOnlyProperty, val reader: (T) -> R) : - ReadOnlyProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): R { - return reader(delegate.getValue(thisRef, property)) - } -} - -//Delegates with non-null values - -class SafeStringDelegate( - val meta: Meta, - private val key: String? = null, - default: () -> String -) : ReadOnlyProperty { - - private val default: String by lazy(default) - - override fun getValue(thisRef: Any?, property: KProperty<*>): String { - return meta[key ?: property.name]?.string ?: default - } -} - -class SafeBooleanDelegate( - val meta: Meta, - private val key: String? = null, - default: () -> Boolean -) : ReadOnlyProperty { - - private val default: Boolean by lazy(default) - - override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean { - return meta[key ?: property.name]?.boolean ?: default - } -} - -class SafeNumberDelegate( - val meta: Meta, - private val key: String? = null, - default: () -> Number -) : ReadOnlyProperty { - - private val default: Number by lazy(default) - - override fun getValue(thisRef: Any?, property: KProperty<*>): Number { - return meta[key ?: property.name]?.number ?: default - } - - val double get() = DelegateWrapper(this) { it.toDouble() } - val int get() = DelegateWrapper(this) { it.toInt() } - val short get() = DelegateWrapper(this) { it.toShort() } - val long get() = DelegateWrapper(this) { it.toLong() } -} - -class SafeEnumDelegate>( - val meta: Meta, - private val key: String? = null, - private val default: E, - private val resolver: (String) -> E -) : ReadOnlyProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): E { - return (meta[key ?: property.name]?.string)?.let { resolver(it) } ?: default - } -} - -//Child node delegate - -class ChildDelegate( - val meta: Meta, - private val key: String? = null, - private val converter: (Meta) -> T -) : ReadOnlyProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): T? { - return meta[key ?: property.name]?.node?.let { converter(it) } - } -} - -//Read-only delegates for Metas - -/** - * A property delegate that uses custom key - */ -fun Meta.value(default: Value = Null, key: String? = null) = ValueDelegate(this, key, default) - -fun Meta.string(default: String? = null, key: String? = null) = StringDelegate(this, key, default) - -fun Meta.boolean(default: Boolean? = null, key: String? = null) = BooleanDelegate(this, key, default) - -fun Meta.number(default: Number? = null, key: String? = null) = NumberDelegate(this, key, default) - -fun Meta.child(key: String? = null) = ChildDelegate(this, key) { it } - -@JvmName("safeString") -fun Meta.string(default: String, key: String? = null) = - SafeStringDelegate(this, key) { default } - -@JvmName("safeBoolean") -fun Meta.boolean(default: Boolean, key: String? = null) = - SafeBooleanDelegate(this, key) { default } - -@JvmName("safeNumber") -fun Meta.number(default: Number, key: String? = null) = - SafeNumberDelegate(this, key) { default } - -@JvmName("safeString") -fun Meta.string(key: String? = null, default: () -> String) = - SafeStringDelegate(this, key, default) - -@JvmName("safeBoolean") -fun Meta.boolean(key: String? = null, default: () -> Boolean) = - SafeBooleanDelegate(this, key, default) - -@JvmName("safeNumber") -fun Meta.number(key: String? = null, default: () -> Number) = - SafeNumberDelegate(this, key, default) - - -inline fun > Meta.enum(default: E, key: String? = null) = - SafeEnumDelegate(this, key, default) { enumValueOf(it) } - -/* Read-write delegates */ - -class MutableValueDelegate>( - val meta: M, - private val key: Name? = null, - private val default: Value? = null -) : ReadWriteProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): Value? { - return meta[key ?: property.name.asName()]?.value ?: default - } - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: Value?) { - val name = key ?: property.name.asName() - if (value == null) { - meta.remove(name) - } else { - meta.setValue(name, value) - } - } - - fun transform(writer: (T) -> Value? = { Value.of(it) }, reader: (Value?) -> T) = - ReadWriteDelegateWrapper(this, reader, writer) -} - -class MutableStringDelegate>( - val meta: M, - private val key: Name? = null, - private val default: String? = null -) : ReadWriteProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): String? { - return meta[key ?: property.name.asName()]?.string ?: default - } - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: String?) { - val name = key ?: property.name.asName() - if (value == null) { - meta.remove(name) - } else { - meta.setValue(name, value.asValue()) - } - } -} - -class MutableBooleanDelegate>( - val meta: M, - private val key: Name? = null, - private val default: Boolean? = null -) : ReadWriteProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean? { - return meta[key ?: property.name.asName()]?.boolean ?: default - } - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean?) { - val name = key ?: property.name.asName() - if (value == null) { - meta.remove(name) - } else { - meta.setValue(name, value.asValue()) - } - } -} - -class MutableNumberDelegate>( - val meta: M, - private val key: Name? = null, - private val default: Number? = null -) : ReadWriteProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): Number? { - return meta[key ?: property.name.asName()]?.number ?: default - } - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: Number?) { - val name = key ?: property.name.asName() - if (value == null) { - meta.remove(name) - } else { - meta.setValue(name, value.asValue()) - } - } - - val double get() = ReadWriteDelegateWrapper(this, reader = { it?.toDouble() }, writer = { it }) - val float get() = ReadWriteDelegateWrapper(this, reader = { it?.toFloat() }, writer = { it }) - val int get() = ReadWriteDelegateWrapper(this, reader = { it?.toInt() }, writer = { it }) - val short get() = ReadWriteDelegateWrapper(this, reader = { it?.toShort() }, writer = { it }) - val long get() = ReadWriteDelegateWrapper(this, reader = { it?.toLong() }, writer = { it }) -} - -//Delegates with non-null values - -class MutableSafeStringDelegate>( - val meta: M, - private val key: Name? = null, - default: () -> String -) : ReadWriteProperty { - - private val default: String by lazy(default) - - override fun getValue(thisRef: Any?, property: KProperty<*>): String { - return meta[key ?: property.name.asName()]?.string ?: default - } - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { - meta.setValue(key ?: property.name.asName(), value.asValue()) - } -} - -class MutableSafeBooleanDelegate>( - val meta: M, - private val key: Name? = null, - default: () -> Boolean -) : ReadWriteProperty { - - private val default: Boolean by lazy(default) - - override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean { - return meta[key ?: property.name.asName()]?.boolean ?: default - } - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean) { - meta.setValue(key ?: property.name.asName(), value.asValue()) - } -} - -class MutableSafeNumberDelegate>( - val meta: M, - private val key: Name? = null, - default: () -> Number -) : ReadWriteProperty { - - private val default: Number by lazy(default) - - override fun getValue(thisRef: Any?, property: KProperty<*>): Number { - return meta[key ?: property.name.asName()]?.number ?: default - } - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: Number) { - meta.setValue(key ?: property.name.asName(), value.asValue()) - } - - val double get() = ReadWriteDelegateWrapper(this, reader = { it.toDouble() }, writer = { it }) - val float get() = ReadWriteDelegateWrapper(this, reader = { it.toFloat() }, writer = { it }) - val int get() = ReadWriteDelegateWrapper(this, reader = { it.toInt() }, writer = { it }) - val short get() = ReadWriteDelegateWrapper(this, reader = { it.toShort() }, writer = { it }) - val long get() = ReadWriteDelegateWrapper(this, reader = { it.toLong() }, writer = { it }) -} - -class MutableSafeEnumvDelegate, E : Enum>( - val meta: M, - private val key: Name? = null, - private val default: E, - private val resolver: (String) -> E -) : ReadWriteProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): E { - return (meta[key ?: property.name.asName()]?.string)?.let { resolver(it) } ?: default - } - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: E) { - meta.setValue(key ?: property.name.asName(), value.name.asValue()) - } -} - -//Child node delegate - -class MutableNodeDelegate>( - val meta: M, - private val key: Name? = null -) : ReadWriteProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): M? { - return meta[key ?: property.name.asName()]?.node - } - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: M?) { - meta[key ?: property.name.asName()] = value - } -} - -class ReadWriteDelegateWrapper( - val delegate: ReadWriteProperty, - val reader: (T) -> R, - val writer: (R) -> T -) : ReadWriteProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): R { - return reader(delegate.getValue(thisRef, property)) - } - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: R) { - delegate.setValue(thisRef, property, writer(value)) - } -} - - -//Read-write delegates - -/** - * A property delegate that uses custom key - */ -fun > M.value(default: Value = Null, key: Name? = null) = - MutableValueDelegate(this, key, default) - -fun > M.string(default: String? = null, key: Name? = null) = - MutableStringDelegate(this, key, default) - -fun > M.boolean(default: Boolean? = null, key: Name? = null) = - MutableBooleanDelegate(this, key, default) - -fun > M.number(default: Number? = null, key: Name? = null) = - MutableNumberDelegate(this, key, default) - -fun > M.child(key: Name? = null) = - MutableNodeDelegate(this, key) - -@JvmName("safeString") -fun > M.string(default: String, key: Name? = null) = - MutableSafeStringDelegate(this, key) { default } - -@JvmName("safeBoolean") -fun > M.boolean(default: Boolean, key: Name? = null) = - MutableSafeBooleanDelegate(this, key) { default } - -@JvmName("safeNumber") -fun > M.number(default: Number, key: Name? = null) = - MutableSafeNumberDelegate(this, key) { default } - -@JvmName("safeString") -fun > M.string(key: Name? = null, default: () -> String) = - MutableSafeStringDelegate(this, key, default) - -@JvmName("safeBoolean") -fun > M.boolean(key: Name? = null, default: () -> Boolean) = - MutableSafeBooleanDelegate(this, key, default) - -@JvmName("safeNumber") -fun > M.number(key: Name? = null, default: () -> Number) = - MutableSafeNumberDelegate(this, key, default) - - -inline fun , reified E : Enum> M.enum(default: E, key: Name? = null) = - MutableSafeEnumvDelegate(this, key, default) { enumValueOf(it) } \ No newline at end of file diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/metaMatcher.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/metaMatcher.kt index 6f16f537..263483a2 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/metaMatcher.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/metaMatcher.kt @@ -26,26 +26,13 @@ fun Meta.getIndexed(name: Name): Map> { @DFExperimental fun Meta.getIndexed(name: String): Map> = this@getIndexed.getIndexed(name.toName()) - /** * Get all items matching given name. */ +@Suppress("UNCHECKED_CAST") @DFExperimental -fun > M.getIndexed(name: Name): Map> { - val root: MetaNode? = when (name.length) { - 0 -> error("Can't use empty name for that") - 1 -> this - else -> (this[name.cutLast()] as? MetaItem.NodeItem)?.node - } - - val (body, index) = name.last()!! - val regex = index.toRegex() - - return root?.items - ?.filter { it.key.body == body && (index.isEmpty() || regex.matches(it.key.index)) } - ?.mapKeys { it.key.index } - ?: emptyMap() -} +fun > M.getIndexed(name: Name): Map> = + (this as Meta).getIndexed(name) as Map> @DFExperimental fun > M.getIndexed(name: String): Map> = getIndexed(name.toName()) \ No newline at end of file diff --git a/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/SchemeTest.kt b/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/SchemeTest.kt index c7703a47..0246fb10 100644 --- a/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/SchemeTest.kt +++ b/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/SchemeTest.kt @@ -13,7 +13,7 @@ class SchemeTest{ "d" put it } } - }.toScheme() + }.asScheme() val meta = styled.toMeta()