// This file was autogenerated by some hot garbage in the `uniffi` crate. // Trust me, you don't want to mess with it! @file:Suppress("NAME_SHADOWING") package uniffi.cdk_ffi // Common helper code. // // Ideally this would live in a separate .kt file where it can be unittested etc // in isolation, and perhaps even published as a re-useable package. // // However, it's important that the details of how this helper code works (e.g. the // way that different builtin types are passed across the FFI) exactly match what's // expected by the Rust code on the other side of the interface. In practice right // now that means coming from the exact some version of `uniffi` that was used to // compile the Rust component. The easiest way to ensure this is to bundle the Kotlin // helpers directly inline like we're doing here. import com.sun.jna.Library import com.sun.jna.IntegerType import com.sun.jna.Native import com.sun.jna.Pointer import com.sun.jna.Structure import com.sun.jna.Callback import com.sun.jna.ptr.* import java.nio.ByteBuffer import java.nio.ByteOrder import java.nio.CharBuffer import java.nio.charset.CodingErrorAction import java.util.concurrent.atomic.AtomicLong import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicBoolean // 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. /** * @suppress */ @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.ffi_cdk_ffi_rustbuffer_alloc(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.ffi_cdk_ffi_rustbuffer_free(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. * * @suppress */ 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") internal open class ForeignBytes : Structure() { @JvmField var len: Int = 0 @JvmField var data: Pointer? = null class ByValue : ForeignBytes(), Structure.ByValue } /** * 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. * * @suppress */ public interface FfiConverter { // 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): ULong // 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).also { it.order(ByteOrder.BIG_ENDIAN) } write(value, bbuf) rbuf.writeField("len", bbuf.position().toLong()) 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 * * @suppress */ public interface FfiConverterRustBuffer: FfiConverter { override fun lift(value: RustBuffer.ByValue) = liftFromRustBuffer(value) override fun lower(value: KotlinType) = lowerIntoRustBuffer(value) } // 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. 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 UniffiRustCallStatus : Structure() { @JvmField var code: Byte = 0 @JvmField var error_buf: RustBuffer.ByValue = RustBuffer.ByValue() class ByValue: UniffiRustCallStatus(), Structure.ByValue fun isSuccess(): Boolean { return code == UNIFFI_CALL_SUCCESS } fun isError(): Boolean { return code == UNIFFI_CALL_ERROR } fun isPanic(): Boolean { 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) : kotlin.Exception(message) /** * Each top-level error class has a companion object that can lift the error from the call status's rust buffer * * @suppress */ interface UniffiRustCallStatusErrorHandler { fun lift(error_buf: RustBuffer.ByValue): E; } // Helpers for calling Rust // In practice we usually need to be synchronized to call this safely, so it doesn't // synchronize itself // Call a rust function that returns a Result<>. Pass in the Error class companion that corresponds to the Err private inline fun uniffiRustCallWithError(errorHandler: UniffiRustCallStatusErrorHandler, callback: (UniffiRustCallStatus) -> U): U { var status = UniffiRustCallStatus() val return_value = callback(status) uniffiCheckCallStatus(errorHandler, status) return return_value } // Check UniffiRustCallStatus and throw an error if the call wasn't successful private fun uniffiCheckCallStatus(errorHandler: UniffiRustCallStatusErrorHandler, status: UniffiRustCallStatus) { if (status.isSuccess()) { return } else if (status.isError()) { throw errorHandler.lift(status.error_buf) } else if (status.isPanic()) { // when the rust code sees a panic, it tries to construct a rustbuffer // with the message. but if that code panics, then it just sends back // an empty buffer. if (status.error_buf.len > 0) { throw InternalException(FfiConverterString.lift(status.error_buf)) } else { throw InternalException("Rust panic") } } else { throw InternalException("Unknown rust call status: $status.code") } } /** * UniffiRustCallStatusErrorHandler implementation for times when we don't expect a CALL_ERROR * * @suppress */ object UniffiNullRustCallStatusErrorHandler: UniffiRustCallStatusErrorHandler { override fun lift(error_buf: RustBuffer.ByValue): InternalException { RustBuffer.free(error_buf) return InternalException("Unexpected CALL_ERROR") } } // Call a rust function that returns a plain value private inline fun uniffiRustCall(callback: (UniffiRustCallStatus) -> U): U { return uniffiRustCallWithError(UniffiNullRustCallStatusErrorHandler, callback) } internal inline fun uniffiTraitInterfaceCall( callStatus: UniffiRustCallStatus, makeCall: () -> T, writeReturn: (T) -> Unit, ) { try { writeReturn(makeCall()) } catch(e: kotlin.Exception) { callStatus.code = UNIFFI_CALL_UNEXPECTED_ERROR callStatus.error_buf = FfiConverterString.lower(e.toString()) } } internal inline fun uniffiTraitInterfaceCallWithError( callStatus: UniffiRustCallStatus, makeCall: () -> T, writeReturn: (T) -> Unit, lowerError: (E) -> RustBuffer.ByValue ) { try { writeReturn(makeCall()) } catch(e: kotlin.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 = FfiConverterString.lower(e.toString()) } } } // Map handles to objects // // This is used pass an opaque 64-bit handle representing a foreign object to the Rust code. internal class UniffiHandleMap { private val map = ConcurrentHashMap() private val counter = java.util.concurrent.atomic.AtomicLong(0) val size: Int get() = map.size // Insert a new object into the handle map and get a handle for it fun insert(obj: T): Long { val handle = counter.getAndAdd(1) map.put(handle, obj) return handle } // Get an object from the handle map fun get(handle: Long): T { return map.get(handle) ?: throw InternalException("UniffiHandleMap.get: Invalid handle") } // Remove an entry from the handlemap and get the Kotlin object back fun remove(handle: Long): T { return map.remove(handle) ?: throw InternalException("UniffiHandleMap: Invalid handle") } } // Contains loading, initialization code, // and the FFI Function declarations in a com.sun.jna.Library. @Synchronized private fun findLibraryName(componentName: String): String { val libOverride = System.getProperty("uniffi.component.$componentName.libraryOverride") if (libOverride != null) { return libOverride } return "cdk_ffi" } private inline fun loadIndirect( componentName: String ): Lib { return Native.load(findLibraryName(componentName), Lib::class.java) } // Define FFI callback types internal interface UniffiRustFutureContinuationCallback : com.sun.jna.Callback { fun callback(`data`: Long,`pollResult`: Byte,) } internal interface UniffiForeignFutureFree : com.sun.jna.Callback { fun callback(`handle`: Long,) } internal interface UniffiCallbackInterfaceFree : com.sun.jna.Callback { fun callback(`handle`: Long,) } @Structure.FieldOrder("handle", "free") internal open class UniffiForeignFuture( @JvmField internal var `handle`: Long = 0.toLong(), @JvmField internal var `free`: UniffiForeignFutureFree? = null, ) : Structure() { class UniffiByValue( `handle`: Long = 0.toLong(), `free`: UniffiForeignFutureFree? = null, ): UniffiForeignFuture(`handle`,`free`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFuture) { `handle` = other.`handle` `free` = other.`free` } } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureStructU8( @JvmField internal var `returnValue`: Byte = 0.toByte(), @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ) : Structure() { class UniffiByValue( `returnValue`: Byte = 0.toByte(), `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ): UniffiForeignFutureStructU8(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureStructU8) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteU8 : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructU8.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureStructI8( @JvmField internal var `returnValue`: Byte = 0.toByte(), @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ) : Structure() { class UniffiByValue( `returnValue`: Byte = 0.toByte(), `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ): UniffiForeignFutureStructI8(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureStructI8) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteI8 : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructI8.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureStructU16( @JvmField internal var `returnValue`: Short = 0.toShort(), @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ) : Structure() { class UniffiByValue( `returnValue`: Short = 0.toShort(), `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ): UniffiForeignFutureStructU16(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureStructU16) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteU16 : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructU16.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureStructI16( @JvmField internal var `returnValue`: Short = 0.toShort(), @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ) : Structure() { class UniffiByValue( `returnValue`: Short = 0.toShort(), `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ): UniffiForeignFutureStructI16(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureStructI16) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteI16 : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructI16.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureStructU32( @JvmField internal var `returnValue`: Int = 0, @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ) : Structure() { class UniffiByValue( `returnValue`: Int = 0, `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ): UniffiForeignFutureStructU32(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureStructU32) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteU32 : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructU32.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureStructI32( @JvmField internal var `returnValue`: Int = 0, @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ) : Structure() { class UniffiByValue( `returnValue`: Int = 0, `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ): UniffiForeignFutureStructI32(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureStructI32) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteI32 : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructI32.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureStructU64( @JvmField internal var `returnValue`: Long = 0.toLong(), @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ) : Structure() { class UniffiByValue( `returnValue`: Long = 0.toLong(), `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ): UniffiForeignFutureStructU64(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureStructU64) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteU64 : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructU64.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureStructI64( @JvmField internal var `returnValue`: Long = 0.toLong(), @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ) : Structure() { class UniffiByValue( `returnValue`: Long = 0.toLong(), `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ): UniffiForeignFutureStructI64(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureStructI64) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteI64 : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructI64.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureStructF32( @JvmField internal var `returnValue`: Float = 0.0f, @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ) : Structure() { class UniffiByValue( `returnValue`: Float = 0.0f, `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ): UniffiForeignFutureStructF32(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureStructF32) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteF32 : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructF32.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureStructF64( @JvmField internal var `returnValue`: Double = 0.0, @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ) : Structure() { class UniffiByValue( `returnValue`: Double = 0.0, `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ): UniffiForeignFutureStructF64(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureStructF64) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteF64 : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructF64.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureStructPointer( @JvmField internal var `returnValue`: Pointer = Pointer.NULL, @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ) : Structure() { class UniffiByValue( `returnValue`: Pointer = Pointer.NULL, `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ): UniffiForeignFutureStructPointer(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureStructPointer) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompletePointer : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructPointer.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureStructRustBuffer( @JvmField internal var `returnValue`: RustBuffer.ByValue = RustBuffer.ByValue(), @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ) : Structure() { class UniffiByValue( `returnValue`: RustBuffer.ByValue = RustBuffer.ByValue(), `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ): UniffiForeignFutureStructRustBuffer(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureStructRustBuffer) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteRustBuffer : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructRustBuffer.UniffiByValue,) } @Structure.FieldOrder("callStatus") internal open class UniffiForeignFutureStructVoid( @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ) : Structure() { class UniffiByValue( `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ): UniffiForeignFutureStructVoid(`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureStructVoid) { `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteVoid : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructVoid.UniffiByValue,) } // A JNA Library to expose the extern-C FFI definitions. // This is an implementation detail which will be called internally by the public API. internal interface UniffiLib : Library { companion object { internal val INSTANCE: UniffiLib by lazy { loadIndirect(componentName = "cdk_ffi") .also { lib: UniffiLib -> uniffiCheckContractApiVersion(lib) uniffiCheckApiChecksums(lib) } } // The Cleaner for the whole library internal val CLEANER: UniffiCleaner by lazy { UniffiCleaner.create() } } fun uniffi_cdk_ffi_fn_clone_ffilocalstore(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, ): Pointer fun uniffi_cdk_ffi_fn_free_ffilocalstore(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, ): Unit fun uniffi_cdk_ffi_fn_constructor_ffilocalstore_new(uniffi_out_err: UniffiRustCallStatus, ): Pointer fun uniffi_cdk_ffi_fn_constructor_ffilocalstore_new_with_path(`dbPath`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Pointer fun uniffi_cdk_ffi_fn_clone_ffiwallet(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, ): Pointer fun uniffi_cdk_ffi_fn_free_ffiwallet(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, ): Unit fun uniffi_cdk_ffi_fn_constructor_ffiwallet_from_mnemonic(`mintUrl`: RustBuffer.ByValue,`unit`: RustBuffer.ByValue,`localstore`: Pointer,`mnemonicWords`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Pointer fun uniffi_cdk_ffi_fn_constructor_ffiwallet_restore_from_mnemonic(`mintUrl`: RustBuffer.ByValue,`unit`: RustBuffer.ByValue,`localstore`: Pointer,`mnemonicWords`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Pointer fun uniffi_cdk_ffi_fn_method_ffiwallet_balance(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue fun uniffi_cdk_ffi_fn_method_ffiwallet_get_mint_info(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue fun uniffi_cdk_ffi_fn_method_ffiwallet_melt(`ptr`: Pointer,`quoteId`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue fun uniffi_cdk_ffi_fn_method_ffiwallet_melt_quote(`ptr`: Pointer,`request`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue fun uniffi_cdk_ffi_fn_method_ffiwallet_mint(`ptr`: Pointer,`quoteId`: RustBuffer.ByValue,`splitTarget`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue fun uniffi_cdk_ffi_fn_method_ffiwallet_mint_quote(`ptr`: Pointer,`amount`: RustBuffer.ByValue,`description`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue fun uniffi_cdk_ffi_fn_method_ffiwallet_mint_quote_state(`ptr`: Pointer,`quoteId`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue fun uniffi_cdk_ffi_fn_method_ffiwallet_mint_url(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue fun uniffi_cdk_ffi_fn_method_ffiwallet_prepare_send(`ptr`: Pointer,`amount`: RustBuffer.ByValue,`options`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue fun uniffi_cdk_ffi_fn_method_ffiwallet_receive(`ptr`: Pointer,`token`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue fun uniffi_cdk_ffi_fn_method_ffiwallet_send(`ptr`: Pointer,`amount`: RustBuffer.ByValue,`options`: RustBuffer.ByValue,`memo`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue fun uniffi_cdk_ffi_fn_method_ffiwallet_unit(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue fun uniffi_cdk_ffi_fn_func_generate_mnemonic(uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue fun ffi_cdk_ffi_rustbuffer_alloc(`size`: Long,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue fun ffi_cdk_ffi_rustbuffer_from_bytes(`bytes`: ForeignBytes.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue fun ffi_cdk_ffi_rustbuffer_free(`buf`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Unit fun ffi_cdk_ffi_rustbuffer_reserve(`buf`: RustBuffer.ByValue,`additional`: Long,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue fun ffi_cdk_ffi_rust_future_poll_u8(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit fun ffi_cdk_ffi_rust_future_cancel_u8(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_free_u8(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_complete_u8(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Byte fun ffi_cdk_ffi_rust_future_poll_i8(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit fun ffi_cdk_ffi_rust_future_cancel_i8(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_free_i8(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_complete_i8(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Byte fun ffi_cdk_ffi_rust_future_poll_u16(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit fun ffi_cdk_ffi_rust_future_cancel_u16(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_free_u16(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_complete_u16(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Short fun ffi_cdk_ffi_rust_future_poll_i16(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit fun ffi_cdk_ffi_rust_future_cancel_i16(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_free_i16(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_complete_i16(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Short fun ffi_cdk_ffi_rust_future_poll_u32(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit fun ffi_cdk_ffi_rust_future_cancel_u32(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_free_u32(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_complete_u32(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Int fun ffi_cdk_ffi_rust_future_poll_i32(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit fun ffi_cdk_ffi_rust_future_cancel_i32(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_free_i32(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_complete_i32(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Int fun ffi_cdk_ffi_rust_future_poll_u64(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit fun ffi_cdk_ffi_rust_future_cancel_u64(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_free_u64(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_complete_u64(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Long fun ffi_cdk_ffi_rust_future_poll_i64(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit fun ffi_cdk_ffi_rust_future_cancel_i64(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_free_i64(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_complete_i64(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Long fun ffi_cdk_ffi_rust_future_poll_f32(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit fun ffi_cdk_ffi_rust_future_cancel_f32(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_free_f32(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_complete_f32(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Float fun ffi_cdk_ffi_rust_future_poll_f64(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit fun ffi_cdk_ffi_rust_future_cancel_f64(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_free_f64(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_complete_f64(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Double fun ffi_cdk_ffi_rust_future_poll_pointer(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit fun ffi_cdk_ffi_rust_future_cancel_pointer(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_free_pointer(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_complete_pointer(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Pointer fun ffi_cdk_ffi_rust_future_poll_rust_buffer(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit fun ffi_cdk_ffi_rust_future_cancel_rust_buffer(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_free_rust_buffer(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_complete_rust_buffer(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue fun ffi_cdk_ffi_rust_future_poll_void(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit fun ffi_cdk_ffi_rust_future_cancel_void(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_free_void(`handle`: Long, ): Unit fun ffi_cdk_ffi_rust_future_complete_void(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Unit fun uniffi_cdk_ffi_checksum_func_generate_mnemonic( ): Short fun uniffi_cdk_ffi_checksum_method_ffiwallet_balance( ): Short fun uniffi_cdk_ffi_checksum_method_ffiwallet_get_mint_info( ): Short fun uniffi_cdk_ffi_checksum_method_ffiwallet_melt( ): Short fun uniffi_cdk_ffi_checksum_method_ffiwallet_melt_quote( ): Short fun uniffi_cdk_ffi_checksum_method_ffiwallet_mint( ): Short fun uniffi_cdk_ffi_checksum_method_ffiwallet_mint_quote( ): Short fun uniffi_cdk_ffi_checksum_method_ffiwallet_mint_quote_state( ): Short fun uniffi_cdk_ffi_checksum_method_ffiwallet_mint_url( ): Short fun uniffi_cdk_ffi_checksum_method_ffiwallet_prepare_send( ): Short fun uniffi_cdk_ffi_checksum_method_ffiwallet_receive( ): Short fun uniffi_cdk_ffi_checksum_method_ffiwallet_send( ): Short fun uniffi_cdk_ffi_checksum_method_ffiwallet_unit( ): Short fun uniffi_cdk_ffi_checksum_constructor_ffilocalstore_new( ): Short fun uniffi_cdk_ffi_checksum_constructor_ffilocalstore_new_with_path( ): Short fun uniffi_cdk_ffi_checksum_constructor_ffiwallet_from_mnemonic( ): Short fun uniffi_cdk_ffi_checksum_constructor_ffiwallet_restore_from_mnemonic( ): Short fun ffi_cdk_ffi_uniffi_contract_version( ): Int } private fun uniffiCheckContractApiVersion(lib: UniffiLib) { // Get the bindings contract version from our ComponentInterface val bindings_contract_version = 26 // Get the scaffolding contract version by calling the into the dylib val scaffolding_contract_version = lib.ffi_cdk_ffi_uniffi_contract_version() if (bindings_contract_version != scaffolding_contract_version) { throw RuntimeException("UniFFI contract version mismatch: try cleaning and rebuilding your project") } } @Suppress("UNUSED_PARAMETER") private fun uniffiCheckApiChecksums(lib: UniffiLib) { if (lib.uniffi_cdk_ffi_checksum_func_generate_mnemonic() != 44815.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_cdk_ffi_checksum_method_ffiwallet_balance() != 40463.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_cdk_ffi_checksum_method_ffiwallet_get_mint_info() != 13159.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_cdk_ffi_checksum_method_ffiwallet_melt() != 3275.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_cdk_ffi_checksum_method_ffiwallet_melt_quote() != 39876.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_cdk_ffi_checksum_method_ffiwallet_mint() != 58480.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_cdk_ffi_checksum_method_ffiwallet_mint_quote() != 42885.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_cdk_ffi_checksum_method_ffiwallet_mint_quote_state() != 60165.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_cdk_ffi_checksum_method_ffiwallet_mint_url() != 18647.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_cdk_ffi_checksum_method_ffiwallet_prepare_send() != 46706.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_cdk_ffi_checksum_method_ffiwallet_receive() != 57605.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_cdk_ffi_checksum_method_ffiwallet_send() != 15473.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_cdk_ffi_checksum_method_ffiwallet_unit() != 4593.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_cdk_ffi_checksum_constructor_ffilocalstore_new() != 15364.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_cdk_ffi_checksum_constructor_ffilocalstore_new_with_path() != 766.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_cdk_ffi_checksum_constructor_ffiwallet_from_mnemonic() != 63545.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_cdk_ffi_checksum_constructor_ffiwallet_restore_from_mnemonic() != 38466.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } } // Async support // Public interface members begin here. // Interface implemented by anything that can contain an object reference. // // Such types expose a `destroy()` method that must be called to cleanly // dispose of the contained objects. Failure to call this method may result // in memory leaks. // // The easiest way to ensure this method is called is to use the `.use` // helper method to execute a block and destroy the object at the end. interface Disposable { fun destroy() companion object { fun destroy(vararg args: Any?) { args.filterIsInstance() .forEach(Disposable::destroy) } } } /** * @suppress */ inline fun T.use(block: (T) -> R) = try { block(this) } finally { try { // N.B. our implementation is on the nullable type `Disposable?`. this?.destroy() } catch (e: Throwable) { // swallow } } /** * Used to instantiate an interface without an actual pointer, for fakes in tests, mostly. * * @suppress * */ object NoPointer /** * @suppress */ public object FfiConverterULong: FfiConverter { override fun lift(value: Long): ULong { return value.toULong() } override fun read(buf: ByteBuffer): ULong { return lift(buf.getLong()) } override fun lower(value: ULong): Long { return value.toLong() } override fun allocationSize(value: ULong) = 8UL override fun write(value: ULong, buf: ByteBuffer) { buf.putLong(value.toLong()) } } /** * @suppress */ public object FfiConverterBoolean: FfiConverter { override fun lift(value: Byte): Boolean { return value.toInt() != 0 } override fun read(buf: ByteBuffer): Boolean { return lift(buf.get()) } override fun lower(value: Boolean): Byte { return if (value) 1.toByte() else 0.toByte() } override fun allocationSize(value: Boolean) = 1UL override fun write(value: Boolean, buf: ByteBuffer) { buf.put(lower(value)) } } /** * @suppress */ public object FfiConverterString: FfiConverter { // Note: we don't inherit from FfiConverterRustBuffer, because we use a // special encoding when lowering/lifting. We can use `RustBuffer.len` to // store our length and avoid writing it out to the buffer. override fun lift(value: RustBuffer.ByValue): String { try { val byteArr = ByteArray(value.len.toInt()) value.asByteBuffer()!!.get(byteArr) return byteArr.toString(Charsets.UTF_8) } finally { RustBuffer.free(value) } } override fun read(buf: ByteBuffer): String { val len = buf.getInt() val byteArr = ByteArray(len) buf.get(byteArr) return byteArr.toString(Charsets.UTF_8) } fun toUtf8(value: String): ByteBuffer { // Make sure we don't have invalid UTF-16, check for lone surrogates. return Charsets.UTF_8.newEncoder().run { onMalformedInput(CodingErrorAction.REPORT) encode(CharBuffer.wrap(value)) } } override fun lower(value: String): RustBuffer.ByValue { val byteBuf = toUtf8(value) // Ideally we'd pass these bytes to `ffi_bytebuffer_from_bytes`, but doing so would require us // to copy them into a JNA `Memory`. So we might as well directly copy them into a `RustBuffer`. val rbuf = RustBuffer.alloc(byteBuf.limit().toULong()) rbuf.asByteBuffer()!!.put(byteBuf) return rbuf } // We aren't sure exactly how many bytes our string will be once it's UTF-8 // encoded. Allocate 3 bytes per UTF-16 code unit which will always be // enough. override fun allocationSize(value: String): ULong { val sizeForLength = 4UL val sizeForString = value.length.toULong() * 3UL return sizeForLength + sizeForString } override fun write(value: String, buf: ByteBuffer) { val byteBuf = toUtf8(value) buf.putInt(byteBuf.limit()) buf.put(byteBuf) } } // This template implements a class for working with a Rust struct via a Pointer/Arc // to the live Rust struct on the other side of the FFI. // // Each instance implements core operations for working with the Rust `Arc` and the // Kotlin Pointer to work with the live Rust struct on the other side of the FFI. // // There's some subtlety here, because we have to be careful not to operate on a Rust // struct after it has been dropped, and because we must expose a public API for freeing // theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: // // * Each instance holds an opaque pointer to the underlying Rust struct. // Method calls need to read this pointer from the object's state and pass it in to // the Rust FFI. // // * When an instance is no longer needed, its pointer should be passed to a // special destructor function provided by the Rust FFI, which will drop the // underlying Rust struct. // // * Given an instance, calling code is expected to call the special // `destroy` method in order to free it after use, either by calling it explicitly // or by using a higher-level helper like the `use` method. Failing to do so risks // leaking the underlying Rust struct. // // * We can't assume that calling code will do the right thing, and must be prepared // to handle Kotlin method calls executing concurrently with or even after a call to // `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. // // * We must never allow Rust code to operate on the underlying Rust struct after // the destructor has been called, and must never call the destructor more than once. // Doing so may trigger memory unsafety. // // * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` // is implemented to call the destructor when the Kotlin object becomes unreachable. // This is done in a background thread. This is not a panacea, and client code should be aware that // 1. the thread may starve if some there are objects that have poorly performing // `drop` methods or do significant work in their `drop` methods. // 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, // or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). // // If we try to implement this with mutual exclusion on access to the pointer, there is the // possibility of a race between a method call and a concurrent call to `destroy`: // // * Thread A starts a method call, reads the value of the pointer, but is interrupted // before it can pass the pointer over the FFI to Rust. // * Thread B calls `destroy` and frees the underlying Rust struct. // * Thread A resumes, passing the already-read pointer value to Rust and triggering // a use-after-free. // // One possible solution would be to use a `ReadWriteLock`, with each method call taking // a read lock (and thus allowed to run concurrently) and the special `destroy` method // taking a write lock (and thus blocking on live method calls). However, we aim not to // generate methods with any hidden blocking semantics, and a `destroy` method that might // block if called incorrectly seems to meet that bar. // // So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track // the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` // has been called. These are updated according to the following rules: // // * The initial value of the counter is 1, indicating a live object with no in-flight calls. // The initial value for the flag is false. // // * At the start of each method call, we atomically check the counter. // If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. // If it is nonzero them we atomically increment it by 1 and proceed with the method call. // // * At the end of each method call, we atomically decrement and check the counter. // If it has reached zero then we destroy the underlying Rust struct. // // * When `destroy` is called, we atomically flip the flag from false to true. // If the flag was already true we silently fail. // Otherwise we atomically decrement and check the counter. // If it has reached zero then we destroy the underlying Rust struct. // // Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, // and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. // // The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been // called *and* all in-flight method calls have completed, avoiding violating any of the expectations // of the underlying Rust code. // // This makes a cleaner a better alternative to _not_ calling `destroy()` as // and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` // method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner // thread may be starved, and the app will leak memory. // // In this case, `destroy`ing manually may be a better solution. // // The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects // with Rust peers are reclaimed: // // 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: // 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: // 3. The memory is reclaimed when the process terminates. // // [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 // /** * The cleaner interface for Object finalization code to run. * This is the entry point to any implementation that we're using. * * The cleaner registers objects and returns cleanables, so now we are * defining a `UniffiCleaner` with a `UniffiClenaer.Cleanable` to abstract the * different implmentations available at compile time. * * @suppress */ interface UniffiCleaner { interface Cleanable { fun clean() } fun register(value: Any, cleanUpTask: Runnable): UniffiCleaner.Cleanable companion object } // The fallback Jna cleaner, which is available for both Android, and the JVM. private class UniffiJnaCleaner : UniffiCleaner { private val cleaner = com.sun.jna.internal.Cleaner.getCleaner() override fun register(value: Any, cleanUpTask: Runnable): UniffiCleaner.Cleanable = UniffiJnaCleanable(cleaner.register(value, cleanUpTask)) } private class UniffiJnaCleanable( private val cleanable: com.sun.jna.internal.Cleaner.Cleanable, ) : UniffiCleaner.Cleanable { override fun clean() = cleanable.clean() } // We decide at uniffi binding generation time whether we were // using Android or not. // There are further runtime checks to chose the correct implementation // of the cleaner. private fun UniffiCleaner.Companion.create(): UniffiCleaner = try { // For safety's sake: if the library hasn't been run in android_cleaner = true // mode, but is being run on Android, then we still need to think about // Android API versions. // So we check if java.lang.ref.Cleaner is there, and use that… java.lang.Class.forName("java.lang.ref.Cleaner") JavaLangRefCleaner() } catch (e: ClassNotFoundException) { // … otherwise, fallback to the JNA cleaner. UniffiJnaCleaner() } private class JavaLangRefCleaner : UniffiCleaner { val cleaner = java.lang.ref.Cleaner.create() override fun register(value: Any, cleanUpTask: Runnable): UniffiCleaner.Cleanable = JavaLangRefCleanable(cleaner.register(value, cleanUpTask)) } private class JavaLangRefCleanable( val cleanable: java.lang.ref.Cleaner.Cleanable ) : UniffiCleaner.Cleanable { override fun clean() = cleanable.clean() } public interface FfiLocalStoreInterface { companion object } open class FfiLocalStore: Disposable, AutoCloseable, FfiLocalStoreInterface { constructor(pointer: Pointer) { this.pointer = pointer this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(pointer)) } /** * This constructor can be used to instantiate a fake object. Only used for tests. Any * attempt to actually use an object constructed this way will fail as there is no * connected Rust object. */ @Suppress("UNUSED_PARAMETER") constructor(noPointer: NoPointer) { this.pointer = null this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(pointer)) } constructor() : this( uniffiRustCallWithError(FfiException) { _status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_constructor_ffilocalstore_new( _status) } ) protected val pointer: Pointer? protected val cleanable: UniffiCleaner.Cleanable private val wasDestroyed = AtomicBoolean(false) private val callCounter = AtomicLong(1) override fun destroy() { // Only allow a single call to this method. // TODO: maybe we should log a warning if called more than once? if (this.wasDestroyed.compareAndSet(false, true)) { // This decrement always matches the initial count of 1 given at creation time. if (this.callCounter.decrementAndGet() == 0L) { cleanable.clean() } } } @Synchronized override fun close() { this.destroy() } internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { // Check and increment the call counter, to keep the object alive. // This needs a compare-and-set retry loop in case of concurrent updates. do { val c = this.callCounter.get() if (c == 0L) { throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") } if (c == Long.MAX_VALUE) { throw IllegalStateException("${this.javaClass.simpleName} call counter would overflow") } } while (! this.callCounter.compareAndSet(c, c + 1L)) // Now we can safely do the method call without the pointer being freed concurrently. try { return block(this.uniffiClonePointer()) } finally { // This decrement always matches the increment we performed above. if (this.callCounter.decrementAndGet() == 0L) { cleanable.clean() } } } // Use a static inner class instead of a closure so as not to accidentally // capture `this` as part of the cleanable's action. private class UniffiCleanAction(private val pointer: Pointer?) : Runnable { override fun run() { pointer?.let { ptr -> uniffiRustCall { status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_free_ffilocalstore(ptr, status) } } } } fun uniffiClonePointer(): Pointer { return uniffiRustCall() { status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_clone_ffilocalstore(pointer!!, status) } } companion object { @Throws(FfiException::class) fun `newWithPath`(`dbPath`: kotlin.String?): FfiLocalStore { return FfiConverterTypeFFILocalStore.lift( uniffiRustCallWithError(FfiException) { _status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_constructor_ffilocalstore_new_with_path( FfiConverterOptionalString.lower(`dbPath`),_status) } ) } } } /** * @suppress */ public object FfiConverterTypeFFILocalStore: FfiConverter { override fun lower(value: FfiLocalStore): Pointer { return value.uniffiClonePointer() } override fun lift(value: Pointer): FfiLocalStore { return FfiLocalStore(value) } override fun read(buf: ByteBuffer): FfiLocalStore { // The Rust code always writes pointers as 8 bytes, and will // fail to compile if they don't fit. return lift(Pointer(buf.getLong())) } override fun allocationSize(value: FfiLocalStore) = 8UL override fun write(value: FfiLocalStore, buf: ByteBuffer) { // The Rust code always expects pointers written as 8 bytes, // and will fail to compile if they don't fit. buf.putLong(Pointer.nativeValue(lower(value))) } } // This template implements a class for working with a Rust struct via a Pointer/Arc // to the live Rust struct on the other side of the FFI. // // Each instance implements core operations for working with the Rust `Arc` and the // Kotlin Pointer to work with the live Rust struct on the other side of the FFI. // // There's some subtlety here, because we have to be careful not to operate on a Rust // struct after it has been dropped, and because we must expose a public API for freeing // theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: // // * Each instance holds an opaque pointer to the underlying Rust struct. // Method calls need to read this pointer from the object's state and pass it in to // the Rust FFI. // // * When an instance is no longer needed, its pointer should be passed to a // special destructor function provided by the Rust FFI, which will drop the // underlying Rust struct. // // * Given an instance, calling code is expected to call the special // `destroy` method in order to free it after use, either by calling it explicitly // or by using a higher-level helper like the `use` method. Failing to do so risks // leaking the underlying Rust struct. // // * We can't assume that calling code will do the right thing, and must be prepared // to handle Kotlin method calls executing concurrently with or even after a call to // `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. // // * We must never allow Rust code to operate on the underlying Rust struct after // the destructor has been called, and must never call the destructor more than once. // Doing so may trigger memory unsafety. // // * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` // is implemented to call the destructor when the Kotlin object becomes unreachable. // This is done in a background thread. This is not a panacea, and client code should be aware that // 1. the thread may starve if some there are objects that have poorly performing // `drop` methods or do significant work in their `drop` methods. // 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, // or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). // // If we try to implement this with mutual exclusion on access to the pointer, there is the // possibility of a race between a method call and a concurrent call to `destroy`: // // * Thread A starts a method call, reads the value of the pointer, but is interrupted // before it can pass the pointer over the FFI to Rust. // * Thread B calls `destroy` and frees the underlying Rust struct. // * Thread A resumes, passing the already-read pointer value to Rust and triggering // a use-after-free. // // One possible solution would be to use a `ReadWriteLock`, with each method call taking // a read lock (and thus allowed to run concurrently) and the special `destroy` method // taking a write lock (and thus blocking on live method calls). However, we aim not to // generate methods with any hidden blocking semantics, and a `destroy` method that might // block if called incorrectly seems to meet that bar. // // So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track // the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` // has been called. These are updated according to the following rules: // // * The initial value of the counter is 1, indicating a live object with no in-flight calls. // The initial value for the flag is false. // // * At the start of each method call, we atomically check the counter. // If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. // If it is nonzero them we atomically increment it by 1 and proceed with the method call. // // * At the end of each method call, we atomically decrement and check the counter. // If it has reached zero then we destroy the underlying Rust struct. // // * When `destroy` is called, we atomically flip the flag from false to true. // If the flag was already true we silently fail. // Otherwise we atomically decrement and check the counter. // If it has reached zero then we destroy the underlying Rust struct. // // Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, // and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. // // The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been // called *and* all in-flight method calls have completed, avoiding violating any of the expectations // of the underlying Rust code. // // This makes a cleaner a better alternative to _not_ calling `destroy()` as // and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` // method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner // thread may be starved, and the app will leak memory. // // In this case, `destroy`ing manually may be a better solution. // // The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects // with Rust peers are reclaimed: // // 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: // 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: // 3. The memory is reclaimed when the process terminates. // // [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 // public interface FfiWalletInterface { fun `balance`(): FfiAmount /** * Fetch and initialize mint information * This should be called after wallet creation to set up the mint in the database */ fun `getMintInfo`(): kotlin.String /** * Execute a melt operation (pay Lightning invoice) */ fun `melt`(`quoteId`: kotlin.String): FfiMelted /** * Create a melt quote for paying a Lightning invoice */ fun `meltQuote`(`request`: kotlin.String): FfiMeltQuote fun `mint`(`quoteId`: kotlin.String, `splitTarget`: FfiSplitTarget): FfiAmount fun `mintQuote`(`amount`: FfiAmount, `description`: kotlin.String?): FfiMintQuote fun `mintQuoteState`(`quoteId`: kotlin.String): FfiMintQuoteBolt11Response fun `mintUrl`(): kotlin.String fun `prepareSend`(`amount`: FfiAmount, `options`: FfiSendOptions): FfiPreparedSend /** * Receive token */ fun `receive`(`token`: kotlin.String): FfiAmount fun `send`(`amount`: FfiAmount, `options`: FfiSendOptions, `memo`: FfiSendMemo?): FfiToken fun `unit`(): kotlin.String companion object } open class FfiWallet: Disposable, AutoCloseable, FfiWalletInterface { constructor(pointer: Pointer) { this.pointer = pointer this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(pointer)) } /** * This constructor can be used to instantiate a fake object. Only used for tests. Any * attempt to actually use an object constructed this way will fail as there is no * connected Rust object. */ @Suppress("UNUSED_PARAMETER") constructor(noPointer: NoPointer) { this.pointer = null this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(pointer)) } protected val pointer: Pointer? protected val cleanable: UniffiCleaner.Cleanable private val wasDestroyed = AtomicBoolean(false) private val callCounter = AtomicLong(1) override fun destroy() { // Only allow a single call to this method. // TODO: maybe we should log a warning if called more than once? if (this.wasDestroyed.compareAndSet(false, true)) { // This decrement always matches the initial count of 1 given at creation time. if (this.callCounter.decrementAndGet() == 0L) { cleanable.clean() } } } @Synchronized override fun close() { this.destroy() } internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { // Check and increment the call counter, to keep the object alive. // This needs a compare-and-set retry loop in case of concurrent updates. do { val c = this.callCounter.get() if (c == 0L) { throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") } if (c == Long.MAX_VALUE) { throw IllegalStateException("${this.javaClass.simpleName} call counter would overflow") } } while (! this.callCounter.compareAndSet(c, c + 1L)) // Now we can safely do the method call without the pointer being freed concurrently. try { return block(this.uniffiClonePointer()) } finally { // This decrement always matches the increment we performed above. if (this.callCounter.decrementAndGet() == 0L) { cleanable.clean() } } } // Use a static inner class instead of a closure so as not to accidentally // capture `this` as part of the cleanable's action. private class UniffiCleanAction(private val pointer: Pointer?) : Runnable { override fun run() { pointer?.let { ptr -> uniffiRustCall { status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_free_ffiwallet(ptr, status) } } } } fun uniffiClonePointer(): Pointer { return uniffiRustCall() { status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_clone_ffiwallet(pointer!!, status) } } @Throws(FfiException::class)override fun `balance`(): FfiAmount { return FfiConverterTypeFFIAmount.lift( callWithPointer { uniffiRustCallWithError(FfiException) { _status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_method_ffiwallet_balance( it, _status) } } ) } /** * Fetch and initialize mint information * This should be called after wallet creation to set up the mint in the database */ @Throws(FfiException::class)override fun `getMintInfo`(): kotlin.String { return FfiConverterString.lift( callWithPointer { uniffiRustCallWithError(FfiException) { _status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_method_ffiwallet_get_mint_info( it, _status) } } ) } /** * Execute a melt operation (pay Lightning invoice) */ @Throws(FfiException::class)override fun `melt`(`quoteId`: kotlin.String): FfiMelted { return FfiConverterTypeFFIMelted.lift( callWithPointer { uniffiRustCallWithError(FfiException) { _status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_method_ffiwallet_melt( it, FfiConverterString.lower(`quoteId`),_status) } } ) } /** * Create a melt quote for paying a Lightning invoice */ @Throws(FfiException::class)override fun `meltQuote`(`request`: kotlin.String): FfiMeltQuote { return FfiConverterTypeFFIMeltQuote.lift( callWithPointer { uniffiRustCallWithError(FfiException) { _status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_method_ffiwallet_melt_quote( it, FfiConverterString.lower(`request`),_status) } } ) } @Throws(FfiException::class)override fun `mint`(`quoteId`: kotlin.String, `splitTarget`: FfiSplitTarget): FfiAmount { return FfiConverterTypeFFIAmount.lift( callWithPointer { uniffiRustCallWithError(FfiException) { _status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_method_ffiwallet_mint( it, FfiConverterString.lower(`quoteId`),FfiConverterTypeFFISplitTarget.lower(`splitTarget`),_status) } } ) } @Throws(FfiException::class)override fun `mintQuote`(`amount`: FfiAmount, `description`: kotlin.String?): FfiMintQuote { return FfiConverterTypeFFIMintQuote.lift( callWithPointer { uniffiRustCallWithError(FfiException) { _status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_method_ffiwallet_mint_quote( it, FfiConverterTypeFFIAmount.lower(`amount`),FfiConverterOptionalString.lower(`description`),_status) } } ) } @Throws(FfiException::class)override fun `mintQuoteState`(`quoteId`: kotlin.String): FfiMintQuoteBolt11Response { return FfiConverterTypeFFIMintQuoteBolt11Response.lift( callWithPointer { uniffiRustCallWithError(FfiException) { _status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_method_ffiwallet_mint_quote_state( it, FfiConverterString.lower(`quoteId`),_status) } } ) } override fun `mintUrl`(): kotlin.String { return FfiConverterString.lift( callWithPointer { uniffiRustCall() { _status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_method_ffiwallet_mint_url( it, _status) } } ) } @Throws(FfiException::class)override fun `prepareSend`(`amount`: FfiAmount, `options`: FfiSendOptions): FfiPreparedSend { return FfiConverterTypeFFIPreparedSend.lift( callWithPointer { uniffiRustCallWithError(FfiException) { _status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_method_ffiwallet_prepare_send( it, FfiConverterTypeFFIAmount.lower(`amount`),FfiConverterTypeFFISendOptions.lower(`options`),_status) } } ) } /** * Receive token */ @Throws(FfiException::class)override fun `receive`(`token`: kotlin.String): FfiAmount { return FfiConverterTypeFFIAmount.lift( callWithPointer { uniffiRustCallWithError(FfiException) { _status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_method_ffiwallet_receive( it, FfiConverterString.lower(`token`),_status) } } ) } @Throws(FfiException::class)override fun `send`(`amount`: FfiAmount, `options`: FfiSendOptions, `memo`: FfiSendMemo?): FfiToken { return FfiConverterTypeFFIToken.lift( callWithPointer { uniffiRustCallWithError(FfiException) { _status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_method_ffiwallet_send( it, FfiConverterTypeFFIAmount.lower(`amount`),FfiConverterTypeFFISendOptions.lower(`options`),FfiConverterOptionalTypeFFISendMemo.lower(`memo`),_status) } } ) } override fun `unit`(): kotlin.String { return FfiConverterString.lift( callWithPointer { uniffiRustCall() { _status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_method_ffiwallet_unit( it, _status) } } ) } companion object { @Throws(FfiException::class) fun `fromMnemonic`(`mintUrl`: kotlin.String, `unit`: FfiCurrencyUnit, `localstore`: FfiLocalStore, `mnemonicWords`: kotlin.String): FfiWallet { return FfiConverterTypeFFIWallet.lift( uniffiRustCallWithError(FfiException) { _status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_constructor_ffiwallet_from_mnemonic( FfiConverterString.lower(`mintUrl`),FfiConverterTypeFFICurrencyUnit.lower(`unit`),FfiConverterTypeFFILocalStore.lower(`localstore`),FfiConverterString.lower(`mnemonicWords`),_status) } ) } @Throws(FfiException::class) fun `restoreFromMnemonic`(`mintUrl`: kotlin.String, `unit`: FfiCurrencyUnit, `localstore`: FfiLocalStore, `mnemonicWords`: kotlin.String): FfiWallet { return FfiConverterTypeFFIWallet.lift( uniffiRustCallWithError(FfiException) { _status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_constructor_ffiwallet_restore_from_mnemonic( FfiConverterString.lower(`mintUrl`),FfiConverterTypeFFICurrencyUnit.lower(`unit`),FfiConverterTypeFFILocalStore.lower(`localstore`),FfiConverterString.lower(`mnemonicWords`),_status) } ) } } } /** * @suppress */ public object FfiConverterTypeFFIWallet: FfiConverter { override fun lower(value: FfiWallet): Pointer { return value.uniffiClonePointer() } override fun lift(value: Pointer): FfiWallet { return FfiWallet(value) } override fun read(buf: ByteBuffer): FfiWallet { // The Rust code always writes pointers as 8 bytes, and will // fail to compile if they don't fit. return lift(Pointer(buf.getLong())) } override fun allocationSize(value: FfiWallet) = 8UL override fun write(value: FfiWallet, buf: ByteBuffer) { // The Rust code always expects pointers written as 8 bytes, // and will fail to compile if they don't fit. buf.putLong(Pointer.nativeValue(lower(value))) } } data class FfiAmount ( var `value`: kotlin.ULong ) { companion object } /** * @suppress */ public object FfiConverterTypeFFIAmount: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): FfiAmount { return FfiAmount( FfiConverterULong.read(buf), ) } override fun allocationSize(value: FfiAmount) = ( FfiConverterULong.allocationSize(value.`value`) ) override fun write(value: FfiAmount, buf: ByteBuffer) { FfiConverterULong.write(value.`value`, buf) } } data class FfiMeltQuote ( var `id`: kotlin.String, var `unit`: kotlin.String, var `amount`: FfiAmount, var `request`: kotlin.String, var `feeReserve`: FfiAmount, var `expiry`: kotlin.ULong, var `paymentPreimage`: kotlin.String? ) { companion object } /** * @suppress */ public object FfiConverterTypeFFIMeltQuote: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): FfiMeltQuote { return FfiMeltQuote( FfiConverterString.read(buf), FfiConverterString.read(buf), FfiConverterTypeFFIAmount.read(buf), FfiConverterString.read(buf), FfiConverterTypeFFIAmount.read(buf), FfiConverterULong.read(buf), FfiConverterOptionalString.read(buf), ) } override fun allocationSize(value: FfiMeltQuote) = ( FfiConverterString.allocationSize(value.`id`) + FfiConverterString.allocationSize(value.`unit`) + FfiConverterTypeFFIAmount.allocationSize(value.`amount`) + FfiConverterString.allocationSize(value.`request`) + FfiConverterTypeFFIAmount.allocationSize(value.`feeReserve`) + FfiConverterULong.allocationSize(value.`expiry`) + FfiConverterOptionalString.allocationSize(value.`paymentPreimage`) ) override fun write(value: FfiMeltQuote, buf: ByteBuffer) { FfiConverterString.write(value.`id`, buf) FfiConverterString.write(value.`unit`, buf) FfiConverterTypeFFIAmount.write(value.`amount`, buf) FfiConverterString.write(value.`request`, buf) FfiConverterTypeFFIAmount.write(value.`feeReserve`, buf) FfiConverterULong.write(value.`expiry`, buf) FfiConverterOptionalString.write(value.`paymentPreimage`, buf) } } data class FfiMelted ( var `state`: kotlin.String, var `preimage`: kotlin.String?, var `amount`: FfiAmount, var `feePaid`: FfiAmount ) { companion object } /** * @suppress */ public object FfiConverterTypeFFIMelted: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): FfiMelted { return FfiMelted( FfiConverterString.read(buf), FfiConverterOptionalString.read(buf), FfiConverterTypeFFIAmount.read(buf), FfiConverterTypeFFIAmount.read(buf), ) } override fun allocationSize(value: FfiMelted) = ( FfiConverterString.allocationSize(value.`state`) + FfiConverterOptionalString.allocationSize(value.`preimage`) + FfiConverterTypeFFIAmount.allocationSize(value.`amount`) + FfiConverterTypeFFIAmount.allocationSize(value.`feePaid`) ) override fun write(value: FfiMelted, buf: ByteBuffer) { FfiConverterString.write(value.`state`, buf) FfiConverterOptionalString.write(value.`preimage`, buf) FfiConverterTypeFFIAmount.write(value.`amount`, buf) FfiConverterTypeFFIAmount.write(value.`feePaid`, buf) } } data class FfiMintQuote ( var `id`: kotlin.String, var `mintUrl`: kotlin.String, var `amount`: FfiAmount, var `unit`: kotlin.String, var `request`: kotlin.String, var `state`: FfiMintQuoteState, var `expiry`: kotlin.ULong ) { companion object } /** * @suppress */ public object FfiConverterTypeFFIMintQuote: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): FfiMintQuote { return FfiMintQuote( FfiConverterString.read(buf), FfiConverterString.read(buf), FfiConverterTypeFFIAmount.read(buf), FfiConverterString.read(buf), FfiConverterString.read(buf), FfiConverterTypeFFIMintQuoteState.read(buf), FfiConverterULong.read(buf), ) } override fun allocationSize(value: FfiMintQuote) = ( FfiConverterString.allocationSize(value.`id`) + FfiConverterString.allocationSize(value.`mintUrl`) + FfiConverterTypeFFIAmount.allocationSize(value.`amount`) + FfiConverterString.allocationSize(value.`unit`) + FfiConverterString.allocationSize(value.`request`) + FfiConverterTypeFFIMintQuoteState.allocationSize(value.`state`) + FfiConverterULong.allocationSize(value.`expiry`) ) override fun write(value: FfiMintQuote, buf: ByteBuffer) { FfiConverterString.write(value.`id`, buf) FfiConverterString.write(value.`mintUrl`, buf) FfiConverterTypeFFIAmount.write(value.`amount`, buf) FfiConverterString.write(value.`unit`, buf) FfiConverterString.write(value.`request`, buf) FfiConverterTypeFFIMintQuoteState.write(value.`state`, buf) FfiConverterULong.write(value.`expiry`, buf) } } data class FfiMintQuoteBolt11Response ( var `quote`: kotlin.String, var `request`: kotlin.String, var `state`: FfiMintQuoteState, var `expiry`: kotlin.ULong? ) { companion object } /** * @suppress */ public object FfiConverterTypeFFIMintQuoteBolt11Response: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): FfiMintQuoteBolt11Response { return FfiMintQuoteBolt11Response( FfiConverterString.read(buf), FfiConverterString.read(buf), FfiConverterTypeFFIMintQuoteState.read(buf), FfiConverterOptionalULong.read(buf), ) } override fun allocationSize(value: FfiMintQuoteBolt11Response) = ( FfiConverterString.allocationSize(value.`quote`) + FfiConverterString.allocationSize(value.`request`) + FfiConverterTypeFFIMintQuoteState.allocationSize(value.`state`) + FfiConverterOptionalULong.allocationSize(value.`expiry`) ) override fun write(value: FfiMintQuoteBolt11Response, buf: ByteBuffer) { FfiConverterString.write(value.`quote`, buf) FfiConverterString.write(value.`request`, buf) FfiConverterTypeFFIMintQuoteState.write(value.`state`, buf) FfiConverterOptionalULong.write(value.`expiry`, buf) } } data class FfiPreparedSend ( var `amount`: FfiAmount, var `swapFee`: FfiAmount, var `sendFee`: FfiAmount, var `totalFee`: FfiAmount ) { companion object } /** * @suppress */ public object FfiConverterTypeFFIPreparedSend: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): FfiPreparedSend { return FfiPreparedSend( FfiConverterTypeFFIAmount.read(buf), FfiConverterTypeFFIAmount.read(buf), FfiConverterTypeFFIAmount.read(buf), FfiConverterTypeFFIAmount.read(buf), ) } override fun allocationSize(value: FfiPreparedSend) = ( FfiConverterTypeFFIAmount.allocationSize(value.`amount`) + FfiConverterTypeFFIAmount.allocationSize(value.`swapFee`) + FfiConverterTypeFFIAmount.allocationSize(value.`sendFee`) + FfiConverterTypeFFIAmount.allocationSize(value.`totalFee`) ) override fun write(value: FfiPreparedSend, buf: ByteBuffer) { FfiConverterTypeFFIAmount.write(value.`amount`, buf) FfiConverterTypeFFIAmount.write(value.`swapFee`, buf) FfiConverterTypeFFIAmount.write(value.`sendFee`, buf) FfiConverterTypeFFIAmount.write(value.`totalFee`, buf) } } data class FfiSendMemo ( var `memo`: kotlin.String, var `includeMemo`: kotlin.Boolean ) { companion object } /** * @suppress */ public object FfiConverterTypeFFISendMemo: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): FfiSendMemo { return FfiSendMemo( FfiConverterString.read(buf), FfiConverterBoolean.read(buf), ) } override fun allocationSize(value: FfiSendMemo) = ( FfiConverterString.allocationSize(value.`memo`) + FfiConverterBoolean.allocationSize(value.`includeMemo`) ) override fun write(value: FfiSendMemo, buf: ByteBuffer) { FfiConverterString.write(value.`memo`, buf) FfiConverterBoolean.write(value.`includeMemo`, buf) } } data class FfiSendOptions ( var `memo`: FfiSendMemo?, var `amountSplitTarget`: FfiSplitTarget, var `sendKind`: FfiSendKind, var `includeFee`: kotlin.Boolean, var `metadata`: Map, var `maxProofs`: kotlin.ULong? ) { companion object } /** * @suppress */ public object FfiConverterTypeFFISendOptions: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): FfiSendOptions { return FfiSendOptions( FfiConverterOptionalTypeFFISendMemo.read(buf), FfiConverterTypeFFISplitTarget.read(buf), FfiConverterTypeFFISendKind.read(buf), FfiConverterBoolean.read(buf), FfiConverterMapStringString.read(buf), FfiConverterOptionalULong.read(buf), ) } override fun allocationSize(value: FfiSendOptions) = ( FfiConverterOptionalTypeFFISendMemo.allocationSize(value.`memo`) + FfiConverterTypeFFISplitTarget.allocationSize(value.`amountSplitTarget`) + FfiConverterTypeFFISendKind.allocationSize(value.`sendKind`) + FfiConverterBoolean.allocationSize(value.`includeFee`) + FfiConverterMapStringString.allocationSize(value.`metadata`) + FfiConverterOptionalULong.allocationSize(value.`maxProofs`) ) override fun write(value: FfiSendOptions, buf: ByteBuffer) { FfiConverterOptionalTypeFFISendMemo.write(value.`memo`, buf) FfiConverterTypeFFISplitTarget.write(value.`amountSplitTarget`, buf) FfiConverterTypeFFISendKind.write(value.`sendKind`, buf) FfiConverterBoolean.write(value.`includeFee`, buf) FfiConverterMapStringString.write(value.`metadata`, buf) FfiConverterOptionalULong.write(value.`maxProofs`, buf) } } data class FfiToken ( var `tokenString`: kotlin.String, var `mint`: kotlin.String, var `memo`: kotlin.String?, var `unit`: kotlin.String ) { companion object } /** * @suppress */ public object FfiConverterTypeFFIToken: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): FfiToken { return FfiToken( FfiConverterString.read(buf), FfiConverterString.read(buf), FfiConverterOptionalString.read(buf), FfiConverterString.read(buf), ) } override fun allocationSize(value: FfiToken) = ( FfiConverterString.allocationSize(value.`tokenString`) + FfiConverterString.allocationSize(value.`mint`) + FfiConverterOptionalString.allocationSize(value.`memo`) + FfiConverterString.allocationSize(value.`unit`) ) override fun write(value: FfiToken, buf: ByteBuffer) { FfiConverterString.write(value.`tokenString`, buf) FfiConverterString.write(value.`mint`, buf) FfiConverterOptionalString.write(value.`memo`, buf) FfiConverterString.write(value.`unit`, buf) } } enum class FfiCurrencyUnit { SAT, MSAT, USD, EUR; companion object } /** * @suppress */ public object FfiConverterTypeFFICurrencyUnit: FfiConverterRustBuffer { override fun read(buf: ByteBuffer) = try { FfiCurrencyUnit.values()[buf.getInt() - 1] } catch (e: IndexOutOfBoundsException) { throw RuntimeException("invalid enum value, something is very wrong!!", e) } override fun allocationSize(value: FfiCurrencyUnit) = 4UL override fun write(value: FfiCurrencyUnit, buf: ByteBuffer) { buf.putInt(value.ordinal + 1) } } sealed class FfiException: kotlin.Exception() { class WalletException( val `msg`: kotlin.String ) : FfiException() { override val message get() = "msg=${ `msg` }" } class InvalidInput( val `msg`: kotlin.String ) : FfiException() { override val message get() = "msg=${ `msg` }" } class NetworkException( val `msg`: kotlin.String ) : FfiException() { override val message get() = "msg=${ `msg` }" } class InternalException( val `msg`: kotlin.String ) : FfiException() { override val message get() = "msg=${ `msg` }" } companion object ErrorHandler : UniffiRustCallStatusErrorHandler { override fun lift(error_buf: RustBuffer.ByValue): FfiException = FfiConverterTypeFFIError.lift(error_buf) } } /** * @suppress */ public object FfiConverterTypeFFIError : FfiConverterRustBuffer { override fun read(buf: ByteBuffer): FfiException { return when(buf.getInt()) { 1 -> FfiException.WalletException( FfiConverterString.read(buf), ) 2 -> FfiException.InvalidInput( FfiConverterString.read(buf), ) 3 -> FfiException.NetworkException( FfiConverterString.read(buf), ) 4 -> FfiException.InternalException( FfiConverterString.read(buf), ) else -> throw RuntimeException("invalid error enum value, something is very wrong!!") } } override fun allocationSize(value: FfiException): ULong { return when(value) { is FfiException.WalletException -> ( // Add the size for the Int that specifies the variant plus the size needed for all fields 4UL + FfiConverterString.allocationSize(value.`msg`) ) is FfiException.InvalidInput -> ( // Add the size for the Int that specifies the variant plus the size needed for all fields 4UL + FfiConverterString.allocationSize(value.`msg`) ) is FfiException.NetworkException -> ( // Add the size for the Int that specifies the variant plus the size needed for all fields 4UL + FfiConverterString.allocationSize(value.`msg`) ) is FfiException.InternalException -> ( // Add the size for the Int that specifies the variant plus the size needed for all fields 4UL + FfiConverterString.allocationSize(value.`msg`) ) } } override fun write(value: FfiException, buf: ByteBuffer) { when(value) { is FfiException.WalletException -> { buf.putInt(1) FfiConverterString.write(value.`msg`, buf) Unit } is FfiException.InvalidInput -> { buf.putInt(2) FfiConverterString.write(value.`msg`, buf) Unit } is FfiException.NetworkException -> { buf.putInt(3) FfiConverterString.write(value.`msg`, buf) Unit } is FfiException.InternalException -> { buf.putInt(4) FfiConverterString.write(value.`msg`, buf) Unit } }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } } enum class FfiMintQuoteState { UNPAID, PAID, ISSUED; companion object } /** * @suppress */ public object FfiConverterTypeFFIMintQuoteState: FfiConverterRustBuffer { override fun read(buf: ByteBuffer) = try { FfiMintQuoteState.values()[buf.getInt() - 1] } catch (e: IndexOutOfBoundsException) { throw RuntimeException("invalid enum value, something is very wrong!!", e) } override fun allocationSize(value: FfiMintQuoteState) = 4UL override fun write(value: FfiMintQuoteState, buf: ByteBuffer) { buf.putInt(value.ordinal + 1) } } sealed class FfiSendKind { object OnlineExact : FfiSendKind() data class OnlineTolerance( val `tolerance`: FfiAmount) : FfiSendKind() { companion object } object OfflineExact : FfiSendKind() data class OfflineTolerance( val `tolerance`: FfiAmount) : FfiSendKind() { companion object } companion object } /** * @suppress */ public object FfiConverterTypeFFISendKind : FfiConverterRustBuffer{ override fun read(buf: ByteBuffer): FfiSendKind { return when(buf.getInt()) { 1 -> FfiSendKind.OnlineExact 2 -> FfiSendKind.OnlineTolerance( FfiConverterTypeFFIAmount.read(buf), ) 3 -> FfiSendKind.OfflineExact 4 -> FfiSendKind.OfflineTolerance( FfiConverterTypeFFIAmount.read(buf), ) else -> throw RuntimeException("invalid enum value, something is very wrong!!") } } override fun allocationSize(value: FfiSendKind) = when(value) { is FfiSendKind.OnlineExact -> { // Add the size for the Int that specifies the variant plus the size needed for all fields ( 4UL ) } is FfiSendKind.OnlineTolerance -> { // Add the size for the Int that specifies the variant plus the size needed for all fields ( 4UL + FfiConverterTypeFFIAmount.allocationSize(value.`tolerance`) ) } is FfiSendKind.OfflineExact -> { // Add the size for the Int that specifies the variant plus the size needed for all fields ( 4UL ) } is FfiSendKind.OfflineTolerance -> { // Add the size for the Int that specifies the variant plus the size needed for all fields ( 4UL + FfiConverterTypeFFIAmount.allocationSize(value.`tolerance`) ) } } override fun write(value: FfiSendKind, buf: ByteBuffer) { when(value) { is FfiSendKind.OnlineExact -> { buf.putInt(1) Unit } is FfiSendKind.OnlineTolerance -> { buf.putInt(2) FfiConverterTypeFFIAmount.write(value.`tolerance`, buf) Unit } is FfiSendKind.OfflineExact -> { buf.putInt(3) Unit } is FfiSendKind.OfflineTolerance -> { buf.putInt(4) FfiConverterTypeFFIAmount.write(value.`tolerance`, buf) Unit } }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } } enum class FfiSplitTarget { NONE, DEFAULT; companion object } /** * @suppress */ public object FfiConverterTypeFFISplitTarget: FfiConverterRustBuffer { override fun read(buf: ByteBuffer) = try { FfiSplitTarget.values()[buf.getInt() - 1] } catch (e: IndexOutOfBoundsException) { throw RuntimeException("invalid enum value, something is very wrong!!", e) } override fun allocationSize(value: FfiSplitTarget) = 4UL override fun write(value: FfiSplitTarget, buf: ByteBuffer) { buf.putInt(value.ordinal + 1) } } /** * @suppress */ public object FfiConverterOptionalULong: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): kotlin.ULong? { if (buf.get().toInt() == 0) { return null } return FfiConverterULong.read(buf) } override fun allocationSize(value: kotlin.ULong?): ULong { if (value == null) { return 1UL } else { return 1UL + FfiConverterULong.allocationSize(value) } } override fun write(value: kotlin.ULong?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) FfiConverterULong.write(value, buf) } } } /** * @suppress */ public object FfiConverterOptionalString: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): kotlin.String? { if (buf.get().toInt() == 0) { return null } return FfiConverterString.read(buf) } override fun allocationSize(value: kotlin.String?): ULong { if (value == null) { return 1UL } else { return 1UL + FfiConverterString.allocationSize(value) } } override fun write(value: kotlin.String?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) FfiConverterString.write(value, buf) } } } /** * @suppress */ public object FfiConverterOptionalTypeFFISendMemo: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): FfiSendMemo? { if (buf.get().toInt() == 0) { return null } return FfiConverterTypeFFISendMemo.read(buf) } override fun allocationSize(value: FfiSendMemo?): ULong { if (value == null) { return 1UL } else { return 1UL + FfiConverterTypeFFISendMemo.allocationSize(value) } } override fun write(value: FfiSendMemo?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) FfiConverterTypeFFISendMemo.write(value, buf) } } } /** * @suppress */ public object FfiConverterMapStringString: FfiConverterRustBuffer> { override fun read(buf: ByteBuffer): Map { val len = buf.getInt() return buildMap(len) { repeat(len) { val k = FfiConverterString.read(buf) val v = FfiConverterString.read(buf) this[k] = v } } } override fun allocationSize(value: Map): ULong { val spaceForMapSize = 4UL val spaceForChildren = value.map { (k, v) -> FfiConverterString.allocationSize(k) + FfiConverterString.allocationSize(v) }.sum() return spaceForMapSize + spaceForChildren } override fun write(value: Map, buf: ByteBuffer) { buf.putInt(value.size) // The parens on `(k, v)` here ensure we're calling the right method, // which is important for compatibility with older android devices. // Ref https://blog.danlew.net/2017/03/16/kotlin-puzzler-whose-line-is-it-anyways/ value.forEach { (k, v) -> FfiConverterString.write(k, buf) FfiConverterString.write(v, buf) } } } /** * Generate a 12-word mnemonic phrase */ @Throws(FfiException::class) fun `generateMnemonic`(): kotlin.String { return FfiConverterString.lift( uniffiRustCallWithError(FfiException) { _status -> UniffiLib.INSTANCE.uniffi_cdk_ffi_fn_func_generate_mnemonic( _status) } ) }