summaryrefslogtreecommitdiffstats
path: root/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Helpers.kt
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Helpers.kt')
-rw-r--r--third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Helpers.kt152
1 files changed, 55 insertions, 97 deletions
diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Helpers.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Helpers.kt
index 382a5f7413..1fdbd3ffc0 100644
--- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Helpers.kt
+++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Helpers.kt
@@ -1,30 +1,43 @@
// A handful of classes and functions to support the generated data structures.
// This would be a good candidate for isolating in its own ffi-support lib.
-// Error runtime.
+
+internal const val UNIFFI_CALL_SUCCESS = 0.toByte()
+internal const val UNIFFI_CALL_ERROR = 1.toByte()
+internal const val UNIFFI_CALL_UNEXPECTED_ERROR = 2.toByte()
+
@Structure.FieldOrder("code", "error_buf")
-internal open class RustCallStatus : Structure() {
+internal open class UniffiRustCallStatus : Structure() {
@JvmField var code: Byte = 0
@JvmField var error_buf: RustBuffer.ByValue = RustBuffer.ByValue()
- class ByValue: RustCallStatus(), Structure.ByValue
+ class ByValue: UniffiRustCallStatus(), Structure.ByValue
fun isSuccess(): Boolean {
- return code == 0.toByte()
+ return code == UNIFFI_CALL_SUCCESS
}
fun isError(): Boolean {
- return code == 1.toByte()
+ return code == UNIFFI_CALL_ERROR
}
fun isPanic(): Boolean {
- return code == 2.toByte()
+ return code == UNIFFI_CALL_UNEXPECTED_ERROR
+ }
+
+ companion object {
+ fun create(code: Byte, errorBuf: RustBuffer.ByValue): UniffiRustCallStatus.ByValue {
+ val callStatus = UniffiRustCallStatus.ByValue()
+ callStatus.code = code
+ callStatus.error_buf = errorBuf
+ return callStatus
+ }
}
}
class InternalException(message: String) : Exception(message)
// Each top-level error class has a companion object that can lift the error from the call status's rust buffer
-interface CallStatusErrorHandler<E> {
+interface UniffiRustCallStatusErrorHandler<E> {
fun lift(error_buf: RustBuffer.ByValue): E;
}
@@ -33,15 +46,15 @@ interface CallStatusErrorHandler<E> {
// synchronize itself
// Call a rust function that returns a Result<>. Pass in the Error class companion that corresponds to the Err
-private inline fun <U, E: Exception> rustCallWithError(errorHandler: CallStatusErrorHandler<E>, callback: (RustCallStatus) -> U): U {
- var status = RustCallStatus();
+private inline fun <U, E: Exception> uniffiRustCallWithError(errorHandler: UniffiRustCallStatusErrorHandler<E>, callback: (UniffiRustCallStatus) -> U): U {
+ var status = UniffiRustCallStatus();
val return_value = callback(status)
- checkCallStatus(errorHandler, status)
+ uniffiCheckCallStatus(errorHandler, status)
return return_value
}
-// Check RustCallStatus and throw an error if the call wasn't successful
-private fun<E: Exception> checkCallStatus(errorHandler: CallStatusErrorHandler<E>, status: RustCallStatus) {
+// Check UniffiRustCallStatus and throw an error if the call wasn't successful
+private fun<E: Exception> uniffiCheckCallStatus(errorHandler: UniffiRustCallStatusErrorHandler<E>, status: UniffiRustCallStatus) {
if (status.isSuccess()) {
return
} else if (status.isError()) {
@@ -60,8 +73,8 @@ private fun<E: Exception> checkCallStatus(errorHandler: CallStatusErrorHandler<E
}
}
-// CallStatusErrorHandler implementation for times when we don't expect a CALL_ERROR
-object NullCallStatusErrorHandler: CallStatusErrorHandler<InternalException> {
+// UniffiRustCallStatusErrorHandler implementation for times when we don't expect a CALL_ERROR
+object UniffiNullRustCallStatusErrorHandler: UniffiRustCallStatusErrorHandler<InternalException> {
override fun lift(error_buf: RustBuffer.ByValue): InternalException {
RustBuffer.free(error_buf)
return InternalException("Unexpected CALL_ERROR")
@@ -69,93 +82,38 @@ object NullCallStatusErrorHandler: CallStatusErrorHandler<InternalException> {
}
// Call a rust function that returns a plain value
-private inline fun <U> rustCall(callback: (RustCallStatus) -> U): U {
- return rustCallWithError(NullCallStatusErrorHandler, callback);
+private inline fun <U> uniffiRustCall(callback: (UniffiRustCallStatus) -> U): U {
+ return uniffiRustCallWithError(UniffiNullRustCallStatusErrorHandler, callback);
}
-// IntegerType that matches Rust's `usize` / C's `size_t`
-public class USize(value: Long = 0) : IntegerType(Native.SIZE_T_SIZE, value, true) {
- // This is needed to fill in the gaps of IntegerType's implementation of Number for Kotlin.
- override fun toByte() = toInt().toByte()
- // Needed until https://youtrack.jetbrains.com/issue/KT-47902 is fixed.
- @Deprecated("`toInt().toChar()` is deprecated")
- override fun toChar() = toInt().toChar()
- override fun toShort() = toInt().toShort()
-
- fun writeToBuffer(buf: ByteBuffer) {
- // Make sure we always write usize integers using native byte-order, since they may be
- // casted to pointer values
- buf.order(ByteOrder.nativeOrder())
- try {
- when (Native.SIZE_T_SIZE) {
- 4 -> buf.putInt(toInt())
- 8 -> buf.putLong(toLong())
- else -> throw RuntimeException("Invalid SIZE_T_SIZE: ${Native.SIZE_T_SIZE}")
- }
- } finally {
- buf.order(ByteOrder.BIG_ENDIAN)
- }
- }
-
- companion object {
- val size: Int
- get() = Native.SIZE_T_SIZE
-
- fun readFromBuffer(buf: ByteBuffer) : USize {
- // Make sure we always read usize integers using native byte-order, since they may be
- // casted from pointer values
- buf.order(ByteOrder.nativeOrder())
- try {
- return when (Native.SIZE_T_SIZE) {
- 4 -> USize(buf.getInt().toLong())
- 8 -> USize(buf.getLong())
- else -> throw RuntimeException("Invalid SIZE_T_SIZE: ${Native.SIZE_T_SIZE}")
- }
- } finally {
- buf.order(ByteOrder.BIG_ENDIAN)
- }
- }
+internal inline fun<T> uniffiTraitInterfaceCall(
+ callStatus: UniffiRustCallStatus,
+ makeCall: () -> T,
+ writeReturn: (T) -> Unit,
+) {
+ try {
+ writeReturn(makeCall())
+ } catch(e: Exception) {
+ callStatus.code = UNIFFI_CALL_UNEXPECTED_ERROR
+ callStatus.error_buf = {{ Type::String.borrow()|lower_fn }}(e.toString())
}
}
-
-// Map handles to objects
-//
-// This is used when the Rust code expects an opaque pointer to represent some foreign object.
-// Normally we would pass a pointer to the object, but JNA doesn't support getting a pointer from an
-// object reference , nor does it support leaking a reference to Rust.
-//
-// Instead, this class maps USize values to objects so that we can pass a pointer-sized type to
-// Rust when it needs an opaque pointer.
-//
-// TODO: refactor callbacks to use this class
-internal class UniFfiHandleMap<T: Any> {
- private val map = ConcurrentHashMap<USize, T>()
- // Use AtomicInteger for our counter, since we may be on a 32-bit system. 4 billion possible
- // values seems like enough. If somehow we generate 4 billion handles, then this will wrap
- // around back to zero and we can assume the first handle generated will have been dropped by
- // then.
- private val counter = java.util.concurrent.atomic.AtomicInteger(0)
-
- val size: Int
- get() = map.size
-
- fun insert(obj: T): USize {
- val handle = USize(counter.getAndAdd(1).toLong())
- map.put(handle, obj)
- return handle
- }
-
- fun get(handle: USize): T? {
- return map.get(handle)
- }
-
- fun remove(handle: USize): T? {
- return map.remove(handle)
+internal inline fun<T, reified E: Throwable> uniffiTraitInterfaceCallWithError(
+ callStatus: UniffiRustCallStatus,
+ makeCall: () -> T,
+ writeReturn: (T) -> Unit,
+ lowerError: (E) -> RustBuffer.ByValue
+) {
+ try {
+ writeReturn(makeCall())
+ } catch(e: Exception) {
+ if (e is E) {
+ callStatus.code = UNIFFI_CALL_ERROR
+ callStatus.error_buf = lowerError(e)
+ } else {
+ callStatus.code = UNIFFI_CALL_UNEXPECTED_ERROR
+ callStatus.error_buf = {{ Type::String.borrow()|lower_fn }}(e.toString())
+ }
}
}
-
-// FFI type for Rust future continuations
-internal interface UniFffiRustFutureContinuationCallbackType : com.sun.jna.Callback {
- fun callback(continuationHandle: USize, pollResult: Short);
-}