summaryrefslogtreecommitdiffstats
path: root/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/FfiConverterTemplate.kt
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/FfiConverterTemplate.kt')
-rw-r--r--third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/FfiConverterTemplate.kt71
1 files changed, 71 insertions, 0 deletions
diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/FfiConverterTemplate.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/FfiConverterTemplate.kt
new file mode 100644
index 0000000000..3b2c9d225a
--- /dev/null
+++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/FfiConverterTemplate.kt
@@ -0,0 +1,71 @@
+// The FfiConverter interface handles converter types to and from the FFI
+//
+// All implementing objects should be public to support external types. When a
+// type is external we need to import it's FfiConverter.
+public interface FfiConverter<KotlinType, FfiType> {
+ // Convert an FFI type to a Kotlin type
+ fun lift(value: FfiType): KotlinType
+
+ // Convert an Kotlin type to an FFI type
+ fun lower(value: KotlinType): FfiType
+
+ // Read a Kotlin type from a `ByteBuffer`
+ fun read(buf: ByteBuffer): KotlinType
+
+ // Calculate bytes to allocate when creating a `RustBuffer`
+ //
+ // This must return at least as many bytes as the write() function will
+ // write. It can return more bytes than needed, for example when writing
+ // Strings we can't know the exact bytes needed until we the UTF-8
+ // encoding, so we pessimistically allocate the largest size possible (3
+ // bytes per codepoint). Allocating extra bytes is not really a big deal
+ // because the `RustBuffer` is short-lived.
+ fun allocationSize(value: KotlinType): Int
+
+ // Write a Kotlin type to a `ByteBuffer`
+ fun write(value: KotlinType, buf: ByteBuffer)
+
+ // Lower a value into a `RustBuffer`
+ //
+ // This method lowers a value into a `RustBuffer` rather than the normal
+ // FfiType. It's used by the callback interface code. Callback interface
+ // returns are always serialized into a `RustBuffer` regardless of their
+ // normal FFI type.
+ fun lowerIntoRustBuffer(value: KotlinType): RustBuffer.ByValue {
+ val rbuf = RustBuffer.alloc(allocationSize(value))
+ try {
+ val bbuf = rbuf.data!!.getByteBuffer(0, rbuf.capacity.toLong()).also {
+ it.order(ByteOrder.BIG_ENDIAN)
+ }
+ write(value, bbuf)
+ rbuf.writeField("len", bbuf.position())
+ return rbuf
+ } catch (e: Throwable) {
+ RustBuffer.free(rbuf)
+ throw e
+ }
+ }
+
+ // Lift a value from a `RustBuffer`.
+ //
+ // This here mostly because of the symmetry with `lowerIntoRustBuffer()`.
+ // It's currently only used by the `FfiConverterRustBuffer` class below.
+ fun liftFromRustBuffer(rbuf: RustBuffer.ByValue): KotlinType {
+ val byteBuf = rbuf.asByteBuffer()!!
+ try {
+ val item = read(byteBuf)
+ if (byteBuf.hasRemaining()) {
+ throw RuntimeException("junk remaining in buffer after lifting, something is very wrong!!")
+ }
+ return item
+ } finally {
+ RustBuffer.free(rbuf)
+ }
+ }
+}
+
+// FfiConverter that uses `RustBuffer` as the FfiType
+public interface FfiConverterRustBuffer<KotlinType>: FfiConverter<KotlinType, RustBuffer.ByValue> {
+ override fun lift(value: RustBuffer.ByValue) = liftFromRustBuffer(value)
+ override fun lower(value: KotlinType) = lowerIntoRustBuffer(value)
+}