Refactor Meta delegates
This commit is contained in:
parent
b83821af51
commit
fe6760eee6
@ -61,7 +61,7 @@ class NodeDescriptor : ItemDescriptor() {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
var default: Config? by nullableConfig()
|
||||
var default: Config? by config()
|
||||
|
||||
/**
|
||||
* The map of children node descriptors
|
||||
|
@ -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())
|
||||
|
||||
|
@ -28,19 +28,6 @@ open class ConfigurableDelegate(
|
||||
val name = key ?: property.name.asName()
|
||||
owner.setProperty(name, value)
|
||||
}
|
||||
|
||||
fun <T> transform(
|
||||
writer: (T) -> MetaItem<*>? = { MetaItem.of(it) },
|
||||
reader: (MetaItem<*>?) -> T
|
||||
): ReadWriteProperty<Any?, T> = object : ReadWriteProperty<Any?, T> {
|
||||
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 <T> Configurable.item(
|
||||
writer: (T) -> MetaItem<*>? = { MetaItem.of(it) },
|
||||
reader: (MetaItem<*>?) -> T
|
||||
): ReadWriteProperty<Any?, T> =
|
||||
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<Any?, Value?> =
|
||||
item(default, key).transform { it.value }
|
||||
@ -81,7 +68,7 @@ fun <T> Configurable.value(
|
||||
writer: (T) -> Value? = { Value.of(it) },
|
||||
reader: (Value?) -> T
|
||||
): ReadWriteProperty<Any?, T> =
|
||||
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<Any?, Config?> =
|
||||
object : ReadWriteProperty<Any?, Config?> {
|
||||
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<Any?, Config?> =
|
||||
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<Any?, Config> =
|
||||
object : ReadWriteProperty<Any?, Config> {
|
||||
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 <T : Configurable> Configurable.spec(spec: Specification<T>, key: Name? = null): ReadWriteProperty<Any?, T?> =
|
||||
object : ReadWriteProperty<Any?, T?> {
|
@ -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<Meta>) : MetaBase() {
|
||||
|
||||
|
@ -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<Any?, MetaItem<*>?> {
|
||||
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<T, R>(
|
||||
val delegate: ReadOnlyProperty<Any?, T>,
|
||||
val reader: (T) -> R
|
||||
) : ReadOnlyProperty<Any?, R> {
|
||||
override fun getValue(thisRef: Any?, property: KProperty<*>): R {
|
||||
return reader(delegate.getValue(thisRef, property))
|
||||
}
|
||||
}
|
||||
|
||||
fun <T, R> ReadOnlyProperty<Any?, T>.map(reader: (T) -> R): DelegateWrapper<T, R> =
|
||||
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 <reified E : Enum<E>> Meta.enum(default: E, key: Name? = null) =
|
||||
item(default, key).map { it.enum<E>()!! }
|
@ -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<M : MutableMeta<M>>(
|
||||
override val owner: M,
|
||||
key: Name? = null,
|
||||
default: MetaItem<*>? = null
|
||||
) : MetaDelegate(owner, key, default), ReadWriteProperty<Any?, MetaItem<*>?> {
|
||||
|
||||
override fun setValue(thisRef: Any?, property: KProperty<*>, value: MetaItem<*>?) {
|
||||
val name = key ?: property.name.asName()
|
||||
owner.setItem(name, value)
|
||||
}
|
||||
}
|
||||
|
||||
class LazyMutableMetaDelegate<M : MutableMeta<M>>(
|
||||
owner: M,
|
||||
key: Name? = null,
|
||||
defaultProvider: () -> MetaItem<*>? = { null }
|
||||
) : MutableMetaDelegate<M>(owner, key) {
|
||||
override val default by lazy(defaultProvider)
|
||||
}
|
||||
|
||||
class ReadWriteDelegateWrapper<T, R>(
|
||||
val delegate: ReadWriteProperty<Any?, T>,
|
||||
val reader: (T) -> R,
|
||||
val writer: (R) -> T
|
||||
) : ReadWriteProperty<Any?, R> {
|
||||
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 <T, R> ReadWriteProperty<Any?, T>.map(reader: (T) -> R, writer: (R) -> T): ReadWriteDelegateWrapper<T, R> =
|
||||
ReadWriteDelegateWrapper(this, reader, writer)
|
||||
|
||||
fun <R> ReadWriteProperty<Any?, MetaItem<*>?>.transform(reader: (MetaItem<*>?) -> R): ReadWriteProperty<Any?, R> =
|
||||
map(reader = reader, writer = { MetaItem.of(it) })
|
||||
|
||||
fun <R> ReadWriteProperty<Any?, Value?>.transform(reader: (Value?) -> R) =
|
||||
map(reader = reader, writer = { Value.of(it) })
|
||||
|
||||
|
||||
fun <M : MutableMeta<M>> M.item(default: Any? = null, key: Name? = null): MutableMetaDelegate<M> =
|
||||
MutableMetaDelegate(this, key, default?.let { MetaItem.of(it) })
|
||||
|
||||
fun <M : MutableMeta<M>> M.lazyItem(key: Name? = null, defaultProvider: () -> Any?): LazyMutableMetaDelegate<M> =
|
||||
LazyMutableMetaDelegate(this, key) { defaultProvider()?.let { MetaItem.of(it) } }
|
||||
|
||||
//Read-write delegates
|
||||
|
||||
/**
|
||||
* A property delegate that uses custom key
|
||||
*/
|
||||
fun <M : MutableMeta<M>> M.value(default: Value? = null, key: Name? = null): ReadWriteProperty<Any?, Value?> =
|
||||
item(default, key).transform { it.value }
|
||||
|
||||
fun <M : MutableMeta<M>> M.string(default: String? = null, key: Name? = null): ReadWriteProperty<Any?, String?> =
|
||||
item(default, key).transform { it.string }
|
||||
|
||||
fun <M : MutableMeta<M>> M.boolean(default: Boolean? = null, key: Name? = null): ReadWriteProperty<Any?, Boolean?> =
|
||||
item(default, key).transform { it.boolean }
|
||||
|
||||
fun <M : MutableMeta<M>> M.number(default: Number? = null, key: Name? = null): ReadWriteProperty<Any?, Number?> =
|
||||
item(default, key).transform { it.number }
|
||||
|
||||
inline fun <reified M : MutableMeta<M>> M.node(key: Name? = null) =
|
||||
item(this, key).transform { it.node as? M }
|
||||
|
||||
@JvmName("safeString")
|
||||
fun <M : MutableMeta<M>> M.string(default: String, key: Name? = null) =
|
||||
item(default, key).transform { it.string!! }
|
||||
|
||||
@JvmName("safeBoolean")
|
||||
fun <M : MutableMeta<M>> M.boolean(default: Boolean, key: Name? = null) =
|
||||
item(default, key).transform { it.boolean!! }
|
||||
|
||||
@JvmName("safeNumber")
|
||||
fun <M : MutableMeta<M>> M.number(default: Number, key: Name? = null) =
|
||||
item(default, key).transform { it.number!! }
|
||||
|
||||
@JvmName("lazyString")
|
||||
fun <M : MutableMeta<M>> M.string(key: Name? = null, default: () -> String) =
|
||||
lazyItem(key, default).transform { it.string!! }
|
||||
|
||||
@JvmName("safeBoolean")
|
||||
fun <M : MutableMeta<M>> M.boolean(key: Name? = null, default: () -> Boolean) =
|
||||
lazyItem(key, default).transform { it.boolean!! }
|
||||
|
||||
@JvmName("safeNumber")
|
||||
fun <M : MutableMeta<M>> M.number(key: Name? = null, default: () -> Number) =
|
||||
lazyItem(key, default).transform { it.number!! }
|
||||
|
||||
|
||||
inline fun <M : MutableMeta<M>, reified E : Enum<E>> M.enum(default: E, key: Name? = null) =
|
||||
item(default, key).transform { it.enum<E>()!! }
|
@ -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<T : Scheme>(val builder: () -> T) : Specification<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 <T : Configurable> Meta.toScheme(spec: Specification<T>, block: T.() -> Unit) = spec.wrap(this).apply(block)
|
||||
|
||||
|
@ -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<String, MetaItem<*>> =
|
||||
// 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
|
||||
*/
|
||||
|
@ -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<Any?, Value?> {
|
||||
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<Any?, String?> {
|
||||
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<Any?, Boolean?> {
|
||||
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<Any?, Number?> {
|
||||
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<T, R>(val delegate: ReadOnlyProperty<Any?, T>, val reader: (T) -> R) :
|
||||
ReadOnlyProperty<Any?, R> {
|
||||
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<Any?, String> {
|
||||
|
||||
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<Any?, Boolean> {
|
||||
|
||||
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<Any?, Number> {
|
||||
|
||||
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<E : Enum<E>>(
|
||||
val meta: Meta,
|
||||
private val key: String? = null,
|
||||
private val default: E,
|
||||
private val resolver: (String) -> E
|
||||
) : ReadOnlyProperty<Any?, E> {
|
||||
override fun getValue(thisRef: Any?, property: KProperty<*>): E {
|
||||
return (meta[key ?: property.name]?.string)?.let { resolver(it) } ?: default
|
||||
}
|
||||
}
|
||||
|
||||
//Child node delegate
|
||||
|
||||
class ChildDelegate<T>(
|
||||
val meta: Meta,
|
||||
private val key: String? = null,
|
||||
private val converter: (Meta) -> T
|
||||
) : ReadOnlyProperty<Any?, T?> {
|
||||
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 <reified E : Enum<E>> Meta.enum(default: E, key: String? = null) =
|
||||
SafeEnumDelegate(this, key, default) { enumValueOf(it) }
|
||||
|
||||
/* Read-write delegates */
|
||||
|
||||
class MutableValueDelegate<M : MutableMeta<M>>(
|
||||
val meta: M,
|
||||
private val key: Name? = null,
|
||||
private val default: Value? = null
|
||||
) : ReadWriteProperty<Any?, Value?> {
|
||||
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 <T> transform(writer: (T) -> Value? = { Value.of(it) }, reader: (Value?) -> T) =
|
||||
ReadWriteDelegateWrapper(this, reader, writer)
|
||||
}
|
||||
|
||||
class MutableStringDelegate<M : MutableMeta<M>>(
|
||||
val meta: M,
|
||||
private val key: Name? = null,
|
||||
private val default: String? = null
|
||||
) : ReadWriteProperty<Any?, String?> {
|
||||
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<M : MutableMeta<M>>(
|
||||
val meta: M,
|
||||
private val key: Name? = null,
|
||||
private val default: Boolean? = null
|
||||
) : ReadWriteProperty<Any?, Boolean?> {
|
||||
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<M : MutableMeta<M>>(
|
||||
val meta: M,
|
||||
private val key: Name? = null,
|
||||
private val default: Number? = null
|
||||
) : ReadWriteProperty<Any?, Number?> {
|
||||
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<M : MutableMeta<M>>(
|
||||
val meta: M,
|
||||
private val key: Name? = null,
|
||||
default: () -> String
|
||||
) : ReadWriteProperty<Any?, String> {
|
||||
|
||||
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<M : MutableMeta<M>>(
|
||||
val meta: M,
|
||||
private val key: Name? = null,
|
||||
default: () -> Boolean
|
||||
) : ReadWriteProperty<Any?, Boolean> {
|
||||
|
||||
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<M : MutableMeta<M>>(
|
||||
val meta: M,
|
||||
private val key: Name? = null,
|
||||
default: () -> Number
|
||||
) : ReadWriteProperty<Any?, Number> {
|
||||
|
||||
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<M : MutableMeta<M>, E : Enum<E>>(
|
||||
val meta: M,
|
||||
private val key: Name? = null,
|
||||
private val default: E,
|
||||
private val resolver: (String) -> E
|
||||
) : ReadWriteProperty<Any?, E> {
|
||||
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<M : MutableMeta<M>>(
|
||||
val meta: M,
|
||||
private val key: Name? = null
|
||||
) : ReadWriteProperty<Any?, M?> {
|
||||
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<T, R>(
|
||||
val delegate: ReadWriteProperty<Any?, T>,
|
||||
val reader: (T) -> R,
|
||||
val writer: (R) -> T
|
||||
) : ReadWriteProperty<Any?, R> {
|
||||
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 : MutableMeta<M>> M.value(default: Value = Null, key: Name? = null) =
|
||||
MutableValueDelegate(this, key, default)
|
||||
|
||||
fun <M : MutableMeta<M>> M.string(default: String? = null, key: Name? = null) =
|
||||
MutableStringDelegate(this, key, default)
|
||||
|
||||
fun <M : MutableMeta<M>> M.boolean(default: Boolean? = null, key: Name? = null) =
|
||||
MutableBooleanDelegate(this, key, default)
|
||||
|
||||
fun <M : MutableMeta<M>> M.number(default: Number? = null, key: Name? = null) =
|
||||
MutableNumberDelegate(this, key, default)
|
||||
|
||||
fun <M : MutableMeta<M>> M.child(key: Name? = null) =
|
||||
MutableNodeDelegate(this, key)
|
||||
|
||||
@JvmName("safeString")
|
||||
fun <M : MutableMeta<M>> M.string(default: String, key: Name? = null) =
|
||||
MutableSafeStringDelegate(this, key) { default }
|
||||
|
||||
@JvmName("safeBoolean")
|
||||
fun <M : MutableMeta<M>> M.boolean(default: Boolean, key: Name? = null) =
|
||||
MutableSafeBooleanDelegate(this, key) { default }
|
||||
|
||||
@JvmName("safeNumber")
|
||||
fun <M : MutableMeta<M>> M.number(default: Number, key: Name? = null) =
|
||||
MutableSafeNumberDelegate(this, key) { default }
|
||||
|
||||
@JvmName("safeString")
|
||||
fun <M : MutableMeta<M>> M.string(key: Name? = null, default: () -> String) =
|
||||
MutableSafeStringDelegate(this, key, default)
|
||||
|
||||
@JvmName("safeBoolean")
|
||||
fun <M : MutableMeta<M>> M.boolean(key: Name? = null, default: () -> Boolean) =
|
||||
MutableSafeBooleanDelegate(this, key, default)
|
||||
|
||||
@JvmName("safeNumber")
|
||||
fun <M : MutableMeta<M>> M.number(key: Name? = null, default: () -> Number) =
|
||||
MutableSafeNumberDelegate(this, key, default)
|
||||
|
||||
|
||||
inline fun <M : MutableMeta<M>, reified E : Enum<E>> M.enum(default: E, key: Name? = null) =
|
||||
MutableSafeEnumvDelegate(this, key, default) { enumValueOf(it) }
|
@ -26,26 +26,13 @@ fun Meta.getIndexed(name: Name): Map<String, MetaItem<*>> {
|
||||
@DFExperimental
|
||||
fun Meta.getIndexed(name: String): Map<String, MetaItem<*>> = this@getIndexed.getIndexed(name.toName())
|
||||
|
||||
|
||||
/**
|
||||
* Get all items matching given name.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@DFExperimental
|
||||
fun <M : MetaNode<M>> M.getIndexed(name: Name): Map<String, MetaItem<M>> {
|
||||
val root: MetaNode<M>? = when (name.length) {
|
||||
0 -> error("Can't use empty name for that")
|
||||
1 -> this
|
||||
else -> (this[name.cutLast()] as? MetaItem.NodeItem<M>)?.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 : MetaNode<M>> M.getIndexed(name: Name): Map<String, MetaItem<M>> =
|
||||
(this as Meta).getIndexed(name) as Map<String, MetaItem<M>>
|
||||
|
||||
@DFExperimental
|
||||
fun <M : MetaNode<M>> M.getIndexed(name: String): Map<String, MetaItem<M>> = getIndexed(name.toName())
|
@ -13,7 +13,7 @@ class SchemeTest{
|
||||
"d" put it
|
||||
}
|
||||
}
|
||||
}.toScheme()
|
||||
}.asScheme()
|
||||
|
||||
val meta = styled.toMeta()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user