[WIP] working on constructor

This commit is contained in:
Alexander Nozik 2024-05-21 13:31:01 +03:00
parent a66e411848
commit 673a7c89a6
6 changed files with 92 additions and 59 deletions

View File

@ -1,35 +0,0 @@
package space.kscience.controls.constructor
import space.kscience.controls.api.Device
/**
* A binding that is used to describe device functionality
*/
public sealed interface Binding
/**
* A binding that exposes device property as read-only state
*/
public class PropertyBinding<T>(
public val device: Device,
public val propertyName: String,
public val state: DeviceState<T>,
) : Binding
/**
* A binding for independent state like a timer
*/
public class StateBinding<T>(
public val state: DeviceState<T>
) : Binding
public class ActionBinding(
public val reads: Collection<DeviceState<*>>,
public val writes: Collection<DeviceState<*>>
): Binding
public interface BindingsContainer{
public val bindings: List<Binding>
public fun registerBinding(binding: Binding)
}

View File

@ -5,12 +5,10 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import space.kscience.controls.api.Device import space.kscience.controls.api.Device
import space.kscience.controls.api.PropertyDescriptor import space.kscience.controls.api.PropertyDescriptor
import space.kscience.controls.manager.ClockManager
import space.kscience.controls.spec.DevicePropertySpec import space.kscience.controls.spec.DevicePropertySpec
import space.kscience.controls.spec.MutableDevicePropertySpec import space.kscience.controls.spec.MutableDevicePropertySpec
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.Factory import space.kscience.dataforge.context.Factory
import space.kscience.dataforge.context.request
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MetaConverter import space.kscience.dataforge.meta.MetaConverter
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
@ -26,25 +24,19 @@ import kotlin.time.Duration
public abstract class DeviceConstructor( public abstract class DeviceConstructor(
context: Context, context: Context,
meta: Meta = Meta.EMPTY, meta: Meta = Meta.EMPTY,
) : DeviceGroup(context, meta), BindingsContainer { ) : DeviceGroup(context, meta), StateContainer {
private val _bindings: MutableList<Binding> = mutableListOf() private val _stateDescriptors: MutableList<StateDescriptor> = mutableListOf()
override val bindings: List<Binding> get() = _bindings override val stateDescriptors: List<StateDescriptor> get() = _stateDescriptors
override fun registerBinding(binding: Binding) { override fun registerState(stateDescriptor: StateDescriptor) {
_bindings.add(binding) _stateDescriptors.add(stateDescriptor)
} }
override fun registerProperty(descriptor: PropertyDescriptor, state: DeviceState<*>) { override fun registerProperty(descriptor: PropertyDescriptor, state: DeviceState<*>) {
super.registerProperty(descriptor, state) super.registerProperty(descriptor, state)
registerBinding(PropertyBinding(this, descriptor.name, state)) registerState(PropertyStateDescriptor(this, descriptor.name, state))
} }
/**
* Create and register a timer. Timer is not counted as a device property.
*/
public fun timer(tick: Duration): TimerState = TimerState(context.request(ClockManager), tick)
.also { registerBinding(StateBinding(it)) }
/** /**
* Bind an action to a [DeviceState]. [onChange] block is performed on each state change * Bind an action to a [DeviceState]. [onChange] block is performed on each state change
* *
@ -55,7 +47,7 @@ public abstract class DeviceConstructor(
reads: Collection<DeviceState<*>>, reads: Collection<DeviceState<*>>,
onChange: suspend (T) -> Unit, onChange: suspend (T) -> Unit,
): Job = valueFlow.onEach(onChange).launchIn(this@DeviceConstructor).also { ): Job = valueFlow.onEach(onChange).launchIn(this@DeviceConstructor).also {
registerBinding(ActionBinding(setOf(this, *reads.toTypedArray()), setOf(*writes))) registerState(ConnectionStateDescriptor(setOf(this, *reads.toTypedArray()), setOf(*writes)))
} }
} }
@ -171,4 +163,4 @@ public fun <T, D : Device> DeviceConstructor.deviceProperty(
property: MutableDevicePropertySpec<D, T>, property: MutableDevicePropertySpec<D, T>,
initialValue: T, initialValue: T,
): PropertyDelegateProvider<DeviceConstructor, ReadOnlyProperty<DeviceConstructor, MutableDeviceState<T>>> = ): PropertyDelegateProvider<DeviceConstructor, ReadOnlyProperty<DeviceConstructor, MutableDeviceState<T>>> =
property(device.mutablePropertyAsState(property, initialValue)) property(device.mutablePropertyAsState(property, initialValue))

View File

@ -1,12 +1,14 @@
package space.kscience.controls.constructor package space.kscience.controls.constructor
public abstract class DeviceModel : BindingsContainer { import space.kscience.dataforge.context.Context
private val _bindings: MutableList<Binding> = mutableListOf() public abstract class DeviceModel(override val context: Context) : StateContainer {
override val bindings: List<Binding> get() = _bindings private val _stateDescriptors: MutableList<StateDescriptor> = mutableListOf()
override fun registerBinding(binding: Binding) { override val stateDescriptors: List<StateDescriptor> get() = _stateDescriptors
_bindings.add(binding)
override fun registerState(stateDescriptor: StateDescriptor) {
_stateDescriptors.add(stateDescriptor)
} }
} }

View File

@ -0,0 +1,74 @@
package space.kscience.controls.constructor
import space.kscience.controls.api.Device
import space.kscience.controls.manager.ClockManager
import space.kscience.dataforge.context.ContextAware
import space.kscience.dataforge.context.request
import space.kscience.dataforge.meta.MetaConverter
import kotlin.time.Duration
/**
* A binding that is used to describe device functionality
*/
public sealed interface StateDescriptor
/**
* A binding that exposes device property as read-only state
*/
public class PropertyStateDescriptor<T>(
public val device: Device,
public val propertyName: String,
public val state: DeviceState<T>,
) : StateDescriptor
/**
* A binding for independent state like a timer
*/
public class StateBinding<T>(
public val state: DeviceState<T>,
) : StateDescriptor
public class ConnectionStateDescriptor(
public val reads: Collection<DeviceState<*>>,
public val writes: Collection<DeviceState<*>>,
) : StateDescriptor
public interface StateContainer : ContextAware {
public val stateDescriptors: List<StateDescriptor>
public fun registerState(stateDescriptor: StateDescriptor)
}
/**
* Register a [state] in this container. The state is not registered as a device property if [this] is a [DeviceConstructor]
*/
public fun <T, D : DeviceState<T>> StateContainer.state(state: D): D {
registerState(StateBinding(state))
return state
}
/**
* Create a register a [MutableDeviceState] with a given [converter]
*/
public fun <T> StateContainer.state(converter: MetaConverter<T>, initialValue: T): MutableDeviceState<T> = state(
DeviceState.internal(converter, initialValue)
)
/**
* Create a register a mutable [Double] state
*/
public fun StateContainer.doubleState(initialValue: Double): MutableDeviceState<Double> = state(
MetaConverter.double, initialValue
)
/**
* Create a register a mutable [String] state
*/
public fun StateContainer.stringState(initialValue: String): MutableDeviceState<String> = state(
MetaConverter.string, initialValue
)
/**
* Create and register a timer state.
*/
public fun StateContainer.timer(tick: Duration): TimerState = state(TimerState(context.request(ClockManager), tick))

View File

@ -51,9 +51,9 @@ public class DoubleInRangeState(
/** /**
* Create and register a [DoubleInRangeState] * Create and register a [DoubleInRangeState]
*/ */
public fun BindingsContainer.doubleInRangeState( public fun StateContainer.doubleInRangeState(
initialValue: Double, initialValue: Double,
range: ClosedFloatingPointRange<Double>, range: ClosedFloatingPointRange<Double>,
): DoubleInRangeState = DoubleInRangeState(initialValue, range).also { ): DoubleInRangeState = DoubleInRangeState(initialValue, range).also {
registerBinding(StateBinding(it)) registerState(StateBinding(it))
} }

View File

@ -12,7 +12,7 @@ kscience {
useKtor() useKtor()
useSerialization() useSerialization()
useContextReceivers() useContextReceivers()
dependencies { commonMain {
api(projects.controlsCore) api(projects.controlsCore)
api(projects.controlsConstructor) api(projects.controlsConstructor)
api(libs.visionforge.plotly) api(libs.visionforge.plotly)