- no caching on stored delegates, fix problens with memory storage connections
+ optStored now properly load/store only non-null values * possible concurrent modification in KVStorage.clear fixed
This commit is contained in:
parent
2eb38e27ed
commit
d29bf960aa
@ -1,14 +1,12 @@
|
||||
plugins {
|
||||
kotlin("multiplatform") version "2.0.20"
|
||||
kotlin("plugin.serialization") version "2.0.20"
|
||||
kotlin("multiplatform") version "2.0.21"
|
||||
kotlin("plugin.serialization") version "2.0.21"
|
||||
id("org.jetbrains.dokka") version "1.9.20"
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
val serialization_version = "1.6.5-SNAPSHOT"
|
||||
|
||||
group = "net.sergeych"
|
||||
version = "0.1.8-SNAPSHOT"
|
||||
version = "0.1.9-SNAPSHOT"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
@ -24,11 +22,11 @@ kotlin {
|
||||
nodejs()
|
||||
}
|
||||
|
||||
macosArm64()
|
||||
iosX64()
|
||||
iosArm64()
|
||||
macosX64()
|
||||
iosSimulatorArm64()
|
||||
// macosArm64()
|
||||
// iosX64()
|
||||
// iosArm64()
|
||||
// macosX64()
|
||||
// iosSimulatorArm64()
|
||||
linuxX64()
|
||||
linuxArm64()
|
||||
mingwX64()
|
||||
@ -55,7 +53,7 @@ kotlin {
|
||||
dependencies {
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
|
||||
// this is actually a bug: we need only the core, but bare core causes strange errors
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
|
||||
api("net.sergeych:mp_stools:[1.4.7,)")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.5.0")
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
package net.sergeych.bintools
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.serializer
|
||||
import net.sergeych.bipack.BipackDecoder
|
||||
import net.sergeych.bipack.BipackEncoder
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
|
||||
/**
|
||||
@ -43,7 +42,7 @@ interface KVStorage {
|
||||
* Default implementation uses [keys]. You may override it for performance
|
||||
*/
|
||||
fun clear() {
|
||||
for (k in keys) this[k] = null
|
||||
for (k in keys.toList()) this[k] = null
|
||||
}
|
||||
|
||||
/**
|
||||
@ -93,46 +92,50 @@ inline fun <reified T:Any>KVStorage.read(key: String): T? =
|
||||
@Suppress("unused")
|
||||
inline fun <reified T:Any>KVStorage.load(key: String): T? = read(key)
|
||||
|
||||
inline operator fun <reified T> KVStorage.invoke(defaultValue: T,overrideName: String? = null) =
|
||||
KVStorageDelegate<T>(this, typeOf<T>(), defaultValue, overrideName)
|
||||
inline operator fun <reified T: Any> KVStorage.invoke(defaultValue: T,overrideName: String? = null) =
|
||||
KVStorageDelegate(this, serializer<T>(), defaultValue, overrideName)
|
||||
|
||||
inline fun <reified T> KVStorage.stored(defaultValue: T, overrideName: String? = null) =
|
||||
KVStorageDelegate<T>(this, typeOf<T>(), defaultValue, overrideName)
|
||||
inline fun <reified T: Any> KVStorage.stored(defaultValue: T, overrideName: String? = null) =
|
||||
KVStorageDelegate(this, serializer<T>(), defaultValue, overrideName)
|
||||
|
||||
inline fun <reified T> KVStorage.optStored(overrideName: String? = null) =
|
||||
KVStorageDelegate<T?>(this, typeOf<T?>(), null, overrideName)
|
||||
inline fun <reified T: Any> KVStorage.optStored(overrideName: String? = null) =
|
||||
KVStorageOptDelegate<T>(this, serializer<T>(),overrideName)
|
||||
|
||||
class KVStorageDelegate<T>(
|
||||
class KVStorageDelegate<T: Any>(
|
||||
private val storage: KVStorage,
|
||||
type: KType,
|
||||
private val serializer: KSerializer<T>,
|
||||
private val defaultValue: T,
|
||||
private val overrideName: String? = null,
|
||||
) {
|
||||
|
||||
private fun name(property: KProperty<*>): String = overrideName ?: property.name
|
||||
|
||||
private var cachedValue: T = defaultValue
|
||||
private var cacheReady = false
|
||||
private val serializer = serializer(type)
|
||||
operator fun getValue(thisRef: Any?, property: KProperty<*>): T =
|
||||
storage.get(name(property))?.let { BipackDecoder.decode(serializer, it) }
|
||||
?: defaultValue
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
||||
if (cacheReady) return cachedValue
|
||||
val data = storage.get(name(property))
|
||||
if (data == null)
|
||||
cachedValue = defaultValue
|
||||
else
|
||||
cachedValue = BipackDecoder.decode(data.toDataSource(), serializer) as T
|
||||
cacheReady = true
|
||||
return cachedValue
|
||||
}
|
||||
|
||||
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
||||
// if (!cacheReady || value != cachedValue) {
|
||||
cachedValue = value
|
||||
cacheReady = true
|
||||
storage[name(property)] = BipackEncoder.encode(serializer, value)
|
||||
}
|
||||
}
|
||||
|
||||
class KVStorageOptDelegate<T: Any>(
|
||||
private val storage: KVStorage,
|
||||
private val serializer: KSerializer<T>,
|
||||
private val overrideName: String? = null,
|
||||
) {
|
||||
private fun name(property: KProperty<*>): String = overrideName ?: property.name
|
||||
|
||||
operator fun getValue(thisRef: Any?, property: KProperty<*>): T? =
|
||||
storage.get(name(property))?.let{
|
||||
BipackDecoder.decode(serializer, it)
|
||||
}
|
||||
|
||||
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
|
||||
if (value == null)
|
||||
storage.delete(name(property))
|
||||
else
|
||||
storage[name(property)] = BipackEncoder.encode(serializer, value)
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
44
src/commonTest/kotlin/bipack/StorageTest.kt
Normal file
44
src/commonTest/kotlin/bipack/StorageTest.kt
Normal file
@ -0,0 +1,44 @@
|
||||
package bipack
|
||||
|
||||
import net.sergeych.bintools.*
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNull
|
||||
|
||||
class StorageTest {
|
||||
@Test
|
||||
fun storageTest3() {
|
||||
val s1 = MemoryKVStorage()
|
||||
val s2 = defaultNamedStorage("test_mp_bintools2")
|
||||
s2.clear()
|
||||
|
||||
s1.write("foo", "bar")
|
||||
s1.write("foo2", "bar2")
|
||||
|
||||
s2.write("foo", "foobar")
|
||||
s2.write("bar", "buzz")
|
||||
s2.write("reason", 42)
|
||||
|
||||
assertEquals("bar", s1.read("foo"))
|
||||
assertEquals("bar2", s1.read("foo2"))
|
||||
assertNull(s1.get("bar"))
|
||||
|
||||
val reason: Int? by s1.optStored()
|
||||
assertNull(s1.get("reason"))
|
||||
assertNull(reason)
|
||||
|
||||
s1.connectToStorage(s2)
|
||||
|
||||
// s1 overwrites s2!
|
||||
assertEquals("bar", s1.read("foo"))
|
||||
|
||||
// don't change
|
||||
assertEquals("bar2", s1.read("foo2"))
|
||||
|
||||
// pull from s1
|
||||
assertEquals("buzz", s1.read("bar"))
|
||||
|
||||
assertEquals(42, s1.read("reason"))
|
||||
assertEquals(42, reason)
|
||||
}
|
||||
}
|
@ -34,5 +34,4 @@ class StorageTest {
|
||||
s2.write("test_$i", "payload_$i")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user