Experimental listOfSpec
delegate.
This commit is contained in:
parent
a6f1e54255
commit
82b328f797
@ -2,6 +2,7 @@
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- Experimental `listOfSpec` delegate.
|
||||
|
||||
### Changed
|
||||
- **API breaking** Descriptor no has a member property `defaultValue` instead of `defaultItem()` extension. It cahces default value state on the first call. It is done because computing default on each call is too expensive.
|
||||
|
@ -67,7 +67,7 @@ public class ContextBuilder internal constructor(
|
||||
return Context(contextName, parent, meta.seal()).apply {
|
||||
factories.forEach { (factory, meta) ->
|
||||
@Suppress("DEPRECATION")
|
||||
plugins.load(factory, meta)
|
||||
plugins.fetch(factory, meta)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -85,7 +85,7 @@ public fun Context.withEnv(block: ContextBuilder.() -> Unit): Context {
|
||||
}
|
||||
|
||||
val builder = ContextBuilder(this, name + "env", properties).apply(block)
|
||||
val requiresFork = builder.factories.any { (factory, meta) ->
|
||||
val requiresFork = builder.factories.values.any { (factory, meta) ->
|
||||
!contains(factory, meta)
|
||||
} || ((properties as Meta) == builder.meta)
|
||||
return if (requiresFork) builder.build() else this
|
||||
|
@ -83,7 +83,6 @@ public class PluginManager(override val context: Context) : ContextAware, Iterab
|
||||
* @param plugin
|
||||
* @return
|
||||
*/
|
||||
@Deprecated("Use immutable contexts instead")
|
||||
private fun <T : Plugin> load(plugin: T): T {
|
||||
if (get(plugin::class, plugin.tag, recursive = false) != null) {
|
||||
error("Plugin with tag ${plugin.tag} already exists in ${context.name}")
|
||||
@ -99,12 +98,6 @@ public class PluginManager(override val context: Context) : ContextAware, Iterab
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a plugin using its factory
|
||||
*/
|
||||
@Deprecated("Use immutable contexts instead")
|
||||
internal fun <T : Plugin> load(factory: PluginFactory<T>, meta: Meta = Meta.EMPTY): T =
|
||||
load(factory(meta, context))
|
||||
|
||||
/**
|
||||
* Remove a plugin from [PluginManager]
|
||||
|
@ -68,7 +68,7 @@ public fun ItemProvider.getIndexed(name: Name): Map<String?, MetaItem> {
|
||||
}
|
||||
}
|
||||
|
||||
public fun ItemProvider.getIndexed(name: String): Map<String?, MetaItem> = this@getIndexed.getIndexed(name.toName())
|
||||
public fun ItemProvider.getIndexed(name: String): Map<String?, MetaItem> = getIndexed(name.toName())
|
||||
|
||||
/**
|
||||
* Return a provider referencing a child node
|
||||
|
@ -1,6 +1,8 @@
|
||||
package space.kscience.dataforge.meta
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.isEmpty
|
||||
import space.kscience.dataforge.values.*
|
||||
|
||||
/**
|
||||
@ -9,7 +11,7 @@ import space.kscience.dataforge.values.*
|
||||
* * a [MetaItemNode] (node)
|
||||
*/
|
||||
@Serializable(MetaItemSerializer::class)
|
||||
public sealed class TypedMetaItem<out M : Meta>() {
|
||||
public sealed class TypedMetaItem<out M : Meta> : ItemProvider {
|
||||
|
||||
abstract override fun equals(other: Any?): Boolean
|
||||
|
||||
@ -32,6 +34,8 @@ public typealias MetaItem = TypedMetaItem<*>
|
||||
|
||||
@Serializable(MetaItemSerializer::class)
|
||||
public class MetaItemValue(public val value: Value) : TypedMetaItem<Nothing>() {
|
||||
override fun getItem(name: Name): MetaItem? = if (name.isEmpty()) this else null
|
||||
|
||||
override fun toString(): String = value.toString()
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
@ -45,6 +49,8 @@ public class MetaItemValue(public val value: Value) : TypedMetaItem<Nothing>() {
|
||||
|
||||
@Serializable(MetaItemSerializer::class)
|
||||
public class MetaItemNode<M : Meta>(public val node: M) : TypedMetaItem<M>() {
|
||||
override fun getItem(name: Name): MetaItem? = if (name.isEmpty()) this else node.getItem(name)
|
||||
|
||||
//Fixing serializer for node could cause class cast problems, but it should not since Meta descendants are not serializable
|
||||
override fun toString(): String = node.toString()
|
||||
|
||||
|
@ -96,6 +96,8 @@ public fun MutableItemProvider.getChild(childName: Name): MutableItemProvider {
|
||||
|
||||
public fun MutableItemProvider.getChild(childName: String): MutableItemProvider = getChild(childName.toName())
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update existing mutable node with another node. The rules are following:
|
||||
* * value replaces anything
|
||||
|
@ -1,5 +1,6 @@
|
||||
package space.kscience.dataforge.meta
|
||||
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.asName
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
@ -30,7 +31,7 @@ public interface ReadOnlySpecification<out T : ItemProvider> {
|
||||
* By convention [Scheme] companion should inherit this class
|
||||
*
|
||||
*/
|
||||
public interface Specification<out T : MutableItemProvider>: ReadOnlySpecification<T> {
|
||||
public interface Specification<out T : MutableItemProvider> : ReadOnlySpecification<T> {
|
||||
/**
|
||||
* Wrap [MutableItemProvider], using it as inner storage (changes to [Specification] are reflected on [MutableItemProvider]
|
||||
*/
|
||||
@ -57,6 +58,9 @@ public fun <C : MutableItemProvider, S : Specification<C>> Configurable.update(
|
||||
public fun <T : MutableItemProvider> TypedMetaItem<MutableMeta<*>>.withSpec(spec: Specification<T>): T? =
|
||||
node?.let { spec.write(it) }
|
||||
|
||||
/**
|
||||
* A delegate that uses a [Specification] to wrap a child of this provider
|
||||
*/
|
||||
public fun <T : Scheme> MutableItemProvider.spec(
|
||||
spec: Specification<T>,
|
||||
key: Name? = null,
|
||||
@ -71,3 +75,32 @@ public fun <T : Scheme> MutableItemProvider.spec(
|
||||
set(name, value.toMeta().asMetaItem())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A delegate that uses a [Specification] to wrap a list of child providers.
|
||||
* If children are mutable, the changes in list elements are reflected on them.
|
||||
* The list is a snapshot of children state, so change in structure is not reflected on its composition.
|
||||
*/
|
||||
@DFExperimental
|
||||
public fun <T : Scheme> MutableItemProvider.listOfSpec(
|
||||
spec: Specification<T>,
|
||||
key: Name? = null,
|
||||
): ReadWriteProperty<Any?, List<T>> = object : ReadWriteProperty<Any?, List<T>> {
|
||||
override fun getValue(thisRef: Any?, property: KProperty<*>): List<T> {
|
||||
val name = key ?: property.name.asName()
|
||||
return getIndexed(name).map {
|
||||
when (val value = it.value) {
|
||||
is MetaItemNode<*> -> when (value.node) {
|
||||
is MutableItemProvider -> spec.write(value.node)
|
||||
else -> spec.read(value.node)
|
||||
}
|
||||
is MetaItemValue -> spec.read(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun setValue(thisRef: Any?, property: KProperty<*>, value: List<T>) {
|
||||
val name = key ?: property.name.asName()
|
||||
setIndexed(name, value.map { it.toMeta() })
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user