Add byte array value. Refactor exotic values

This commit is contained in:
Alexander Nozik 2024-04-02 10:03:18 +03:00
parent 9fe3deac33
commit 104111f62d
8 changed files with 177 additions and 22 deletions

View File

@ -135,7 +135,7 @@ public interface MetaConverter<T>: MetaSpec<T> {
@DFExperimental @DFExperimental
public inline fun <reified T> serializable( public inline fun <reified T> serializable(
descriptor: MetaDescriptor? = null, descriptor: MetaDescriptor? = null,
jsonEncoder: Json = Json { ignoreUnknownKeys = true }, jsonEncoder: Json = Json,
): MetaConverter<T> = object : MetaConverter<T> { ): MetaConverter<T> = object : MetaConverter<T> {
private val serializer: KSerializer<T> = serializer() private val serializer: KSerializer<T> = serializer()

View File

@ -197,17 +197,6 @@ public fun MutableMetaProvider.numberList(
reader = { it?.list?.map { value -> value.numberOrNull ?: Double.NaN } ?: listOf(*default) }, reader = { it?.list?.map { value -> value.numberOrNull ?: Double.NaN } ?: listOf(*default) },
) )
/* A special delegate for double arrays */
public fun MutableMetaProvider.doubleArray(
vararg default: Double,
key: Name? = null,
): ReadWriteProperty<Any?, DoubleArray> = value(
key,
writer = { DoubleArrayValue(it) },
reader = { it?.doubleArray ?: doubleArrayOf(*default) },
)
public fun <T> MutableMetaProvider.listValue( public fun <T> MutableMetaProvider.listValue(
key: Name? = null, key: Name? = null,

View File

@ -256,8 +256,6 @@ public fun ShortArray.asValue(): Value = if (isEmpty()) Null else ListValue(map
public fun FloatArray.asValue(): Value = if (isEmpty()) Null else ListValue(map { NumberValue(it) }) public fun FloatArray.asValue(): Value = if (isEmpty()) Null else ListValue(map { NumberValue(it) })
public fun ByteArray.asValue(): Value = if (isEmpty()) Null else ListValue(map { NumberValue(it) })
public fun <E : Enum<E>> E.asValue(): Value = EnumValue(this) public fun <E : Enum<E>> E.asValue(): Value = EnumValue(this)

View File

@ -1,5 +1,9 @@
package space.kscience.dataforge.meta package space.kscience.dataforge.meta
import space.kscience.dataforge.names.Name
import kotlin.properties.ReadOnlyProperty
import kotlin.properties.ReadWriteProperty
/** /**
* A value built from string which content and type are parsed on-demand * A value built from string which content and type are parsed on-demand
@ -44,3 +48,79 @@ public class DoubleArrayValue(override val value: DoubleArray) : Value, Iterable
} }
public fun DoubleArray.asValue(): Value = if (isEmpty()) Null else DoubleArrayValue(this) public fun DoubleArray.asValue(): Value = if (isEmpty()) Null else DoubleArrayValue(this)
public val Value.doubleArray: DoubleArray
get() = if (this is DoubleArrayValue) {
value
} else {
DoubleArray(list.size) { list[it].double }
}
public val Meta?.doubleArray: DoubleArray? get() = this?.value?.doubleArray
public fun MetaProvider.doubleArray(
vararg default: Double,
key: Name? = null,
): ReadOnlyProperty<Any?, DoubleArray> = value(
key,
reader = { it?.doubleArray ?: doubleArrayOf(*default) },
)
public fun MutableMetaProvider.doubleArray(
vararg default: Double,
key: Name? = null,
): ReadWriteProperty<Any?, DoubleArray> = value(
key,
writer = { DoubleArrayValue(it) },
reader = { it?.doubleArray ?: doubleArrayOf(*default) },
)
public class ByteArrayValue(override val value: ByteArray) : Value, Iterable<Byte> {
override val type: ValueType get() = ValueType.LIST
override val list: List<Value> get() = value.map { NumberValue(it) }
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Value) return false
return when (other) {
is ByteArrayValue -> value.contentEquals(other.value)
else -> list == other.list
}
}
override fun hashCode(): Int = value.contentHashCode()
override fun toString(): String = list.joinToString(prefix = "[", postfix = "]")
override fun iterator(): Iterator<Byte> = value.iterator()
}
public fun ByteArray.asValue(): Value = ByteArrayValue(this)
public val Value.byteArray: ByteArray
get() = if (this is ByteArrayValue) {
value
} else {
ByteArray(list.size) { list[it].number.toByte() }
}
public val Meta?.byteArray: ByteArray? get() = this?.value?.byteArray
public fun MetaProvider.byteArray(
vararg default: Byte,
key: Name? = null,
): ReadOnlyProperty<Any?, ByteArray> = value(
key,
reader = { it?.byteArray ?: byteArrayOf(*default) },
)
public fun MutableMetaProvider.byteArray(
vararg default: Byte,
key: Name? = null,
): ReadWriteProperty<Any?, ByteArray> = value(
key,
writer = { ByteArrayValue(it) },
reader = { it?.byteArray ?: byteArrayOf(*default) },
)

View File

@ -31,12 +31,5 @@ public inline fun <reified E : Enum<E>> Value.enum(): E = if (this is EnumValue<
public val Value.stringList: List<String> get() = list.map { it.string } public val Value.stringList: List<String> get() = list.map { it.string }
public val Value.doubleArray: DoubleArray
get() = if (this is DoubleArrayValue) {
value
} else {
DoubleArray(list.size) { list[it].double }
}
public fun Value.toMeta(): Meta = Meta(this) public fun Value.toMeta(): Meta = Meta(this)

View File

@ -18,4 +18,11 @@ public annotation class DFExperimental
*/ */
@RequiresOptIn(level = RequiresOptIn.Level.WARNING) @RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Retention(AnnotationRetention.BINARY) @Retention(AnnotationRetention.BINARY)
public annotation class DFInternal public annotation class DFInternal
/**
* Annotation marks methods that explicitly use KType without checking that it corresponds to the type parameter
*/
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Retention(AnnotationRetention.BINARY)
public annotation class UnsafeKType

View File

@ -1,7 +1,17 @@
package space.kscience.dataforge.meta package space.kscience.dataforge.meta
import space.kscience.dataforge.misc.DFExperimental
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertNotNull
internal class SubScheme : Scheme() {
var subValue by string()
companion object : SchemeSpec<SubScheme>(::SubScheme)
}
internal class TestScheme : Scheme() { internal class TestScheme : Scheme() {
var list by numberList(1, 2, 3) var list by numberList(1, 2, 3)
@ -11,9 +21,23 @@ internal class TestScheme : Scheme() {
var v by value() var v by value()
var sub by scheme(SubScheme)
companion object : SchemeSpec<TestScheme>(::TestScheme) companion object : SchemeSpec<TestScheme>(::TestScheme)
} }
private class SchemeWithInit: Scheme(){
init {
set("initial", "initialValue")
}
var initial by string()
companion object: SchemeSpec<SchemeWithInit>(::SchemeWithInit)
}
class SpecificationTest { class SpecificationTest {
// @Test // @Test
@ -71,4 +95,64 @@ class SpecificationTest {
assertEquals(22, config["child.a"].int) assertEquals(22, config["child.a"].int)
assertEquals("test", config["child.b"].string) assertEquals("test", config["child.b"].string)
} }
@Test
fun testSchemeWrappingBeforeEdit() {
val config = MutableMeta()
val scheme = TestScheme.write(config)
scheme.a = 29
assertEquals(29, config["a"].int)
}
@OptIn(DFExperimental::class)
@Test
fun testSchemeWrappingAfterEdit() {
val scheme = TestScheme.empty()
scheme.a = 29
val config = MutableMeta()
scheme.retarget(config)
assertEquals(29, scheme.a)
}
@Test
fun testSchemeSubscription() {
val scheme = TestScheme.empty()
var flag: Int? = null
scheme.useProperty(TestScheme::a) { a ->
flag = a
}
scheme.a = 2
assertEquals(2, flag)
}
@Test
fun testListSubscription(){
val scheme = TestScheme.empty()
var value: Value? = null
scheme.v = ListValue(0.0,0.0,0.0)
scheme.useProperty(TestScheme::v){
value = it
}
scheme.v = ListValue(1.0, 2.0, 3.0)
assertNotNull(value)
}
@Test
fun testSubScheme(){
val scheme = TestScheme.empty()
scheme.sub.subValue = "aaa"
assertEquals("aaa",scheme.sub.subValue)
}
@Test
fun testSchemeWithInit(){
val scheme = SchemeWithInit()
assertEquals("initialValue", scheme.initial)
scheme.initial = "none"
assertEquals("none", scheme.initial)
}
} }

View File

@ -0,0 +1,4 @@
package space.kscience.dataforge.values
class DoubleArrayValue {
}