Refactor Value.

This commit is contained in:
Alexander Nozik 2020-12-09 12:04:10 +03:00
parent e317b67a48
commit 7c4d69ec1b
20 changed files with 117 additions and 152 deletions

View File

@ -4,6 +4,7 @@
### Added ### Added
- Yaml meta format based on yaml.kt - Yaml meta format based on yaml.kt
- `Path` builders - `Path` builders
- Special ValueType for lists
### Changed ### Changed
- `ListValue` and `DoubleArrayValue` implement `Iterable`. - `ListValue` and `DoubleArrayValue` implement `Iterable`.
@ -11,6 +12,7 @@
- `Meta{}` builder made inline - `Meta{}` builder made inline
- Moved `Envelope` builder to a top level function. Companion invoke is deprecated. - Moved `Envelope` builder to a top level function. Companion invoke is deprecated.
- Context logging moved to the extension - Context logging moved to the extension
- `number` and `string` methods on `Value` moved to extensions (breaking change)
### Deprecated ### Deprecated

View File

@ -84,6 +84,6 @@ public fun <T : Any> Provider.top(target: String, type: KClass<out T>): Map<Name
/** /**
* Typed top level content * Typed top level content
*/ */
public inline fun <reified T : Any> Provider.top(target: String): Map<Name, T> = top(target, T::class) public inline fun <reified T : Any> Provider.top(target: String ): Map<Name, T> = top(target, T::class)

View File

@ -17,6 +17,7 @@ public class FrontMatterEnvelopeFormat(
) : EnvelopeFormat { ) : EnvelopeFormat {
override fun readPartial(input: Input): PartialEnvelope { override fun readPartial(input: Input): PartialEnvelope {
@Suppress("VARIABLE_WITH_REDUNDANT_INITIALIZER")
var line = "" var line = ""
var offset = 0u var offset = 0u
do { do {

View File

@ -32,57 +32,56 @@ public object BinaryMetaFormat : MetaFormat, MetaFormatFactory {
writeUtf8String(str) writeUtf8String(str)
} }
public fun Output.writeValue(value: Value) { public fun Output.writeValue(value: Value): Unit = when (value.type) {
if (value.isList()) { ValueType.NUMBER -> when (value.value) {
is Short -> {
writeChar('s')
writeShort(value.short)
}
is Int -> {
writeChar('i')
writeInt(value.int)
}
is Long -> {
writeChar('l')
writeLong(value.long)
}
is Float -> {
writeChar('f')
writeFloat(value.float)
}
else -> {
writeChar('d')
writeDouble(value.double)
}
}
ValueType.STRING -> {
writeChar('S')
writeString(value.string)
}
ValueType.BOOLEAN -> {
if (value.boolean) {
writeChar('+')
} else {
writeChar('-')
}
}
ValueType.NULL -> {
writeChar('N')
}
ValueType.LIST -> {
writeChar('L') writeChar('L')
writeInt(value.list.size) writeInt(value.list.size)
value.list.forEach { value.list.forEach {
writeValue(it) writeValue(it)
} }
} else when (value.type) {
ValueType.NUMBER -> when (value.value) {
is Short -> {
writeChar('s')
writeShort(value.number.toShort())
}
is Int -> {
writeChar('i')
writeInt(value.number.toInt())
}
is Long -> {
writeChar('l')
writeLong(value.number.toLong())
}
is Float -> {
writeChar('f')
writeFloat(value.number.toFloat())
}
else -> {
writeChar('d')
writeDouble(value.number.toDouble())
}
}
ValueType.STRING -> {
writeChar('S')
writeString(value.string)
}
ValueType.BOOLEAN -> {
if (value.boolean) {
writeChar('+')
} else {
writeChar('-')
}
}
ValueType.NULL -> {
writeChar('N')
}
} }
} }
override fun writeMeta( override fun writeMeta(
output: kotlinx.io.Output, output: kotlinx.io.Output,
meta: hep.dataforge.meta.Meta, meta: hep.dataforge.meta.Meta,
descriptor: hep.dataforge.meta.descriptors.NodeDescriptor? descriptor: hep.dataforge.meta.descriptors.NodeDescriptor?,
) { ) {
output.writeChar('M') output.writeChar('M')
output.writeInt(meta.items.size) output.writeInt(meta.items.size)

View File

@ -29,9 +29,7 @@ public interface Envelope {
/** /**
* Build a static envelope using provided builder * Build a static envelope using provided builder
*/ */
@Deprecated("Use top level function instead", @Deprecated("Use top level function instead")
replaceWith = ReplaceWith("Envelope(block)", "hep.dataforge.io.Envelope")
)
public inline operator fun invoke(block: EnvelopeBuilder.() -> Unit): Envelope = public inline operator fun invoke(block: EnvelopeBuilder.() -> Unit): Envelope =
EnvelopeBuilder().apply(block).seal() EnvelopeBuilder().apply(block).seal()
} }

View File

@ -7,7 +7,7 @@ import kotlin.test.assertEquals
class EnvelopeFormatTest { class EnvelopeFormatTest {
val envelope = Envelope.invoke { val envelope = Envelope {
type = "test.format" type = "test.format"
meta{ meta{
"d" put 22.2 "d" put 22.2

View File

@ -2,6 +2,7 @@ package hep.dataforge.io
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.meta.JsonMeta.Companion.JSON_ARRAY_KEY import hep.dataforge.meta.JsonMeta.Companion.JSON_ARRAY_KEY
import hep.dataforge.values.number
import kotlinx.io.asBinary import kotlinx.io.asBinary
import kotlinx.serialization.json.* import kotlinx.serialization.json.*
import kotlin.test.Test import kotlin.test.Test

View File

@ -817,9 +817,6 @@ public final class hep/dataforge/values/DoubleArrayValue : hep/dataforge/values/
public fun <init> ([D)V public fun <init> ([D)V
public fun equals (Ljava/lang/Object;)Z public fun equals (Ljava/lang/Object;)Z
public fun getList ()Ljava/util/List; public fun getList ()Ljava/util/List;
public fun getNumber ()Ljava/lang/Double;
public synthetic fun getNumber ()Ljava/lang/Number;
public fun getString ()Ljava/lang/String;
public fun getType ()Lhep/dataforge/values/ValueType; public fun getType ()Lhep/dataforge/values/ValueType;
public synthetic fun getValue ()Ljava/lang/Object; public synthetic fun getValue ()Ljava/lang/Object;
public fun getValue ()[D public fun getValue ()[D
@ -832,8 +829,6 @@ public final class hep/dataforge/values/EnumValue : hep/dataforge/values/Value {
public fun <init> (Ljava/lang/Enum;)V public fun <init> (Ljava/lang/Enum;)V
public fun equals (Ljava/lang/Object;)Z public fun equals (Ljava/lang/Object;)Z
public fun getList ()Ljava/util/List; public fun getList ()Ljava/util/List;
public fun getNumber ()Ljava/lang/Number;
public fun getString ()Ljava/lang/String;
public fun getType ()Lhep/dataforge/values/ValueType; public fun getType ()Lhep/dataforge/values/ValueType;
public fun getValue ()Ljava/lang/Enum; public fun getValue ()Ljava/lang/Enum;
public synthetic fun getValue ()Ljava/lang/Object; public synthetic fun getValue ()Ljava/lang/Object;
@ -850,8 +845,6 @@ public final class hep/dataforge/values/False : hep/dataforge/values/Value {
public static final field INSTANCE Lhep/dataforge/values/False; public static final field INSTANCE Lhep/dataforge/values/False;
public fun equals (Ljava/lang/Object;)Z public fun equals (Ljava/lang/Object;)Z
public fun getList ()Ljava/util/List; public fun getList ()Ljava/util/List;
public fun getNumber ()Ljava/lang/Number;
public fun getString ()Ljava/lang/String;
public fun getType ()Lhep/dataforge/values/ValueType; public fun getType ()Lhep/dataforge/values/ValueType;
public fun getValue ()Ljava/lang/Object; public fun getValue ()Ljava/lang/Object;
public fun hashCode ()I public fun hashCode ()I
@ -862,8 +855,7 @@ public final class hep/dataforge/values/LazyParsedValue : hep/dataforge/values/V
public fun <init> (Ljava/lang/String;)V public fun <init> (Ljava/lang/String;)V
public fun equals (Ljava/lang/Object;)Z public fun equals (Ljava/lang/Object;)Z
public fun getList ()Ljava/util/List; public fun getList ()Ljava/util/List;
public fun getNumber ()Ljava/lang/Number; public final fun getString ()Ljava/lang/String;
public fun getString ()Ljava/lang/String;
public fun getType ()Lhep/dataforge/values/ValueType; public fun getType ()Lhep/dataforge/values/ValueType;
public fun getValue ()Ljava/lang/Object; public fun getValue ()Ljava/lang/Object;
public fun hashCode ()I public fun hashCode ()I
@ -874,8 +866,6 @@ public final class hep/dataforge/values/ListValue : hep/dataforge/values/Value,
public fun <init> (Ljava/util/List;)V public fun <init> (Ljava/util/List;)V
public fun equals (Ljava/lang/Object;)Z public fun equals (Ljava/lang/Object;)Z
public fun getList ()Ljava/util/List; public fun getList ()Ljava/util/List;
public fun getNumber ()Ljava/lang/Number;
public fun getString ()Ljava/lang/String;
public fun getType ()Lhep/dataforge/values/ValueType; public fun getType ()Lhep/dataforge/values/ValueType;
public synthetic fun getValue ()Ljava/lang/Object; public synthetic fun getValue ()Ljava/lang/Object;
public fun getValue ()Ljava/util/List; public fun getValue ()Ljava/util/List;
@ -888,8 +878,6 @@ public final class hep/dataforge/values/Null : hep/dataforge/values/Value {
public static final field INSTANCE Lhep/dataforge/values/Null; public static final field INSTANCE Lhep/dataforge/values/Null;
public fun equals (Ljava/lang/Object;)Z public fun equals (Ljava/lang/Object;)Z
public fun getList ()Ljava/util/List; public fun getList ()Ljava/util/List;
public fun getNumber ()Ljava/lang/Number;
public fun getString ()Ljava/lang/String;
public fun getType ()Lhep/dataforge/values/ValueType; public fun getType ()Lhep/dataforge/values/ValueType;
public fun getValue ()Ljava/lang/Object; public fun getValue ()Ljava/lang/Object;
public fun hashCode ()I public fun hashCode ()I
@ -900,8 +888,7 @@ public final class hep/dataforge/values/NumberValue : hep/dataforge/values/Value
public fun <init> (Ljava/lang/Number;)V public fun <init> (Ljava/lang/Number;)V
public fun equals (Ljava/lang/Object;)Z public fun equals (Ljava/lang/Object;)Z
public fun getList ()Ljava/util/List; public fun getList ()Ljava/util/List;
public fun getNumber ()Ljava/lang/Number; public final fun getNumber ()Ljava/lang/Number;
public fun getString ()Ljava/lang/String;
public fun getType ()Lhep/dataforge/values/ValueType; public fun getType ()Lhep/dataforge/values/ValueType;
public fun getValue ()Ljava/lang/Object; public fun getValue ()Ljava/lang/Object;
public fun hashCode ()I public fun hashCode ()I
@ -912,8 +899,7 @@ public final class hep/dataforge/values/StringValue : hep/dataforge/values/Value
public fun <init> (Ljava/lang/String;)V public fun <init> (Ljava/lang/String;)V
public fun equals (Ljava/lang/Object;)Z public fun equals (Ljava/lang/Object;)Z
public fun getList ()Ljava/util/List; public fun getList ()Ljava/util/List;
public fun getNumber ()Ljava/lang/Number; public final fun getString ()Ljava/lang/String;
public fun getString ()Ljava/lang/String;
public fun getType ()Lhep/dataforge/values/ValueType; public fun getType ()Lhep/dataforge/values/ValueType;
public fun getValue ()Ljava/lang/Object; public fun getValue ()Ljava/lang/Object;
public fun hashCode ()I public fun hashCode ()I
@ -924,8 +910,6 @@ public final class hep/dataforge/values/True : hep/dataforge/values/Value {
public static final field INSTANCE Lhep/dataforge/values/True; public static final field INSTANCE Lhep/dataforge/values/True;
public fun equals (Ljava/lang/Object;)Z public fun equals (Ljava/lang/Object;)Z
public fun getList ()Ljava/util/List; public fun getList ()Ljava/util/List;
public fun getNumber ()Ljava/lang/Number;
public fun getString ()Ljava/lang/String;
public fun getType ()Lhep/dataforge/values/ValueType; public fun getType ()Lhep/dataforge/values/ValueType;
public fun getValue ()Ljava/lang/Object; public fun getValue ()Ljava/lang/Object;
public fun hashCode ()I public fun hashCode ()I
@ -934,18 +918,16 @@ public final class hep/dataforge/values/True : hep/dataforge/values/Value {
public abstract interface class hep/dataforge/values/Value { public abstract interface class hep/dataforge/values/Value {
public static final field Companion Lhep/dataforge/values/Value$Companion; public static final field Companion Lhep/dataforge/values/Value$Companion;
public static final field TARGET Ljava/lang/String; public static final field TYPE Ljava/lang/String;
public abstract fun equals (Ljava/lang/Object;)Z public abstract fun equals (Ljava/lang/Object;)Z
public abstract fun getList ()Ljava/util/List; public abstract fun getList ()Ljava/util/List;
public abstract fun getNumber ()Ljava/lang/Number;
public abstract fun getString ()Ljava/lang/String;
public abstract fun getType ()Lhep/dataforge/values/ValueType; public abstract fun getType ()Lhep/dataforge/values/ValueType;
public abstract fun getValue ()Ljava/lang/Object; public abstract fun getValue ()Ljava/lang/Object;
public abstract fun hashCode ()I public abstract fun hashCode ()I
} }
public final class hep/dataforge/values/Value$Companion { public final class hep/dataforge/values/Value$Companion {
public static final field TARGET Ljava/lang/String; public static final field TYPE Ljava/lang/String;
public final fun of (Ljava/lang/Object;)Lhep/dataforge/values/Value; public final fun of (Ljava/lang/Object;)Lhep/dataforge/values/Value;
} }
@ -978,6 +960,9 @@ public final class hep/dataforge/values/ValueKt {
public static final fun asValue ([I)Lhep/dataforge/values/Value; public static final fun asValue ([I)Lhep/dataforge/values/Value;
public static final fun asValue ([J)Lhep/dataforge/values/Value; public static final fun asValue ([J)Lhep/dataforge/values/Value;
public static final fun asValue ([S)Lhep/dataforge/values/Value; public static final fun asValue ([S)Lhep/dataforge/values/Value;
public static final fun getNumber (Lhep/dataforge/values/Value;)Ljava/lang/Number;
public static final fun getNumberOrNull (Lhep/dataforge/values/Value;)Ljava/lang/Number;
public static final fun getString (Lhep/dataforge/values/Value;)Ljava/lang/String;
public static final fun parseValue (Ljava/lang/String;)Lhep/dataforge/values/Value; public static final fun parseValue (Ljava/lang/String;)Lhep/dataforge/values/Value;
} }
@ -993,6 +978,7 @@ public final class hep/dataforge/values/ValueSerializer : kotlinx/serialization/
public final class hep/dataforge/values/ValueType : java/lang/Enum { public final class hep/dataforge/values/ValueType : java/lang/Enum {
public static final field BOOLEAN Lhep/dataforge/values/ValueType; public static final field BOOLEAN Lhep/dataforge/values/ValueType;
public static final field Companion Lhep/dataforge/values/ValueType$Companion; public static final field Companion Lhep/dataforge/values/ValueType$Companion;
public static final field LIST Lhep/dataforge/values/ValueType;
public static final field NULL Lhep/dataforge/values/ValueType; public static final field NULL Lhep/dataforge/values/ValueType;
public static final field NUMBER Lhep/dataforge/values/ValueType; public static final field NUMBER Lhep/dataforge/values/ValueType;
public static final field STRING Lhep/dataforge/values/ValueType; public static final field STRING Lhep/dataforge/values/ValueType;

View File

@ -16,20 +16,16 @@ import kotlinx.serialization.json.*
/** /**
* @param descriptor reserved for custom serialization in future * @param descriptor reserved for custom serialization in future
*/ */
public fun Value.toJson(descriptor: ValueDescriptor? = null): JsonElement { public fun Value.toJson(descriptor: ValueDescriptor? = null): JsonElement = when (type) {
return if (isList()) { ValueType.NUMBER -> JsonPrimitive(numberOrNull)
JsonArray(list.map { it.toJson() }) ValueType.STRING -> JsonPrimitive(string)
} else { ValueType.BOOLEAN -> JsonPrimitive(boolean)
when (type) { ValueType.LIST -> JsonArray(list.map { it.toJson() })
ValueType.NUMBER -> JsonPrimitive(number) ValueType.NULL -> JsonNull
ValueType.STRING -> JsonPrimitive(string)
ValueType.BOOLEAN -> JsonPrimitive(boolean)
ValueType.NULL -> JsonNull
}
}
} }
//Use these methods to customize JSON key mapping //Use these methods to customize JSON key mapping
@Suppress("NULLABLE_EXTENSION_OPERATOR_WITH_SAFE_CALL_RECEIVER")
private fun String.toJsonKey(descriptor: ItemDescriptor?) = descriptor?.attributes["jsonName"].string ?: toString() private fun String.toJsonKey(descriptor: ItemDescriptor?) = descriptor?.attributes["jsonName"].string ?: toString()
//private fun NodeDescriptor?.getDescriptor(key: String) = this?.items?.get(key) //private fun NodeDescriptor?.getDescriptor(key: String) = this?.items?.get(key)

View File

@ -4,10 +4,7 @@ import hep.dataforge.meta.Meta.Companion.VALUE_KEY
import hep.dataforge.meta.MetaItem.NodeItem import hep.dataforge.meta.MetaItem.NodeItem
import hep.dataforge.meta.MetaItem.ValueItem import hep.dataforge.meta.MetaItem.ValueItem
import hep.dataforge.names.* import hep.dataforge.names.*
import hep.dataforge.values.EnumValue import hep.dataforge.values.*
import hep.dataforge.values.Null
import hep.dataforge.values.Value
import hep.dataforge.values.boolean
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
@ -245,7 +242,7 @@ public val MetaItem<*>?.value: Value?
public val MetaItem<*>?.string: String? get() = value?.string public val MetaItem<*>?.string: String? get() = value?.string
public val MetaItem<*>?.boolean: Boolean? get() = value?.boolean public val MetaItem<*>?.boolean: Boolean? get() = value?.boolean
public val MetaItem<*>?.number: Number? get() = value?.number public val MetaItem<*>?.number: Number? get() = value?.numberOrNull
public val MetaItem<*>?.double: Double? get() = number?.toDouble() public val MetaItem<*>?.double: Double? get() = number?.toDouble()
public val MetaItem<*>?.float: Float? get() = number?.toFloat() public val MetaItem<*>?.float: Float? get() = number?.toFloat()
public val MetaItem<*>?.int: Int? get() = number?.toInt() public val MetaItem<*>?.int: Int? get() = number?.toInt()

View File

@ -3,10 +3,7 @@ package hep.dataforge.meta
import hep.dataforge.meta.transformations.MetaConverter import hep.dataforge.meta.transformations.MetaConverter
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.values.DoubleArrayValue import hep.dataforge.values.*
import hep.dataforge.values.Value
import hep.dataforge.values.asValue
import hep.dataforge.values.doubleArray
import kotlin.properties.ReadWriteProperty import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
@ -72,7 +69,6 @@ public fun <R> MutableItemDelegate.convert(
} }
/* Read-write delegates for [MutableItemProvider] */ /* Read-write delegates for [MutableItemProvider] */
/** /**
@ -171,7 +167,7 @@ public fun MutableItemProvider.numberList(
vararg default: Number, vararg default: Number,
key: Name? = null, key: Name? = null,
): ReadWriteProperty<Any?, List<Number>> = item(key).convert( ): ReadWriteProperty<Any?, List<Number>> = item(key).convert(
reader = { it?.value?.list?.map { value -> value.number } ?: listOf(*default) }, reader = { it?.value?.list?.map { value -> value.numberOrNull ?: Double.NaN } ?: listOf(*default) },
writer = { it.map { num -> num.asValue() }.asValue().asMetaItem() } writer = { it.map { num -> num.asValue() }.asValue().asMetaItem() }
) )

View File

@ -11,7 +11,7 @@ import kotlinx.serialization.Serializable
*/ */
@Serializable @Serializable
public enum class ValueType { public enum class ValueType {
NUMBER, STRING, BOOLEAN, NULL NUMBER, STRING, BOOLEAN, LIST, NULL
} }
/** /**
@ -31,16 +31,6 @@ public interface Value {
*/ */
public val type: ValueType public val type: ValueType
/**
* get this value represented as Number
*/
public val number: Number
/**
* get this value represented as String
*/
public val string: String
/** /**
* get this value represented as List * get this value represented as List
*/ */
@ -51,7 +41,7 @@ public interface Value {
override fun hashCode(): Int override fun hashCode(): Int
public companion object { public companion object {
public const val TARGET: String = "value" public const val TYPE: String = "value"
/** /**
* Convert object to value * Convert object to value
@ -86,16 +76,27 @@ public interface Value {
} }
} }
public val Value.string: String get() = toString()
/**
* get this value represented as Number
*/
public val Value.numberOrNull: Number?
get() = if (this is NumberValue) number else string.toDoubleOrNull()
/**
* Return [Value] number content or throw error if value is not a number
*/
public val Value.number: Number
get() = (if (this is NumberValue) number else numberOrNull ?: error("The value is not a number"))
/** /**
* A singleton null value * A singleton null value
*/ */
public object Null : Value { public object Null : Value {
override val value: Any? get() = null override val value: Any? get() = null
override val type: ValueType get() = ValueType.NULL override val type: ValueType get() = ValueType.NULL
override val number: Number get() = Double.NaN override fun toString(): String = "@null"
override val string: String get() = "@null"
override fun toString(): String = value.toString()
override fun equals(other: Any?): Boolean = other === Null override fun equals(other: Any?): Boolean = other === Null
override fun hashCode(): Int = 0 override fun hashCode(): Int = 0
@ -107,9 +108,6 @@ public object Null : Value {
public object True : Value { public object True : Value {
override val value: Any get() = true override val value: Any get() = true
override val type: ValueType get() = ValueType.BOOLEAN override val type: ValueType get() = ValueType.BOOLEAN
override val number: Number get() = 1.0
override val string: String get() = "true"
override fun toString(): String = value.toString() override fun toString(): String = value.toString()
override fun equals(other: Any?): Boolean = other === True override fun equals(other: Any?): Boolean = other === True
@ -122,42 +120,40 @@ public object True : Value {
public object False : Value { public object False : Value {
override val value: Any get() = false override val value: Any get() = false
override val type: ValueType get() = ValueType.BOOLEAN override val type: ValueType get() = ValueType.BOOLEAN
override val number: Number get() = -1.0
override val string: String get() = "false"
override fun toString(): String = value.toString() override fun toString(): String = value.toString()
override fun equals(other: Any?): Boolean = other === False override fun equals(other: Any?): Boolean = other === False
override fun hashCode(): Int = -1 override fun hashCode(): Int = -1
} }
public class NumberValue(override val number: Number) : Value { public class NumberValue(public val number: Number) : Value {
override val value: Any get() = number override val value: Any get() = number
override val type: ValueType get() = ValueType.NUMBER override val type: ValueType get() = ValueType.NUMBER
override val string: String get() = number.toString()
override fun toString(): String = number.toString()
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (other !is Value) return false if (other !is Value) return false
return when (number) {
is Short -> number.toShort() == other.number.toShort() val otherNumber = other.numberOrNull ?: return false
is Long -> number.toLong() == other.number.toLong()
is Byte -> number.toByte() == other.number.toByte() return when (numberOrNull) {
is Int -> number.toInt() == other.number.toInt() is Short -> number.toShort() == otherNumber.toShort()
is Float -> number.toFloat() == other.number.toFloat() is Long -> number.toLong() == otherNumber.toLong()
is Double -> number.toDouble() == other.number.toDouble() is Byte -> number.toByte() == otherNumber.toByte()
else -> number.toString() == other.number.toString() is Int -> number.toInt() == otherNumber.toInt()
is Float -> number.toFloat() == otherNumber.toFloat()
is Double -> number.toDouble() == otherNumber.toDouble()
else -> number.toString() == otherNumber.toString()
} }
} }
override fun hashCode(): Int = number.hashCode() override fun hashCode(): Int = numberOrNull.hashCode()
override fun toString(): String = value.toString()
} }
public class StringValue(override val string: String) : Value { public class StringValue(public val string: String) : Value {
override val value: Any get() = string override val value: Any get() = string
override val type: ValueType get() = ValueType.STRING override val type: ValueType get() = ValueType.STRING
override val number: Number get() = string.toDouble()
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
return this.string == (other as? Value)?.string return this.string == (other as? Value)?.string
@ -165,21 +161,19 @@ public class StringValue(override val string: String) : Value {
override fun hashCode(): Int = string.hashCode() override fun hashCode(): Int = string.hashCode()
override fun toString(): String = "\"${value.toString()}\"" override fun toString(): String = string
} }
public class EnumValue<E : Enum<*>>(override val value: E) : Value { public class EnumValue<E : Enum<*>>(override val value: E) : Value {
override val type: ValueType get() = ValueType.STRING override val type: ValueType get() = ValueType.STRING
override val number: Number get() = value.ordinal
override val string: String get() = value.name override fun toString(): String = value.toString()
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
return string == (other as? Value)?.string return string == (other as? Value)?.string
} }
override fun hashCode(): Int = value.hashCode() override fun hashCode(): Int = value.hashCode()
override fun toString(): String = value.toString()
} }
public class ListValue(override val list: List<Value>) : Value, Iterable<Value> { public class ListValue(override val list: List<Value>) : Value, Iterable<Value> {
@ -188,9 +182,7 @@ public class ListValue(override val list: List<Value>) : Value, Iterable<Value>
} }
override val value: List<Value> get() = list override val value: List<Value> get() = list
override val type: ValueType get() = list.first().type override val type: ValueType get() = ValueType.LIST
override val number: Number get() = list.first().number
override val string: String get() = list.first().string
override fun toString(): String = list.joinToString(prefix = "[", postfix = "]") override fun toString(): String = list.joinToString(prefix = "[", postfix = "]")
@ -200,7 +192,7 @@ public class ListValue(override val list: List<Value>) : Value, Iterable<Value>
if (this === other) return true if (this === other) return true
if (other !is Value) return false if (other !is Value) return false
if (other is DoubleArrayValue) { if (other is DoubleArrayValue) {
return DoubleArray(list.size) { list[it].number.toDouble() }.contentEquals(other.value) return DoubleArray(list.size) { list[it].numberOrNull?.toDouble() ?: Double.NaN }.contentEquals(other.value)
} }
return list == other.list return list == other.list
} }
@ -208,8 +200,6 @@ public class ListValue(override val list: List<Value>) : Value, Iterable<Value>
override fun hashCode(): Int { override fun hashCode(): Int {
return list.hashCode() return list.hashCode()
} }
} }
public fun Number.asValue(): Value = NumberValue(this) public fun Number.asValue(): Value = NumberValue(this)

View File

@ -24,6 +24,7 @@ public object ValueSerializer : KSerializer<Value> {
ValueType.NUMBER -> decodeDouble().asValue() //TODO differentiate? ValueType.NUMBER -> decodeDouble().asValue() //TODO differentiate?
ValueType.BOOLEAN -> decodeBoolean().asValue() ValueType.BOOLEAN -> decodeBoolean().asValue()
ValueType.STRING -> decodeString().asValue() ValueType.STRING -> decodeString().asValue()
ValueType.LIST -> decodeSerializableValue(ListSerializer(ValueSerializer)).asValue()
} }
} }
@ -45,6 +46,7 @@ public object ValueSerializer : KSerializer<Value> {
ValueType.NUMBER -> encodeDouble(value.double) ValueType.NUMBER -> encodeDouble(value.double)
ValueType.BOOLEAN -> encodeBoolean(value.boolean) ValueType.BOOLEAN -> encodeBoolean(value.boolean)
ValueType.STRING -> encodeString(value.string) ValueType.STRING -> encodeString(value.string)
ValueType.LIST -> encodeSerializableValue(ListSerializer(ValueSerializer),value.list)
} }
} }

View File

@ -4,12 +4,11 @@ package hep.dataforge.values
/** /**
* 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
*/ */
public class LazyParsedValue(override val string: String) : Value { public class LazyParsedValue(public val string: String) : Value {
private val parsedValue by lazy { string.parseValue() } private val parsedValue by lazy { string.parseValue() }
override val value: Any? get() = parsedValue.value override val value: Any? get() = parsedValue.value
override val type: ValueType get() = parsedValue.type override val type: ValueType get() = parsedValue.type
override val number: Number get() = parsedValue.number
override fun toString(): String = string override fun toString(): String = string
@ -24,9 +23,7 @@ public fun String.lazyParseValue(): LazyParsedValue = LazyParsedValue(this)
* A performance optimized version of list value for doubles * A performance optimized version of list value for doubles
*/ */
public class DoubleArrayValue(override val value: DoubleArray) : Value, Iterable<Double> { public class DoubleArrayValue(override val value: DoubleArray) : Value, Iterable<Double> {
override val type: ValueType get() = ValueType.NUMBER override val type: ValueType get() = ValueType.LIST
override val number: Double get() = value.first()
override val string: String get() = value.first().toString()
override val list: List<Value> get() = value.map { NumberValue(it) } override val list: List<Value> get() = value.map { NumberValue(it) }
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {

View File

@ -9,10 +9,9 @@ import hep.dataforge.meta.MetaBuilder
public fun Value.isNull(): Boolean = this == Null public fun Value.isNull(): Boolean = this == Null
/** /**
* Check if value is list. This method checks the type of the value, not the number of the elements. * Check if value is list.
* So it will return `true` for empty lists and lists of one elements.
*/ */
public fun Value.isList(): Boolean = this is Iterable<*> public fun Value.isList(): Boolean = this.type == ValueType.LIST
public val Value.boolean: Boolean public val Value.boolean: Boolean
get() = this == True get() = this == True

View File

@ -19,6 +19,7 @@ class DynamicMetaTest {
d.ob.booleanNode = true d.ob.booleanNode = true
val meta = DynamicMeta(d) val meta = DynamicMeta(d)
println(meta)
assertEquals(true, meta["ob.booleanNode"].boolean) assertEquals(true, meta["ob.booleanNode"].boolean)
assertEquals(2, meta["array"].value?.list?.get(1)?.int) assertEquals(2, meta["array"].value?.list?.get(1)?.int)
assertEquals(4, meta.items.size) assertEquals(4, meta.items.size)

View File

@ -32,5 +32,6 @@ public val ColumnHeader<Value>.textWidth: Int
ValueType.STRING -> 16 ValueType.STRING -> 16
ValueType.BOOLEAN -> 5 ValueType.BOOLEAN -> 5
ValueType.NULL -> 5 ValueType.NULL -> 5
ValueType.LIST -> 32
null -> 16 null -> 16
} }

View File

@ -111,8 +111,8 @@ public class TextTable(
private fun Output.writeValue(value: Value, width: Int, left: Boolean = true) { private fun Output.writeValue(value: Value, width: Int, left: Boolean = true) {
require(width > 5) { "Width could not be less than 5" } require(width > 5) { "Width could not be less than 5" }
val str: String = when (value.type) { val str: String = when (value.type) {
ValueType.NUMBER -> value.number.toString() //TODO apply decimal format ValueType.NUMBER -> value.numberOrNull.toString() //TODO apply decimal format
ValueType.STRING -> value.string.take(width) ValueType.STRING, ValueType.LIST -> value.string.take(width)
ValueType.BOOLEAN -> if (value.boolean) { ValueType.BOOLEAN -> if (value.boolean) {
"true" "true"
} else { } else {

View File

@ -6,6 +6,7 @@ import hep.dataforge.tables.get
import hep.dataforge.tables.row import hep.dataforge.tables.row
import hep.dataforge.values.Value import hep.dataforge.values.Value
import hep.dataforge.values.int import hep.dataforge.values.int
import hep.dataforge.values.string
import kotlinx.coroutines.flow.toList import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.io.ExperimentalIoApi import kotlinx.io.ExperimentalIoApi

View File

@ -16,9 +16,7 @@ import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream import java.util.zip.ZipOutputStream
import kotlin.reflect.KClass import kotlin.reflect.KClass
typealias FileFormatResolver<T> = (Path, Meta) -> IOFormat<T> public typealias FileFormatResolver<T> = (Path, Meta) -> IOFormat<T>
private fun newZFS(path: Path): FileSystem { private fun newZFS(path: Path): FileSystem {
val fsProvider = FileSystemProvider.installedProviders().find { it.scheme == "jar" } val fsProvider = FileSystemProvider.installedProviders().find { it.scheme == "jar" }
@ -84,7 +82,7 @@ public fun <T : Any> DataTreeBuilder<T>.file(
* Read the directory as a data node. If [path] is a zip archive, read it as directory * Read the directory as a data node. If [path] is a zip archive, read it as directory
*/ */
@DFExperimental @DFExperimental
fun <T : Any> IOPlugin.readDataDirectory( public fun <T : Any> IOPlugin.readDataDirectory(
path: Path, path: Path,
type: KClass<out T>, type: KClass<out T>,
formatResolver: FileFormatResolver<T> formatResolver: FileFormatResolver<T>