diff --git a/CHANGELOG.md b/CHANGELOG.md index ae61e9d9..1fad20ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - More fine-grained types in Action builders. ### Changed +- Meta `get` method allows nullable receiver - `withDefault` functions do not add new keys to meta children and are consistent. - `dataforge.meta.values` package is merged into `dataforge.meta` for better star imports - Kotlin 1.7.20 diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Meta.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Meta.kt index 7d2974b0..52ffea42 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Meta.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Meta.kt @@ -5,6 +5,7 @@ import kotlinx.serialization.json.Json import space.kscience.dataforge.misc.Type import space.kscience.dataforge.misc.unsafeCast import space.kscience.dataforge.names.* +import kotlin.jvm.JvmName /** @@ -94,6 +95,10 @@ public interface Meta : MetaRepr, MetaProvider { public val Meta.isLeaf: Boolean get() = items.isEmpty() +public operator fun Meta?.get(token: NameToken): Meta? = this?.items?.get(token) + +@Deprecated("Use nullable receiver", level = DeprecationLevel.HIDDEN) +@JvmName("getNonNullable") public operator fun Meta.get(token: NameToken): Meta? = items[token] /** @@ -103,11 +108,19 @@ public operator fun Meta.get(token: NameToken): Meta? = items[token] */ public operator fun Meta?.get(name: Name): Meta? = this?.getMeta(name) +@Deprecated("Use nullable receiver", level = DeprecationLevel.HIDDEN) +@JvmName("getNonNullable") +public operator fun Meta.get(name: Name): Meta? = getMeta(name) + /** * Parse [Name] from [key] using full name notation and pass it to [Meta.get] */ public operator fun Meta?.get(key: String): Meta? = this?.get(key.parseAsName(true)) +@Deprecated("Use nullable receiver", level = DeprecationLevel.HIDDEN) +@JvmName("getNonNullable") +public operator fun Meta.get(key: String): Meta? = get(key.parseAsName(true)) + /** * Get all items matching given name. The index of the last element, if present is used as a [Regex], * against which indexes of elements are matched. @@ -162,7 +175,7 @@ public inline val > TypedMeta.self: M get() = unsafeCast() //public typealias Meta = TypedMeta<*> -public operator fun > TypedMeta.get(token: NameToken): M? = items[token] +public operator fun > TypedMeta?.get(token: NameToken): M? = this?.items?.get(token) /** * Perform recursive item search using given [name]. Each [NameToken] is treated as a name in [TypedMeta.items] of a parent node. @@ -175,11 +188,19 @@ public tailrec operator fun > TypedMeta?.get(name: Name): M? else -> get(name.firstOrNull()!!)?.get(name.cutFirst()) } +@Deprecated("Use nullable receiver", level = DeprecationLevel.HIDDEN) +@JvmName("getNonNullable") +public operator fun > TypedMeta.get(name: Name): M? = get(name) + /** * Parse [Name] from [key] using full name notation and pass it to [TypedMeta.get] */ public operator fun > TypedMeta?.get(key: String): M? = this[key.parseAsName(true)] +@Deprecated("Use nullable receiver", level = DeprecationLevel.HIDDEN) +@JvmName("getNonNullable") +public operator fun > TypedMeta.get(key: String): M? = get(key) + /** * Get a sequence of [Name]-[Value] pairs using top-down traversal of the tree diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/names/Name.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/names/Name.kt index 5696ffc2..84eec80e 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/names/Name.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/names/Name.kt @@ -24,14 +24,14 @@ public class Name(public val tokens: List) { } } - override fun hashCode(): Int { - return if (tokens.size == 1) { - tokens.first().hashCode() - } else { - tokens.hashCode() - } + private val cachedHashCode = if (tokens.size == 1) { + tokens.first().hashCode() + } else { + tokens.hashCode() } + override fun hashCode(): Int = cachedHashCode + public companion object { public const val NAME_SEPARATOR: String = "." diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/names/NameToken.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/names/NameToken.kt index f576ad39..2710e42c 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/names/NameToken.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/names/NameToken.kt @@ -9,7 +9,7 @@ import space.kscience.dataforge.misc.DFExperimental * A name token could have appendix in square brackets called *index* */ @Serializable(NameTokenSerializer::class) -public data class NameToken(val body: String, val index: String? = null) { +public class NameToken(public val body: String, public val index: String? = null) { init { if (body.isEmpty()) error("Syntax error: Name token body is empty") @@ -33,6 +33,7 @@ public data class NameToken(val body: String, val index: String? = null) { bodyEscaped } + /** * Return unescaped version of the [NameToken]. Should be used only for output because it is not possible to correctly * parse it back. @@ -43,6 +44,22 @@ public data class NameToken(val body: String, val index: String? = null) { body } + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as NameToken + + if (body != other.body) return false + if (index != other.index) return false + + return true + } + + private val cachedHashCode = body.hashCode() * 31 + (index?.hashCode() ?: 0) + + override fun hashCode(): Int = cachedHashCode + public companion object { private val escapedChars = listOf('\\', '.', '[', ']') diff --git a/dataforge-meta/src/jsMain/kotlin/space/kscience/dataforge/meta/DynamicMeta.kt b/dataforge-meta/src/jsMain/kotlin/space/kscience/dataforge/meta/DynamicMeta.kt index 2f901de4..b38d5891 100644 --- a/dataforge-meta/src/jsMain/kotlin/space/kscience/dataforge/meta/DynamicMeta.kt +++ b/dataforge-meta/src/jsMain/kotlin/space/kscience/dataforge/meta/DynamicMeta.kt @@ -33,7 +33,7 @@ public fun Meta.toDynamic(): dynamic { public class DynamicMeta(internal val obj: dynamic) : TypedMeta { private fun keys(): Array = js("Object").keys(obj) as Array - private fun isArray(@Suppress("UNUSED_PARAMETER") obj: dynamic): Boolean = + private fun isArray(obj: dynamic): Boolean = js("Array").isArray(obj) as Boolean private fun isPrimitive(obj: dynamic): Boolean =