diff --git a/lynglib/build.gradle.kts b/lynglib/build.gradle.kts index 84bdc71..4bc5866 100644 --- a/lynglib/build.gradle.kts +++ b/lynglib/build.gradle.kts @@ -21,7 +21,7 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl import org.jetbrains.kotlin.gradle.dsl.JvmTarget group = "net.sergeych" -version = "1.0.5-SNAPSHOT" +version = "1.0.6-SNAPSHOT" // Removed legacy buildscript classpath declarations; plugins are applied via the plugins DSL below diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstance.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstance.kt index 79ad5df..7db9e99 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstance.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstance.kt @@ -210,8 +210,13 @@ class ObjInstance(override val objClass: ObjClass) : Obj() { // using objlist allow for some optimizations: val params = meta.params.map { readField(scope, it.name).value } + println("serializing $objClass with params: $params") encoder.encodeAnyList(scope, params) - serializeStateVars(scope, encoder) + val vars = serializingVars.values.map { it.value } + println("encoding vars: $vars") + if (vars.isNotEmpty()) { + encoder.encodeAnyList(scope, vars) + } } override suspend fun toJson(scope: Scope): JsonElement { @@ -232,9 +237,9 @@ class ObjInstance(override val objClass: ObjClass) : Obj() { return JsonObject(result) } - val instanceVars: Map by lazy { - instanceScope.objects.filter { it.value.type.serializable } - } +// val instanceVars: Map by lazy { +// instanceScope.objects.filter { it.value.type.serializable } +// } val serializingVars: Map by lazy { instanceScope.objects.filter { @@ -243,18 +248,11 @@ class ObjInstance(override val objClass: ObjClass) : Obj() { it.value.isMutable } } - protected suspend fun serializeStateVars(scope: Scope, encoder: LynonEncoder) { - val vars = instanceVars.values.map { it.value } - if (vars.isNotEmpty()) { - encoder.encodeAnyList(scope, vars) - } - } - internal suspend fun deserializeStateVars(scope: Scope, decoder: LynonDecoder) { - val localVars = instanceVars.values.toList() + val localVars = serializingVars.values.toList() if (localVars.isNotEmpty()) { val vars = decoder.decodeAnyList(scope) - if (vars.size > instanceVars.size) + if (vars.size > serializingVars.size) scope.raiseIllegalArgument("serialized vars has bigger size than instance vars") for ((i, v) in vars.withIndex()) { localVars[i].value = v diff --git a/lynglib/src/commonTest/kotlin/ScriptTest.kt b/lynglib/src/commonTest/kotlin/ScriptTest.kt index 30dcf94..14c5472 100644 --- a/lynglib/src/commonTest/kotlin/ScriptTest.kt +++ b/lynglib/src/commonTest/kotlin/ScriptTest.kt @@ -3815,20 +3815,43 @@ class ScriptTest { assertEquals(JSTest1("bar", 1, true), x.decodeSerializable()) } -// @Test -// fun testInstanceVars() = runTest { -// val x = eval(""" -// class T(x,y) -// T(1, 2) -// """.trimIndent()) as ObjInstance -// println(x.serializingVars.map { "${it.key}=${it.value.value}"}) -// } + @Test + fun testInstanceVars() = runTest { + var x = eval(""" + // in this case, x and y are constructor parameters, not instance variables: + class T(x,y) { + // and z is val and therefore needn't serialization either: + val z = x + y + } + T(1, 2) + """.trimIndent()) as ObjInstance + println(x.serializingVars.map { "${it.key}=${it.value.value}"}) + // so serializingVars is empty: + assertEquals(emptyMap(), x.serializingVars) + + x = eval(""" + class T(x,y) { + // variable z though should be serialized: + var z = x + y + } + val x = T(1, 2) + x.z = 100 + assertEquals(100, x.z) + x + """.trimIndent()) as ObjInstance + // z is instance var, it must present + val z = x.serializingVars["z"] ?: x.serializingVars["T::z"] + // and be mutable: + assertTrue( z!!.isMutable ) + println(x.serializingVars.map { "${it.key}=${it.value.value}"}) + } @Test fun memberValCantBeAssigned() = runTest { eval(""" class Point(foo,bar) { val t = 42 + var r = 142 } val p = Point(1,2) // val should not be assignable: @@ -3837,8 +3860,13 @@ class ScriptTest { // val field must be readonly: assertThrows { p.t = "bad" } + p.r = 123 + // and the value should not be changed assertEqual(42, p.t) + + // but r should be changed: + assertEqual(123, p.r) """) } diff --git a/lynglib/src/jvmTest/kotlin/LynonTests.kt b/lynglib/src/jvmTest/kotlin/LynonTests.kt index 49f263c..89634cb 100644 --- a/lynglib/src/jvmTest/kotlin/LynonTests.kt +++ b/lynglib/src/jvmTest/kotlin/LynonTests.kt @@ -723,6 +723,61 @@ class Wallet( id, ownerKey, balance=0, createdAt=Instant.now().truncateToSecond( assertEquals(cp, cp2) """) } + + @Test + fun testClassSerializationSizes() = runTest { + testScope().eval(""" + class Point(x=0,y=0) + // 1 bit - nonnull + // 4 bits type record + // 8 bits size (5) + // 1 bit uncompressed + // 40 bits "Point" + // 54 total: + assertEquals( 54, Lynon.encode("Point").size ) + assertEquals( 7, Lynon.encode("Point").toBuffer().size ) + + // 1 bit - nonnull + // 4 bits type record + assertEquals( 5, Lynon.encode(0).size ) + + class Empty() + // 1 bit non-null + // 4 bits type record + // 54 bits "Empty" + // 4 bits list size + // dont know where 1 bit for not cached + assertEquals( 64, Lynon.encode(Empty()).size ) + assertEquals( Empty(), Lynon.decode(Lynon.encode(Empty())) ) + + // Here the situation is dofferent: we have 2 in zeroes plus int size, but cache shrinks it + assertEquals( 70, Lynon.encode(Point()).size ) + // two 1's added 16 bit (each short int is 8 bits) + assertEquals( 86, Lynon.encode(Point(1,1)).size ) + assertEquals( 86, Lynon.encode(Point(1,2)).size ) + + // Now let's make it more complex: we add 1 var to save: + class Poin2(x=0,y=0) { + val z = x + y + } + // val must not be serialized so no change here: + assertEquals( 86, Lynon.encode(Poin2(1,2)).size ) + + // lets check size of homogenous list of one small int + // 8 bits 3 + // 4 bits type + // 8 bits list size + // 2 bits not cached and not null + // 4 bits element type + assertEquals( 27, Lynon.encode([3]).size) + + class Poin3(x=0,y=0) { + var z = x + y + } + // var must be serialized, but caching could reduce size: + assert( Lynon.encode(Poin3(1,2)).size <= 110) + """.trimIndent()) + } }