Skip to content

Commit

Permalink
feat(coroutine): Add LambdaCallable::onDestroy to cancel coroutine wh…
Browse files Browse the repository at this point in the history
…en callable is cancelled
  • Loading branch information
piiertho committed Oct 17, 2024
1 parent 117b671 commit 6cc462b
Show file tree
Hide file tree
Showing 12 changed files with 499 additions and 348 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,14 @@ import com.squareup.kotlinpoet.TypeSpec
import com.squareup.kotlinpoet.TypeVariableName
import com.squareup.kotlinpoet.UNIT
import godot.codegen.services.IAwaitGenerationService
import godot.tools.common.constants.GODOT_OBJECT
import godot.tools.common.constants.*
import godot.tools.common.constants.GodotKotlinJvmTypes.signal
import godot.tools.common.constants.godotCorePackage
import godot.tools.common.constants.godotCoroutinePackage
import godot.tools.common.constants.kotlinCoroutinePackage
import godot.tools.common.constants.kotlinxCoroutinePackage

private val cancellableContinuationClass = ClassName(kotlinxCoroutinePackage, "CancellableContinuation")
private val suspendCancellableCoroutine = MemberName(kotlinxCoroutinePackage, "suspendCancellableCoroutine")
private val connect = MemberName(godotCorePackage, "connectThreadSafe")
private const val connectThreadSafe = "connectThreadSafe"
private val resume = MemberName(kotlinCoroutinePackage, "resume")
private const val cancel = "cancel"

object AwaitGenerationService : IAwaitGenerationService {
override fun generate(maxArgumentCount: Int): FileSpec {
Expand Down Expand Up @@ -120,14 +117,26 @@ object AwaitGenerationService : IAwaitGenerationService {
1 -> lambdaParameters
else -> "SignalArguments$argCount($lambdaParameters)"
}
val lambdaParametersWithType = buildString {
for (i in 0 until argCount) {
if (i != 0) {
append("")
}
append("p$i:·P$i")
}
}

return this
.beginControlFlow("return·%M", suspendCancellableCoroutine)
.addStatement("cont:·%T<%T>·->", cancellableContinuationClass, returnType)
.beginControlFlow("%M(%T.ConnectFlags.CONNECT_ONE_SHOT.id.toInt())", connect, GODOT_OBJECT)
.addStatement("$lambdaParameters·->")
.beginControlFlow("%L(", connectThreadSafe)
.addStatement("$lambdaParametersWithType·->")
.addStatement("cont.%M($resumeParameters)", resume)
.endControlFlow()
.beginControlFlow(".%M", AS_CALLABLE_UTIL_FUNCTION)
.addStatement("cont.%L()", cancel)
.endControlFlow()
.addCode(",·%T.ConnectFlags.CONNECT_ONE_SHOT.id.toInt())", GODOT_OBJECT)
.endControlFlow()
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,7 @@
package godot.codegen.services.impl

import com.squareup.kotlinpoet.ANY
import com.squareup.kotlinpoet.AnnotationSpec
import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.CodeBlock
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.FunSpec
import com.squareup.kotlinpoet.KModifier
import com.squareup.kotlinpoet.LambdaTypeName
import com.squareup.kotlinpoet.MemberName
import com.squareup.kotlinpoet.ParameterSpec
import com.squareup.kotlinpoet.*
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import com.squareup.kotlinpoet.PropertySpec
import com.squareup.kotlinpoet.TypeSpec
import com.squareup.kotlinpoet.TypeVariableName
import godot.codegen.services.ILambdaCallableGenerationService
import godot.codegen.utils.GenericClassNameInfo
import godot.tools.common.constants.GodotFunctions
Expand All @@ -25,21 +13,21 @@ class LambdaCallableGenerationService : ILambdaCallableGenerationService {
override fun generate(maxArgumentCount: Int): FileSpec {
val callableFileSpec = FileSpec.builder(godotCorePackage, "LambdaCallables")

val onDestroyCallLambdaType = LambdaTypeName.get(returnType = UNIT).copy(nullable = true)

for (argCount in 0..maxArgumentCount) {
val ktCallableClassName = ClassName(godotCorePackage, "$KT_CALLABLE_NAME$argCount")
val ktCallableClassName = ClassName(godotCorePackage, "$LAMBDA_CALLABLE_NAME$argCount")
val classBuilder = TypeSpec
.classBuilder(ktCallableClassName)
.superclass(
KT_CALLABLE_CLASS_NAME
LAMBDA_CALLABLE_CLASS_NAME
.parameterizedBy(returnTypeParameter)
)

val argumentRange = 0..<argCount

classBuilder
.addSuperclassConstructorParameter(
VARIANT_TYPE_ARGUMENT_NAME
)
classBuilder.addSuperclassConstructorParameter(VARIANT_TYPE_ARGUMENT_NAME)
classBuilder.addSuperclassConstructorParameter(ON_DESTROY_CALL_ARGUMENT_NAME)

for (index in argumentRange) {
classBuilder.addSuperclassConstructorParameter("p${index}Type")
Expand Down Expand Up @@ -122,6 +110,16 @@ class LambdaCallableGenerationService : ILambdaCallableGenerationService {
)
}

primaryConstructor
.addParameter(
ParameterSpec
.builder(
ON_DESTROY_CALL_ARGUMENT_NAME,
onDestroyCallLambdaType
)
.build()
)

primaryConstructor
.addParameter(
ParameterSpec
Expand Down Expand Up @@ -221,7 +219,7 @@ class LambdaCallableGenerationService : ILambdaCallableGenerationService {
var removedTypeVariables = 0
while (typeVariables.isNotEmpty()) {
val bindReturnType =
ClassName(godotCorePackage, "$KT_CALLABLE_NAME${typeVariableNames.size - typeVariables.size}")
ClassName(godotCorePackage, "$LAMBDA_CALLABLE_NAME${typeVariableNames.size - typeVariables.size}")
classBuilder.addFunction(
FunSpec.builder("bind")
.addParameters(
Expand All @@ -239,6 +237,8 @@ class LambdaCallableGenerationService : ILambdaCallableGenerationService {
append(",·p${index}Type")
}

append("$ON_DESTROY_CALL_ARGUMENT_NAME")

append(")·{·")

for (index in (0..<removedTypeVariables)) {
Expand Down Expand Up @@ -278,23 +278,30 @@ class LambdaCallableGenerationService : ILambdaCallableGenerationService {
.addTypeVariables(typeVariableNames.map { it.copy(reified = true) })
.addTypeVariable(returnTypeParameter.copy(reified = true))
.addModifiers(KModifier.INLINE)
.addParameter(
ParameterSpec
.builder(
FUNCTION_PARAMETER_NAME,
lambdaTypeName
)
.addModifiers(KModifier.NOINLINE)
.build()
.addParameters(
listOf(
ParameterSpec
.builder(
FUNCTION_PARAMETER_NAME,
lambdaTypeName
)
.addModifiers(KModifier.NOINLINE)
.build(),
ParameterSpec
.builder(ON_DESTROY_CALL_ARGUMENT_NAME, onDestroyCallLambdaType)
.addModifiers(KModifier.NOINLINE)
.build()
)
)
.addCode(
CodeBlock.of(
buildString {
append("return·$KT_CALLABLE_NAME$argCount(")
append("return·$LAMBDA_CALLABLE_NAME$argCount(")
append("%M.getOrDefault(%T::class,·%T),·")
for (typeParameter in typeVariableNames) {
append("%M[%T::class]!!,·")
}
append("$ON_DESTROY_CALL_ARGUMENT_NAME")
append(FUNCTION_PARAMETER_NAME)
append(')')
},
Expand All @@ -319,7 +326,14 @@ class LambdaCallableGenerationService : ILambdaCallableGenerationService {
.addTypeVariable(returnTypeParameter.copy(reified = true))
.addModifiers(KModifier.INLINE)
.receiver(lambdaTypeName)
.addCode("return·$CALLABLE_FUNCTION_NAME$argCount(this)")
.addParameter(
ParameterSpec
.builder(ON_DESTROY_CALL_ARGUMENT_NAME, onDestroyCallLambdaType)
.addModifiers(KModifier.NOINLINE)
.defaultValue("null")
.build()
)
.addCode("return·$CALLABLE_FUNCTION_NAME$argCount(this,·$ON_DESTROY_CALL_ARGUMENT_NAME)")
.build()
)
}
Expand Down Expand Up @@ -365,11 +379,12 @@ class LambdaCallableGenerationService : ILambdaCallableGenerationService {
.addCode(
CodeBlock.of(
buildString {
append("return·$KT_CALLABLE_NAME$argCount(")
append("return·$LAMBDA_CALLABLE_NAME$argCount(")
append("%M.getOrDefault(%T.getOrCreateKotlinClass(returnClass),·%T),·")
genericClassNameInfo.toParameterSpecList().forEach {
append("%M[%T.getOrCreateKotlinClass(${it.name}Class)]!!,·")
}
append("null,·")
append(FUNCTION_PARAMETER_NAME)
append(')')
},
Expand Down Expand Up @@ -397,11 +412,12 @@ class LambdaCallableGenerationService : ILambdaCallableGenerationService {

private companion object {
const val FUNCTION_PARAMETER_NAME = "function"
const val KT_CALLABLE_NAME = "LambdaCallable"
const val LAMBDA_CALLABLE_NAME = "LambdaCallable"
const val CALLABLE_FUNCTION_NAME = "callable"
const val JAVA_CREATE_METHOD_NAME = "javaCreate"
const val VARIANT_TYPE_ARGUMENT_NAME = "variantConverter"
val KT_CALLABLE_CLASS_NAME = ClassName(godotCorePackage, KT_CALLABLE_NAME)
const val ON_DESTROY_CALL_ARGUMENT_NAME = "onDestroyCall"
val LAMBDA_CALLABLE_CLASS_NAME = ClassName(godotCorePackage, LAMBDA_CALLABLE_NAME)
val returnTypeParameter = TypeVariableName("R", ANY.copy(nullable = true))

//Java
Expand Down
Loading

0 comments on commit 6cc462b

Please sign in to comment.