// This is a helper for safely working with byte buffers returned from the Rust code. // A rust-owned buffer is represented by its capacity, its current length, and a // pointer to the underlying data. @Structure.FieldOrder("capacity", "len", "data") open class RustBuffer : Structure() { // Note: `capacity` and `len` are actually `ULong` values, but JVM only supports signed values. // When dealing with these fields, make sure to call `toULong()`. @JvmField var capacity: Long = 0 @JvmField var len: Long = 0 @JvmField var data: Pointer? = null class ByValue: RustBuffer(), Structure.ByValue class ByReference: RustBuffer(), Structure.ByReference internal fun setValue(other: RustBuffer) { capacity = other.capacity len = other.len data = other.data } companion object { internal fun alloc(size: ULong = 0UL) = uniffiRustCall() { status -> // Note: need to convert the size to a `Long` value to make this work with JVM. UniffiLib.INSTANCE.{{ ci.ffi_rustbuffer_alloc().name() }}(size.toLong(), status) }.also { if(it.data == null) { throw RuntimeException("RustBuffer.alloc() returned null data pointer (size=${size})") } } internal fun create(capacity: ULong, len: ULong, data: Pointer?): RustBuffer.ByValue { var buf = RustBuffer.ByValue() buf.capacity = capacity.toLong() buf.len = len.toLong() buf.data = data return buf } internal fun free(buf: RustBuffer.ByValue) = uniffiRustCall() { status -> UniffiLib.INSTANCE.{{ ci.ffi_rustbuffer_free().name() }}(buf, status) } } @Suppress("TooGenericExceptionThrown") fun asByteBuffer() = this.data?.getByteBuffer(0, this.len.toLong())?.also { it.order(ByteOrder.BIG_ENDIAN) } } /** * The equivalent of the `*mut RustBuffer` type. * Required for callbacks taking in an out pointer. * * Size is the sum of all values in the struct. */ class RustBufferByReference : ByReference(16) { /** * Set the pointed-to `RustBuffer` to the given value. */ fun setValue(value: RustBuffer.ByValue) { // NOTE: The offsets are as they are in the C-like struct. val pointer = getPointer() pointer.setLong(0, value.capacity) pointer.setLong(8, value.len) pointer.setPointer(16, value.data) } /** * Get a `RustBuffer.ByValue` from this reference. */ fun getValue(): RustBuffer.ByValue { val pointer = getPointer() val value = RustBuffer.ByValue() value.writeField("capacity", pointer.getLong(0)) value.writeField("len", pointer.getLong(8)) value.writeField("data", pointer.getLong(16)) return value } } // This is a helper for safely passing byte references into the rust code. // It's not actually used at the moment, because there aren't many things that you // can take a direct pointer to in the JVM, and if we're going to copy something // then we might as well copy it into a `RustBuffer`. But it's here for API // completeness. @Structure.FieldOrder("len", "data") open class ForeignBytes : Structure() { @JvmField var len: Int = 0 @JvmField var data: Pointer? = null class ByValue : ForeignBytes(), Structure.ByValue }