[Master-Merge ToDo] Change function and property registration to get rid of `Variant.unwrap`
Closed this issue · 0 comments
chippmann commented
Currently we make heavy use of Variant.unwrap inside the entry generation. This issue aims to remove the need of Variant.unwrap
as it includes a JumpTable and an unsafe cast which is both dangerous and not good for performance (as it's called many times).
An example how the new system will work:
//Entry.kt
fun asDouble(argument: Variant) = argument.asDouble()
fun asString(argument: Variant) = argument.asString()
//Entry.kt
val typeConversionLambdas: Map<String, (Variant) -> Any?> = mapOf(
"double" to ::asDouble,
"string" to ::asString
)
//Entry.kt
inline fun <reified T> getTypeConversionLambda(): (Variant) -> T? {
return when (T::class) {
Double::class -> typeConversionLambdas["double"] as (Variant) -> T?
String::class -> typeConversionLambdas["string"] as (Variant) -> T?
else -> return { null }
}
}
//Entry.kt
@CName("godot_nativescript_init")
fun NativeScriptInit(handle: COpaquePointer) {
Godot.nativescriptInit(handle)
with(ClassRegistry(handle)) {
registerClass("example.TestingClass", "Node", ::TestingClass, false) {
//function(TestingClass::_ready.name, RPCMode.DISABLED, TestingClass::_ready) <-OLD WAY
function(TestingClass::_process.name, RPCMode.DISABLED, TestingClass::_process, listOf(getTypeConversionLambda<Double>())) //NEW WAY
}
}
}
//function.kt
class Function1<T : Object, P0, R>(
val method: T.(P0) -> R,
val list: List<(Variant) -> T?>
) : Function<T, R>(1) {
override fun invoke(instance: T, args: List<Variant>): Variant {
return Variant.wrap(
method(
instance,
list[0].invoke(args[0]) as P0
)
)
}
}
//ClassBuilder
fun <T : Object, P0, R> ClassBuilder<T>.function(methodName: String, rpcMode: RPCMode, body: T.(P0) -> R, argumentConverters: List<(Variant) -> T?>) {
val methodRef = StableRef.create(Function1(body, argumentConverters)).asCPointer()
disposables.add(methodRef)
memScoped {
val attribs = cValue<godot_method_attributes> {
rpc_type = toGodotRpcMode(rpcMode)
}
val instanceMethod = cValue<godot_instance_method> {
method_data = methodRef
this.method = staticCFunction(::invokeMethod)
}
nullSafe(Godot.nativescript.godot_nativescript_register_method)(
nativescriptHandle,
className.cstr.ptr,
methodName.cstr.ptr,
attribs,
instanceMethod
)
}
}
Same applies for property registration.