Skip to content

Commit

Permalink
Makes ObjectMapper2 interface, make Dynamic2 delegating accessAny to …
Browse files Browse the repository at this point in the history
…it to support change its behaviour (#1433)
  • Loading branch information
soywiz authored Mar 15, 2023
1 parent 7a92355 commit 5ef5689
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 32 deletions.
24 changes: 1 addition & 23 deletions korte/src/commonMain/kotlin/com/soywiz/korte/dynamic/Dynamic2.kt
Original file line number Diff line number Diff line change
Expand Up @@ -153,29 +153,7 @@ object Dynamic2 {
else -> listOf<Any?>()
}

suspend fun accessAny(instance: Any?, key: Any?, mapper: ObjectMapper2): Any? = when (instance) {
null -> null
is Dynamic2Gettable -> instance.dynamic2Get(key)
is Map<*, *> -> instance[key]
is Iterable<*> -> instance.toList()[toInt(key)]
else -> {
val keyStr = DynamicContext { key.toDynamicString() }
when {
mapper.hasProperty(instance, keyStr) -> {
//println("Access dynamic property : $keyStr")
mapper.get(instance, key)
}
mapper.hasMethod(instance, keyStr) -> {
//println("Access dynamic method : $keyStr")
mapper.invokeAsync(instance::class as KClass<Any>, instance as Any?, keyStr, listOf())
}
else -> {
//println("Access dynamic null : '$keyStr'")
null
}
}
}
}
suspend fun accessAny(instance: Any?, key: Any?, mapper: ObjectMapper2): Any? = mapper.accessAny(instance, key)

suspend fun setAny(instance: Any?, key: Any?, value: Any?, mapper: ObjectMapper2): Unit = when (instance) {
null -> Unit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,53 @@ package com.soywiz.korte.dynamic
import kotlin.reflect.KClass

@Suppress("UNCHECKED_CAST")
open class ObjectMapper2 {
interface ObjectMapper2 {
val DynamicType<*>.dynamicShape: DynamicShape<Any?> get() = this.run { DynamicTypeScope.run { this.__dynamicShape as DynamicShape<Any?> } }

open fun hasProperty(instance: Any, key: String): Boolean {
fun hasProperty(instance: Any, key: String): Boolean {
if (instance is DynamicType<*>) return instance.dynamicShape.hasProp(key)
return false
}
open fun hasMethod(instance: Any, key: String): Boolean {
fun hasMethod(instance: Any, key: String): Boolean {
if (instance is DynamicType<*>) return instance.dynamicShape.hasMethod(key)
return false
}
open suspend fun invokeAsync(type: KClass<Any>, instance: Any?, key: String, args: List<Any?>): Any? {
suspend fun invokeAsync(type: KClass<Any>, instance: Any?, key: String, args: List<Any?>): Any? {
if (instance is DynamicType<*>) return instance.dynamicShape.callMethod(instance, key, args)
return null
}
open suspend fun set(instance: Any, key: Any?, value: Any?) {
suspend fun set(instance: Any, key: Any?, value: Any?) {
if (instance is DynamicType<*>) return instance.dynamicShape.setProp(instance, key, value)
}
open suspend fun get(instance: Any, key: Any?): Any? {
suspend fun get(instance: Any, key: Any?): Any? {
if (instance is DynamicType<*>) return instance.dynamicShape.getProp(instance, key)
return null
}
suspend fun accessAny(instance: Any?, key: Any?): Any? = when (instance) {
null -> null
is Dynamic2Gettable -> instance.dynamic2Get(key)
is Map<*, *> -> instance[key]
is Iterable<*> -> instance.toList()[Dynamic2.toInt(key)]
else -> accessAnyObject(instance, key)
}
suspend fun accessAnyObject(instance: Any?, key: Any?): Any? {
if (instance == null) return null
val keyStr = DynamicContext { key.toDynamicString() }
return when {
hasProperty(instance, keyStr) -> {
//println("Access dynamic property : $keyStr")
get(instance, key)
}
hasMethod(instance, keyStr) -> {
//println("Access dynamic method : $keyStr")
invokeAsync(instance::class as KClass<Any>, instance as Any?, keyStr, listOf())
}
else -> {
//println("Access dynamic null : '$keyStr'")
null
}
}
}
}

expect val Mapper2: ObjectMapper2
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
import kotlin.reflect.KClass

open class JsObjectMapper2 : ObjectMapper2() {
open class JsObjectMapper2 : ObjectMapper2 {
override fun hasProperty(instance: Any, key: String): Boolean {
if (instance is DynamicType<*>) return instance.dynamicShape.hasProp(key)
val tof = jsTypeOf(instance.asDynamic()[key])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
import kotlin.reflect.KClass
import kotlin.reflect.KProperty

open class JvmObjectMapper2 : ObjectMapper2() {
open class JvmObjectMapper2 : ObjectMapper2 {
class ClassReflectCache<T : Any>(val clazz: KClass<T>) {
data class MyProperty(
val name: String,
Expand Down
27 changes: 27 additions & 0 deletions korte/src/jvmTest/kotlin/com/soywiz/korte/TemplateJvmTest.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.soywiz.korte

import com.soywiz.korte.dynamic.*
import java.time.LocalDate
import java.time.Month
import kotlin.test.Test
Expand Down Expand Up @@ -49,11 +50,37 @@ class TemplateJvmTest {
fun getB(): Int? = 20
}

@Suppress("unused")
class GetterWithMap : LinkedHashMap<String, Any?>() {
@JvmField var a: Int? = 10
@JvmField var b: Int? = 10
var c: Int? = 10
fun getA(): Int? = null
fun getB(): Int? = 20
}

@Test
fun testGetter() = suspendTest {
assertEquals(
",20,10",
Template("{{ data.a }},{{ data.b }},{{ data.c }}")("data" to Getter())
)
}

@Test
fun testGetterCustomMapper() = suspendTest {
val getter = GetterWithMap().also { it["a"] = "A"; it["b"] = "B" }
assertEquals(
"A,B,",
Template("{{ data.a }},{{ data.b }},{{ data.c }}")("data" to getter)
)
assertEquals(
"A,20,10",
Template("{{ data.a }},{{ data.b }},{{ data.c }}")("data" to getter, mapper = object : ObjectMapper2 by Mapper2 {
override suspend fun accessAny(instance: Any?, key: Any?): Any? {
return super.accessAnyObject(instance, key) ?: super.accessAny(instance, key)
}
})
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.soywiz.korte.dynamic
import kotlin.native.concurrent.SharedImmutable

// @TODO: Hopefully someday: https://github.com/Kotlin/kotlinx.serialization/tree/dev
open class NativeObjectMapper2 : ObjectMapper2() {
open class NativeObjectMapper2 : ObjectMapper2 {
//override fun hasProperty(instance: Any, key: String): Boolean = TODO("Not supported in native yet")
//override fun hasMethod(instance: Any, key: String): Boolean = TODO("Not supported in native yet")
//override suspend fun invokeAsync(type: KClass<Any>, instance: Any?, key: String, args: List<Any?>) = TODO("Not supported in native yet")
Expand Down

0 comments on commit 5ef5689

Please sign in to comment.