Merge MetaConverter and MetaSpec

This commit is contained in:
Alexander Nozik 2023-12-31 13:08:30 +03:00
parent fd1d98aa87
commit 991f77c45a
8 changed files with 44 additions and 36 deletions

View File

@ -9,6 +9,7 @@
### Changed
- Descriptor `children` renamed to `nodes`
- `MetaConverter` now inherits `MetaSpec` (former `Specifiction`). So `MetaConverter` could be used more universally.
### Deprecated
- `node(key,converter)` in favor of `serializable` delegate

View File

@ -1,6 +1,5 @@
package space.kscience.dataforge.properties
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import space.kscience.dataforge.misc.DFExperimental
@ -14,7 +13,6 @@ public interface Property<T> {
}
@DFExperimental
@OptIn(ExperimentalCoroutinesApi::class)
public fun <T> Property<T>.toFlow(): StateFlow<T> = MutableStateFlow(value).also { stateFlow ->
onChange {
stateFlow.value = it

View File

@ -183,7 +183,6 @@ public interface MetaConverter<T>: MetaSpec<T> {
}
}
public fun <T : Any> MetaConverter<T>.readNullable(item: Meta?): T? = item?.let { read(it) }
public fun <T : Any> MetaConverter<T>.convertNullable(obj: T?): Meta? = obj?.let { convert(it) }
public fun <T> MetaConverter<T>.readValue(value: Value): T? = read(Meta(value))

View File

@ -13,13 +13,13 @@ public fun MetaProvider.node(key: Name? = null): ReadOnlyProperty<Any?, Meta?> =
}
/**
* Use [converter] to read the Meta node
* Use [metaSpec] to read the Meta node
*/
public fun <T> MetaProvider.convertable(
converter: MetaConverter<T>,
public fun <T> MetaProvider.spec(
metaSpec: MetaSpec<T>,
key: Name? = null,
): ReadOnlyProperty<Any?, T?> = ReadOnlyProperty { _, property ->
get(key ?: property.name.asName())?.let { converter.read(it) }
get(key ?: property.name.asName())?.let { metaSpec.read(it) }
}
/**
@ -29,19 +29,19 @@ public fun <T> MetaProvider.convertable(
public inline fun <reified T> MetaProvider.serializable(
descriptor: MetaDescriptor? = null,
key: Name? = null,
): ReadOnlyProperty<Any?, T?> = convertable(MetaConverter.serializable(descriptor), key)
): ReadOnlyProperty<Any?, T?> = spec(MetaConverter.serializable(descriptor), key)
@Deprecated("Use convertable", ReplaceWith("convertable(converter, key)"))
public fun <T> MetaProvider.node(
key: Name? = null,
converter: MetaConverter<T>,
): ReadOnlyProperty<Any?, T?> = convertable(converter, key)
converter: MetaSpec<T>,
): ReadOnlyProperty<Any?, T?> = spec(converter, key)
/**
* Use [converter] to convert a list of same name siblings meta to object
*/
public fun <T> Meta.listOfConvertable(
converter: MetaConverter<T>,
public fun <T> Meta.listOfSpec(
converter: MetaSpec<T>,
key: Name? = null,
): ReadOnlyProperty<Any?, List<T>> = ReadOnlyProperty{_, property ->
val name = key ?: property.name.asName()
@ -52,7 +52,7 @@ public fun <T> Meta.listOfConvertable(
public inline fun <reified T> Meta.listOfSerializable(
descriptor: MetaDescriptor? = null,
key: Name? = null,
): ReadOnlyProperty<Any?, List<T>> = listOfConvertable(MetaConverter.serializable(descriptor), key)
): ReadOnlyProperty<Any?, List<T>> = listOfSpec(MetaConverter.serializable(descriptor), key)
/**
* A property delegate that uses custom key

View File

@ -16,3 +16,6 @@ public interface MetaSpec<out T> : Described {
public fun read(source: Meta): T = readOrNull(source) ?: error("Meta $source could not be interpreted by $this")
}
public fun <T : Any> MetaSpec<T>.readNullable(item: Meta?): T? = item?.let { read(it) }
public fun <T> MetaSpec<T>.readValue(value: Value): T? = read(Meta(value))

View File

@ -1,8 +1,10 @@
package space.kscience.dataforge.meta
import space.kscience.dataforge.misc.ThreadSafe
import space.kscience.dataforge.names.*
import kotlin.reflect.KProperty1
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.cutFirst
import space.kscience.dataforge.names.firstOrNull
import space.kscience.dataforge.names.isEmpty
internal data class MetaListener(
@ -67,24 +69,4 @@ internal abstract class AbstractObservableMeta : ObservableMeta {
override fun toString(): String = Meta.toString(this)
override fun equals(other: Any?): Boolean = Meta.equals(this, other as? Meta)
override fun hashCode(): Int = Meta.hashCode(this)
}
/**
* Use the value of the property in a [callBack].
* The callback is called once immediately after subscription to pass the initial value.
*
* Optional [owner] property is used for
*/
public fun <S : Scheme, T> S.useProperty(
property: KProperty1<S, T>,
owner: Any? = null,
callBack: S.(T) -> Unit,
) {
//Pass initial value.
callBack(property.get(this))
meta.onChange(owner) { name ->
if (name.startsWith(property.name.asName())) {
callBack(property.get(this@useProperty))
}
}
}

View File

@ -9,6 +9,7 @@ import space.kscience.dataforge.misc.ThreadSafe
import space.kscience.dataforge.names.*
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
import kotlin.reflect.KProperty1
/**
* A base for delegate-based or descriptor-based scheme. [Scheme] has an empty constructor to simplify usage from [MetaSpec].
@ -288,3 +289,24 @@ public fun <T : Scheme> Scheme.listOfScheme(
spec: SchemeSpec<T>,
key: Name? = null,
): ReadWriteProperty<Any?, List<T>> = meta.listOfScheme(spec, key)
/**
* Use the value of the property in a [callBack].
* The callback is called once immediately after subscription to pass the initial value.
*
* Optional [owner] property is used for
*/
public fun <S : Scheme, T> S.useProperty(
property: KProperty1<S, T>,
owner: Any? = null,
callBack: S.(T) -> Unit,
) {
//Pass initial value.
callBack(property.get(this))
meta.onChange(owner) { name ->
if (name.startsWith(property.name.asName())) {
callBack(property.get(this@useProperty))
}
}
}

View File

@ -3,9 +3,11 @@ package space.kscience.dataforge.meta.descriptors
import space.kscience.dataforge.meta.Scheme
import space.kscience.dataforge.meta.SchemeSpec
import space.kscience.dataforge.meta.ValueType
import space.kscience.dataforge.misc.DFExperimental
import kotlin.reflect.KProperty1
import kotlin.reflect.typeOf
@DFExperimental
public inline fun <S : Scheme, reified T> MetaDescriptorBuilder.value(
property: KProperty1<S, T>,
noinline block: MetaDescriptorBuilder.() -> Unit = {},
@ -37,6 +39,7 @@ public inline fun <S : Scheme, reified T> MetaDescriptorBuilder.value(
else -> node(property.name, block)
}
@DFExperimental
public inline fun <S : Scheme, reified T : Scheme> MetaDescriptorBuilder.scheme(
property: KProperty1<S, T>,
spec: SchemeSpec<T>,