- 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 {
|
plugins {
|
||||||
kotlin("multiplatform") version "2.0.20"
|
kotlin("multiplatform") version "2.0.21"
|
||||||
kotlin("plugin.serialization") version "2.0.20"
|
kotlin("plugin.serialization") version "2.0.21"
|
||||||
id("org.jetbrains.dokka") version "1.9.20"
|
id("org.jetbrains.dokka") version "1.9.20"
|
||||||
`maven-publish`
|
`maven-publish`
|
||||||
}
|
}
|
||||||
|
|
||||||
val serialization_version = "1.6.5-SNAPSHOT"
|
|
||||||
|
|
||||||
group = "net.sergeych"
|
group = "net.sergeych"
|
||||||
version = "0.1.8-SNAPSHOT"
|
version = "0.1.9-SNAPSHOT"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
@ -24,11 +22,11 @@ kotlin {
|
|||||||
nodejs()
|
nodejs()
|
||||||
}
|
}
|
||||||
|
|
||||||
macosArm64()
|
// macosArm64()
|
||||||
iosX64()
|
// iosX64()
|
||||||
iosArm64()
|
// iosArm64()
|
||||||
macosX64()
|
// macosX64()
|
||||||
iosSimulatorArm64()
|
// iosSimulatorArm64()
|
||||||
linuxX64()
|
linuxX64()
|
||||||
linuxArm64()
|
linuxArm64()
|
||||||
mingwX64()
|
mingwX64()
|
||||||
@ -55,7 +53,7 @@ kotlin {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
|
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
|
// 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,)")
|
api("net.sergeych:mp_stools:[1.4.7,)")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.5.0")
|
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.5.0")
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
package net.sergeych.bintools
|
package net.sergeych.bintools
|
||||||
|
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
import kotlinx.serialization.serializer
|
import kotlinx.serialization.serializer
|
||||||
import net.sergeych.bipack.BipackDecoder
|
import net.sergeych.bipack.BipackDecoder
|
||||||
import net.sergeych.bipack.BipackEncoder
|
import net.sergeych.bipack.BipackEncoder
|
||||||
import kotlin.reflect.KProperty
|
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
|
* Default implementation uses [keys]. You may override it for performance
|
||||||
*/
|
*/
|
||||||
fun clear() {
|
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")
|
@Suppress("unused")
|
||||||
inline fun <reified T:Any>KVStorage.load(key: String): T? = read(key)
|
inline fun <reified T:Any>KVStorage.load(key: String): T? = read(key)
|
||||||
|
|
||||||
inline operator fun <reified T> KVStorage.invoke(defaultValue: T,overrideName: String? = null) =
|
inline operator fun <reified T: Any> KVStorage.invoke(defaultValue: T,overrideName: String? = null) =
|
||||||
KVStorageDelegate<T>(this, typeOf<T>(), defaultValue, overrideName)
|
KVStorageDelegate(this, serializer<T>(), defaultValue, overrideName)
|
||||||
|
|
||||||
inline fun <reified T> KVStorage.stored(defaultValue: T, overrideName: String? = null) =
|
inline fun <reified T: Any> KVStorage.stored(defaultValue: T, overrideName: String? = null) =
|
||||||
KVStorageDelegate<T>(this, typeOf<T>(), defaultValue, overrideName)
|
KVStorageDelegate(this, serializer<T>(), defaultValue, overrideName)
|
||||||
|
|
||||||
inline fun <reified T> KVStorage.optStored(overrideName: String? = null) =
|
inline fun <reified T: Any> KVStorage.optStored(overrideName: String? = null) =
|
||||||
KVStorageDelegate<T?>(this, typeOf<T?>(), null, overrideName)
|
KVStorageOptDelegate<T>(this, serializer<T>(),overrideName)
|
||||||
|
|
||||||
class KVStorageDelegate<T>(
|
class KVStorageDelegate<T: Any>(
|
||||||
private val storage: KVStorage,
|
private val storage: KVStorage,
|
||||||
type: KType,
|
private val serializer: KSerializer<T>,
|
||||||
private val defaultValue: T,
|
private val defaultValue: T,
|
||||||
private val overrideName: String? = null,
|
private val overrideName: String? = null,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private fun name(property: KProperty<*>): String = overrideName ?: property.name
|
private fun name(property: KProperty<*>): String = overrideName ?: property.name
|
||||||
|
|
||||||
private var cachedValue: T = defaultValue
|
operator fun getValue(thisRef: Any?, property: KProperty<*>): T =
|
||||||
private var cacheReady = false
|
storage.get(name(property))?.let { BipackDecoder.decode(serializer, it) }
|
||||||
private val serializer = serializer(type)
|
?: 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) {
|
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
||||||
// if (!cacheReady || value != cachedValue) {
|
storage[name(property)] = BipackEncoder.encode(serializer, value)
|
||||||
cachedValue = value
|
}
|
||||||
cacheReady = true
|
}
|
||||||
|
|
||||||
|
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)
|
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")
|
s2.write("test_$i", "payload_$i")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user