Experimental listOfSpec
delegate.
This commit is contained in:
parent
a6f1e54255
commit
82b328f797
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### Added
|
||||||
|
- Experimental `listOfSpec` delegate.
|
||||||
|
|
||||||
### Changed
|
### 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.
|
- **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 {
|
return Context(contextName, parent, meta.seal()).apply {
|
||||||
factories.forEach { (factory, meta) ->
|
factories.forEach { (factory, meta) ->
|
||||||
@Suppress("DEPRECATION")
|
@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 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)
|
!contains(factory, meta)
|
||||||
} || ((properties as Meta) == builder.meta)
|
} || ((properties as Meta) == builder.meta)
|
||||||
return if (requiresFork) builder.build() else this
|
return if (requiresFork) builder.build() else this
|
||||||
|
@ -83,7 +83,6 @@ public class PluginManager(override val context: Context) : ContextAware, Iterab
|
|||||||
* @param plugin
|
* @param plugin
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Deprecated("Use immutable contexts instead")
|
|
||||||
private fun <T : Plugin> load(plugin: T): T {
|
private fun <T : Plugin> load(plugin: T): T {
|
||||||
if (get(plugin::class, plugin.tag, recursive = false) != null) {
|
if (get(plugin::class, plugin.tag, recursive = false) != null) {
|
||||||
error("Plugin with tag ${plugin.tag} already exists in ${context.name}")
|
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]
|
* 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
|
* Return a provider referencing a child node
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package space.kscience.dataforge.meta
|
package space.kscience.dataforge.meta
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.dataforge.names.isEmpty
|
||||||
import space.kscience.dataforge.values.*
|
import space.kscience.dataforge.values.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -9,7 +11,7 @@ import space.kscience.dataforge.values.*
|
|||||||
* * a [MetaItemNode] (node)
|
* * a [MetaItemNode] (node)
|
||||||
*/
|
*/
|
||||||
@Serializable(MetaItemSerializer::class)
|
@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
|
abstract override fun equals(other: Any?): Boolean
|
||||||
|
|
||||||
@ -32,6 +34,8 @@ public typealias MetaItem = TypedMetaItem<*>
|
|||||||
|
|
||||||
@Serializable(MetaItemSerializer::class)
|
@Serializable(MetaItemSerializer::class)
|
||||||
public class MetaItemValue(public val value: Value) : TypedMetaItem<Nothing>() {
|
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 toString(): String = value.toString()
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
@ -45,6 +49,8 @@ public class MetaItemValue(public val value: Value) : TypedMetaItem<Nothing>() {
|
|||||||
|
|
||||||
@Serializable(MetaItemSerializer::class)
|
@Serializable(MetaItemSerializer::class)
|
||||||
public class MetaItemNode<M : Meta>(public val node: M) : TypedMetaItem<M>() {
|
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
|
//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()
|
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())
|
public fun MutableItemProvider.getChild(childName: String): MutableItemProvider = getChild(childName.toName())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update existing mutable node with another node. The rules are following:
|
* Update existing mutable node with another node. The rules are following:
|
||||||
* * value replaces anything
|
* * value replaces anything
|
||||||
@ -126,4 +128,4 @@ public fun MutableItemProvider.withDefault(default: ItemProvider?): MutableItemP
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getItem(name: Name): MetaItem? = this@withDefault.getItem(name) ?: default.getItem(name)
|
override fun getItem(name: Name): MetaItem? = this@withDefault.getItem(name) ?: default.getItem(name)
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package space.kscience.dataforge.meta
|
package space.kscience.dataforge.meta
|
||||||
|
|
||||||
|
import space.kscience.dataforge.misc.DFExperimental
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import kotlin.properties.ReadWriteProperty
|
import kotlin.properties.ReadWriteProperty
|
||||||
@ -30,7 +31,7 @@ public interface ReadOnlySpecification<out T : ItemProvider> {
|
|||||||
* By convention [Scheme] companion should inherit this class
|
* 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]
|
* 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? =
|
public fun <T : MutableItemProvider> TypedMetaItem<MutableMeta<*>>.withSpec(spec: Specification<T>): T? =
|
||||||
node?.let { spec.write(it) }
|
node?.let { spec.write(it) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A delegate that uses a [Specification] to wrap a child of this provider
|
||||||
|
*/
|
||||||
public fun <T : Scheme> MutableItemProvider.spec(
|
public fun <T : Scheme> MutableItemProvider.spec(
|
||||||
spec: Specification<T>,
|
spec: Specification<T>,
|
||||||
key: Name? = null,
|
key: Name? = null,
|
||||||
@ -71,3 +75,32 @@ public fun <T : Scheme> MutableItemProvider.spec(
|
|||||||
set(name, value.toMeta().asMetaItem())
|
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