Add alternative device syntax
This commit is contained in:
parent
b1d3ba59bc
commit
e182af403f
@ -1,8 +1,13 @@
|
|||||||
package ru.mipt.npm.controls.properties
|
package ru.mipt.npm.controls.properties
|
||||||
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Deferred
|
||||||
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
import ru.mipt.npm.controls.api.ActionDescriptor
|
import ru.mipt.npm.controls.api.ActionDescriptor
|
||||||
import ru.mipt.npm.controls.api.Device
|
import ru.mipt.npm.controls.api.Device
|
||||||
import ru.mipt.npm.controls.api.PropertyDescriptor
|
import ru.mipt.npm.controls.api.PropertyDescriptor
|
||||||
@ -10,8 +15,6 @@ import space.kscience.dataforge.context.Context
|
|||||||
import space.kscience.dataforge.context.Global
|
import space.kscience.dataforge.context.Global
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.MetaItem
|
import space.kscience.dataforge.meta.MetaItem
|
||||||
import space.kscience.dataforge.meta.TypedMetaItem
|
|
||||||
import kotlin.jvm.Synchronized
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param D recursive self-type for properties and actions
|
* @param D recursive self-type for properties and actions
|
||||||
@ -19,10 +22,13 @@ import kotlin.jvm.Synchronized
|
|||||||
public open class DeviceBySpec<D : DeviceBySpec<D>> : Device {
|
public open class DeviceBySpec<D : DeviceBySpec<D>> : Device {
|
||||||
override var context: Context = Global
|
override var context: Context = Global
|
||||||
internal set
|
internal set
|
||||||
|
|
||||||
public var meta: Meta = Meta.EMPTY
|
public var meta: Meta = Meta.EMPTY
|
||||||
internal set
|
internal set
|
||||||
|
|
||||||
public var properties: Map<String, DevicePropertySpec<D, *>> = emptyMap()
|
public var properties: Map<String, DevicePropertySpec<D, *>> = emptyMap()
|
||||||
internal set
|
internal set
|
||||||
|
|
||||||
public var actions: Map<String, DeviceActionSpec<D, *, *>> = emptyMap()
|
public var actions: Map<String, DeviceActionSpec<D, *, *>> = emptyMap()
|
||||||
internal set
|
internal set
|
||||||
|
|
||||||
@ -36,17 +42,28 @@ public open class DeviceBySpec<D: DeviceBySpec<D>> : Device {
|
|||||||
|
|
||||||
private val logicalState: HashMap<String, MetaItem?> = HashMap()
|
private val logicalState: HashMap<String, MetaItem?> = HashMap()
|
||||||
|
|
||||||
private val _propertyFlow: MutableSharedFlow<Pair<String, TypedMetaItem<*>>> = MutableSharedFlow()
|
private val _propertyFlow: MutableSharedFlow<Pair<String, MetaItem>> = MutableSharedFlow()
|
||||||
|
|
||||||
override val propertyFlow: SharedFlow<Pair<String, MetaItem>> get() = _propertyFlow
|
override val propertyFlow: SharedFlow<Pair<String, MetaItem>> get() = _propertyFlow
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
internal val self: D get() = this as D
|
internal val self: D
|
||||||
|
get() = this as D
|
||||||
|
|
||||||
@Synchronized
|
internal fun getLogicalState(propertyName: String): MetaItem? = logicalState[propertyName]
|
||||||
private fun setLogicalState(propertyName: String, value: MetaItem?) {
|
|
||||||
|
private val stateLock = Mutex()
|
||||||
|
|
||||||
|
internal suspend fun setLogicalState(propertyName: String, value: MetaItem?) {
|
||||||
|
if (value != logicalState[propertyName]) {
|
||||||
|
stateLock.withLock {
|
||||||
logicalState[propertyName] = value
|
logicalState[propertyName] = value
|
||||||
}
|
}
|
||||||
|
if (value != null) {
|
||||||
|
_propertyFlow.emit(propertyName to value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Force read physical value and push an update if it is changed
|
* Force read physical value and push an update if it is changed
|
||||||
@ -54,10 +71,7 @@ public open class DeviceBySpec<D: DeviceBySpec<D>> : Device {
|
|||||||
public suspend fun readProperty(propertyName: String): MetaItem {
|
public suspend fun readProperty(propertyName: String): MetaItem {
|
||||||
val newValue = properties[propertyName]?.readItem(self)
|
val newValue = properties[propertyName]?.readItem(self)
|
||||||
?: error("A property with name $propertyName is not registered in $this")
|
?: error("A property with name $propertyName is not registered in $this")
|
||||||
if (newValue != logicalState[propertyName]) {
|
|
||||||
setLogicalState(propertyName, newValue)
|
setLogicalState(propertyName, newValue)
|
||||||
_propertyFlow.emit(propertyName to newValue)
|
|
||||||
}
|
|
||||||
return newValue
|
return newValue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,8 +79,10 @@ public open class DeviceBySpec<D: DeviceBySpec<D>> : Device {
|
|||||||
logicalState[propertyName] ?: readProperty(propertyName)
|
logicalState[propertyName] ?: readProperty(propertyName)
|
||||||
|
|
||||||
override suspend fun invalidateProperty(propertyName: String) {
|
override suspend fun invalidateProperty(propertyName: String) {
|
||||||
|
stateLock.withLock {
|
||||||
logicalState.remove(propertyName)
|
logicalState.remove(propertyName)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun setProperty(propertyName: String, value: MetaItem) {
|
override suspend fun setProperty(propertyName: String, value: MetaItem) {
|
||||||
//If there is a physical property with given name, invalidate logical property and write physical one
|
//If there is a physical property with given name, invalidate logical property and write physical one
|
||||||
@ -81,3 +97,19 @@ public open class DeviceBySpec<D: DeviceBySpec<D>> : Device {
|
|||||||
override suspend fun execute(action: String, argument: MetaItem?): MetaItem? =
|
override suspend fun execute(action: String, argument: MetaItem?): MetaItem? =
|
||||||
actions[action]?.executeItem(self, argument)
|
actions[action]?.executeItem(self, argument)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public operator fun <D : DeviceBySpec<D>, T : Any> D.get(
|
||||||
|
propertySpec: DevicePropertySpec<D, T>
|
||||||
|
): Deferred<T> = scope.async {
|
||||||
|
propertySpec.read(this@get).also {
|
||||||
|
setLogicalState(propertySpec.name, propertySpec.converter.objectToMetaItem(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public operator fun <D : DeviceBySpec<D>, T : Any> D.set(propertySpec: WritableDevicePropertySpec<D, T>, value: T) {
|
||||||
|
scope.launch {
|
||||||
|
propertySpec.write(this@set, value)
|
||||||
|
invalidateProperty(propertySpec.name)
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package ru.mipt.npm.controls.properties
|
package ru.mipt.npm.controls.properties
|
||||||
|
|
||||||
|
import kotlinx.coroutines.Deferred
|
||||||
import ru.mipt.npm.controls.api.ActionDescriptor
|
import ru.mipt.npm.controls.api.ActionDescriptor
|
||||||
import ru.mipt.npm.controls.api.PropertyDescriptor
|
import ru.mipt.npm.controls.api.PropertyDescriptor
|
||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
@ -8,6 +9,7 @@ import space.kscience.dataforge.meta.Meta
|
|||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
import space.kscience.dataforge.meta.transformations.MetaConverter
|
||||||
import kotlin.properties.PropertyDelegateProvider
|
import kotlin.properties.PropertyDelegateProvider
|
||||||
import kotlin.properties.ReadOnlyProperty
|
import kotlin.properties.ReadOnlyProperty
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
public abstract class DeviceSpec<D : DeviceBySpec<D>>(
|
public abstract class DeviceSpec<D : DeviceBySpec<D>>(
|
||||||
private val buildDevice: () -> D
|
private val buildDevice: () -> D
|
||||||
@ -44,7 +46,7 @@ public abstract class DeviceSpec<D : DeviceBySpec<D>>(
|
|||||||
read: suspend D.() -> T,
|
read: suspend D.() -> T,
|
||||||
write: suspend D.(T) -> Unit
|
write: suspend D.(T) -> Unit
|
||||||
): PropertyDelegateProvider<DeviceSpec<D>, ReadOnlyProperty<DeviceSpec<D>, WritableDevicePropertySpec<D, T>>> =
|
): PropertyDelegateProvider<DeviceSpec<D>, ReadOnlyProperty<DeviceSpec<D>, WritableDevicePropertySpec<D, T>>> =
|
||||||
PropertyDelegateProvider { _: DeviceSpec<D>, property ->
|
PropertyDelegateProvider { _: DeviceSpec<D>, property: KProperty<*> ->
|
||||||
val propertyName = name ?: property.name
|
val propertyName = name ?: property.name
|
||||||
val deviceProperty = object : WritableDevicePropertySpec<D, T> {
|
val deviceProperty = object : WritableDevicePropertySpec<D, T> {
|
||||||
override val name: String = propertyName
|
override val name: String = propertyName
|
||||||
|
Loading…
Reference in New Issue
Block a user