blob: 3544b2f9e6ecc1857b57a56b7d2fabb3f7c93f33 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
{{ self.add_import("kotlinx.coroutines.CoroutineScope") }}
{{ self.add_import("kotlinx.coroutines.delay") }}
{{ self.add_import("kotlinx.coroutines.isActive") }}
{{ self.add_import("kotlinx.coroutines.launch") }}
internal const val UNIFFI_RUST_TASK_CALLBACK_SUCCESS = 0.toByte()
internal const val UNIFFI_RUST_TASK_CALLBACK_CANCELLED = 1.toByte()
internal const val UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS = 0.toByte()
internal const val UNIFFI_FOREIGN_EXECUTOR_CALLBACK_CANCELLED = 1.toByte()
internal const val UNIFFI_FOREIGN_EXECUTOR_CALLBACK_ERROR = 2.toByte()
// Callback function to execute a Rust task. The Kotlin code schedules these in a coroutine then
// invokes them.
internal interface UniFfiRustTaskCallback : com.sun.jna.Callback {
fun callback(rustTaskData: Pointer?, statusCode: Byte)
}
internal object UniFfiForeignExecutorCallback : com.sun.jna.Callback {
fun callback(handle: USize, delayMs: Int, rustTask: UniFfiRustTaskCallback?, rustTaskData: Pointer?) : Byte {
if (rustTask == null) {
FfiConverterForeignExecutor.drop(handle)
return UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS
} else {
val coroutineScope = FfiConverterForeignExecutor.lift(handle)
if (coroutineScope.isActive) {
val job = coroutineScope.launch {
if (delayMs > 0) {
delay(delayMs.toLong())
}
rustTask.callback(rustTaskData, UNIFFI_RUST_TASK_CALLBACK_SUCCESS)
}
job.invokeOnCompletion { cause ->
if (cause != null) {
rustTask.callback(rustTaskData, UNIFFI_RUST_TASK_CALLBACK_CANCELLED)
}
}
return UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS
} else {
return UNIFFI_FOREIGN_EXECUTOR_CALLBACK_CANCELLED
}
}
}
}
public object FfiConverterForeignExecutor: FfiConverter<CoroutineScope, USize> {
internal val handleMap = UniFfiHandleMap<CoroutineScope>()
internal fun drop(handle: USize) {
handleMap.remove(handle)
}
internal fun register(lib: _UniFFILib) {
{%- match ci.ffi_foreign_executor_callback_set() %}
{%- when Some with (fn) %}
lib.{{ fn.name() }}(UniFfiForeignExecutorCallback)
{%- when None %}
{#- No foreign executor, we don't set anything #}
{% endmatch %}
}
// Number of live handles, exposed so we can test the memory management
public fun handleCount() : Int {
return handleMap.size
}
override fun allocationSize(value: CoroutineScope) = USize.size
override fun lift(value: USize): CoroutineScope {
return handleMap.get(value) ?: throw RuntimeException("unknown handle in FfiConverterForeignExecutor.lift")
}
override fun read(buf: ByteBuffer): CoroutineScope {
return lift(USize.readFromBuffer(buf))
}
override fun lower(value: CoroutineScope): USize {
return handleMap.insert(value)
}
override fun write(value: CoroutineScope, buf: ByteBuffer) {
lower(value).writeToBuffer(buf)
}
}
|