---
source: boltffi_bindgen/src/render/kotlin/templates.rs
assertion_line: 1386
expression: rendered
---
/**
 * ### Thread Safety
 *
 * Callback methods may be invoked from any thread and the thread is not guaranteed to be
 * the same between calls. **Your implementation must be thread-safe.**
 * Use `BoltFFIScope.launchOnMain` if updating UI.
 */
interface AsyncHandler {
    suspend fun onComplete(result: String)
}

private object AsyncHandlerMap {
    private val map = java.util.concurrent.ConcurrentHashMap<Long, AsyncHandler>()
    private val counter = java.util.concurrent.atomic.AtomicLong(1L)

    fun insert(obj: AsyncHandler): Long {
        val handle = counter.getAndAdd(2L)
        map[handle] = obj
        return handle
    }

    fun get(handle: Long): AsyncHandler? = map[handle]

    fun remove(handle: Long): AsyncHandler? = map.remove(handle)

    fun clone(handle: Long): Long {
        val obj = map[handle] ?: return 0L
        return insert(obj)
    }
}

object AsyncHandlerCallbacks {
    private val pendingAsyncCallbacks = java.util.concurrent.ConcurrentHashMap<Long, Long>()

    @JvmStatic
    fun free(handle: Long) {
        AsyncHandlerMap.remove(handle)
    }

    @JvmStatic
    fun clone(handle: Long): Long {
        return AsyncHandlerMap.clone(handle)
    }

    @JvmStatic
    fun on_complete(handle: Long, result: String, callbackPtr: Long, callbackData: Long) {
        try {
            val impl = AsyncHandlerMap.get(handle) ?: throw IllegalStateException("AsyncHandlerMap: invalid handle $handle")
            val resultDecoded = result
            pendingAsyncCallbacks[callbackData] = callbackPtr
            try {
                BoltFFIScope.launch {
                    try {
                        impl.onComplete(resultDecoded)
                        completeOnComplete(callbackData)
                    } catch (t: Throwable) {
                        failOnComplete(callbackData)
                    }
                }
            } catch (t: Throwable) {
                pendingAsyncCallbacks.remove(callbackData)
                Native.invokeOnCompleteFailure(callbackPtr, callbackData)
            }
        } catch (t: Throwable) {
            Native.invokeOnCompleteFailure(callbackPtr, callbackData)
        }
    }

    @JvmStatic
    fun completeOnComplete(callbackData: Long) {
        val callbackPtr = pendingAsyncCallbacks.remove(callbackData) ?: return
        Native.invokeOnComplete(callbackPtr, callbackData)
    }

    @JvmStatic
    fun failOnComplete(callbackData: Long) {
        val callbackPtr = pendingAsyncCallbacks.remove(callbackData) ?: return
        Native.invokeOnCompleteFailure(callbackPtr, callbackData)
    }
}

object AsyncHandlerBridge {
    private val registered = java.util.concurrent.atomic.AtomicBoolean(false)

    fun register() {
        if (!registered.compareAndSet(false, true)) return
    }

    fun create(impl: AsyncHandler): Long {
        register()
        return AsyncHandlerMap.insert(impl)
    }
}
