// 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.pvtcoms_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.ffi_pvtcoms_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.ffi_pvtcoms_ffi_rustbuffer_free(buf, status) } } @Suppress("TooGenericExceptionThrown") fun asByteBuffer() = this.data?.getByteBuffer(0, this.len)?.also { it.order(ByteOrder.BIG_ENDIAN) } } // 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) { val err = try { e.stackTraceToString() } catch(_: Throwable) { "" } callStatus.code = UNIFFI_CALL_UNEXPECTED_ERROR callStatus.error_buf = FfiConverterString.lower(err) } } 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 { val err = try { e.stackTraceToString() } catch(_: Throwable) { "" } callStatus.code = UNIFFI_CALL_UNEXPECTED_ERROR callStatus.error_buf = FfiConverterString.lower(err) } } } // Initial value and increment amount for handles. // These ensure that Kotlin-generated handles always have the lowest bit set private const val UNIFFI_HANDLEMAP_INITIAL = 1.toLong() private const val UNIFFI_HANDLEMAP_DELTA = 2.toLong() // 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() // Start private val counter = java.util.concurrent.atomic.AtomicLong(UNIFFI_HANDLEMAP_INITIAL) 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(UNIFFI_HANDLEMAP_DELTA) map.put(handle, obj) return handle } // Clone a handle, creating a new one fun clone(handle: Long): Long { val obj = map.get(handle) ?: throw InternalException("UniffiHandleMap.clone: Invalid handle") return insert(obj) } // 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 "pvtcoms_ffi" } // Define FFI callback types internal interface UniffiRustFutureContinuationCallback : com.sun.jna.Callback { fun callback(`data`: Long,`pollResult`: Byte,) } internal interface UniffiForeignFutureDroppedCallback : com.sun.jna.Callback { fun callback(`handle`: Long,) } internal interface UniffiCallbackInterfaceFree : com.sun.jna.Callback { fun callback(`handle`: Long,) } internal interface UniffiCallbackInterfaceClone : com.sun.jna.Callback { fun callback(`handle`: Long,) : Long } @Structure.FieldOrder("handle", "free") internal open class UniffiForeignFutureDroppedCallbackStruct( @JvmField internal var `handle`: Long = 0.toLong(), @JvmField internal var `free`: UniffiForeignFutureDroppedCallback? = null, ) : Structure() { class UniffiByValue( `handle`: Long = 0.toLong(), `free`: UniffiForeignFutureDroppedCallback? = null, ): UniffiForeignFutureDroppedCallbackStruct(`handle`,`free`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureDroppedCallbackStruct) { `handle` = other.`handle` `free` = other.`free` } } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureResultU8( @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(), ): UniffiForeignFutureResultU8(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureResultU8) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteU8 : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultU8.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureResultI8( @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(), ): UniffiForeignFutureResultI8(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureResultI8) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteI8 : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultI8.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureResultU16( @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(), ): UniffiForeignFutureResultU16(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureResultU16) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteU16 : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultU16.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureResultI16( @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(), ): UniffiForeignFutureResultI16(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureResultI16) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteI16 : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultI16.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureResultU32( @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(), ): UniffiForeignFutureResultU32(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureResultU32) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteU32 : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultU32.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureResultI32( @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(), ): UniffiForeignFutureResultI32(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureResultI32) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteI32 : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultI32.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureResultU64( @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(), ): UniffiForeignFutureResultU64(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureResultU64) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteU64 : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultU64.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureResultI64( @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(), ): UniffiForeignFutureResultI64(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureResultI64) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteI64 : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultI64.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureResultF32( @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(), ): UniffiForeignFutureResultF32(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureResultF32) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteF32 : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultF32.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureResultF64( @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(), ): UniffiForeignFutureResultF64(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureResultF64) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteF64 : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultF64.UniffiByValue,) } @Structure.FieldOrder("returnValue", "callStatus") internal open class UniffiForeignFutureResultRustBuffer( @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(), ): UniffiForeignFutureResultRustBuffer(`returnValue`,`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureResultRustBuffer) { `returnValue` = other.`returnValue` `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteRustBuffer : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultRustBuffer.UniffiByValue,) } @Structure.FieldOrder("callStatus") internal open class UniffiForeignFutureResultVoid( @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ) : Structure() { class UniffiByValue( `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), ): UniffiForeignFutureResultVoid(`callStatus`,), Structure.ByValue internal fun uniffiSetValue(other: UniffiForeignFutureResultVoid) { `callStatus` = other.`callStatus` } } internal interface UniffiForeignFutureCompleteVoid : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultVoid.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. // For large crates we prevent `MethodTooLargeException` (see #2340) // N.B. the name of the extension is very misleading, since it is // rather `InterfaceTooLargeException`, caused by too many methods // in the interface for large crates. // // By splitting the otherwise huge interface into two parts // * UniffiLib (this) // * IntegrityCheckingUniffiLib // And all checksum methods are put into `IntegrityCheckingUniffiLib` // we allow for ~2x as many methods in the UniffiLib interface. // // Note: above all written when we used JNA's `loadIndirect` etc. // We now use JNA's "direct mapping" - unclear if same considerations apply exactly. internal object IntegrityCheckingUniffiLib { init { Native.register(IntegrityCheckingUniffiLib::class.java, findLibraryName(componentName = "pvtcoms_ffi")) uniffiCheckContractApiVersion(this) uniffiCheckApiChecksums(this) } external fun uniffi_pvtcoms_ffi_checksum_func_fingerprint( ): Short external fun uniffi_pvtcoms_ffi_checksum_func_open( ): Short external fun uniffi_pvtcoms_ffi_checksum_func_safety_number( ): Short external fun uniffi_pvtcoms_ffi_checksum_func_seal( ): Short external fun uniffi_pvtcoms_ffi_checksum_func_verify( ): Short external fun uniffi_pvtcoms_ffi_checksum_func_version( ): Short external fun uniffi_pvtcoms_ffi_checksum_method_identity_fingerprint( ): Short external fun uniffi_pvtcoms_ffi_checksum_method_identity_public_key( ): Short external fun uniffi_pvtcoms_ffi_checksum_method_identity_sign( ): Short external fun uniffi_pvtcoms_ffi_checksum_method_identity_to_sealed( ): Short external fun uniffi_pvtcoms_ffi_checksum_constructor_identity_from_sealed( ): Short external fun uniffi_pvtcoms_ffi_checksum_constructor_identity_generate( ): Short external fun ffi_pvtcoms_ffi_uniffi_contract_version( ): Int } internal object UniffiLib { // The Cleaner for the whole library internal val CLEANER: UniffiCleaner by lazy { UniffiCleaner.create() } init { Native.register(UniffiLib::class.java, findLibraryName(componentName = "pvtcoms_ffi")) } external fun uniffi_pvtcoms_ffi_fn_clone_identity(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Long external fun uniffi_pvtcoms_ffi_fn_free_identity(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Unit external fun uniffi_pvtcoms_ffi_fn_constructor_identity_from_sealed(`storageKey`: RustBuffer.ByValue,`blob`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Long external fun uniffi_pvtcoms_ffi_fn_constructor_identity_generate(uniffi_out_err: UniffiRustCallStatus, ): Long external fun uniffi_pvtcoms_ffi_fn_method_identity_fingerprint(`ptr`: Long,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue external fun uniffi_pvtcoms_ffi_fn_method_identity_public_key(`ptr`: Long,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue external fun uniffi_pvtcoms_ffi_fn_method_identity_sign(`ptr`: Long,`msg`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue external fun uniffi_pvtcoms_ffi_fn_method_identity_to_sealed(`ptr`: Long,`storageKey`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue external fun uniffi_pvtcoms_ffi_fn_func_fingerprint(`publicKey`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue external fun uniffi_pvtcoms_ffi_fn_func_open(`key`: RustBuffer.ByValue,`aad`: RustBuffer.ByValue,`blob`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue external fun uniffi_pvtcoms_ffi_fn_func_safety_number(`sessionKey`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue external fun uniffi_pvtcoms_ffi_fn_func_seal(`key`: RustBuffer.ByValue,`aad`: RustBuffer.ByValue,`plaintext`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue external fun uniffi_pvtcoms_ffi_fn_func_verify(`publicKey`: RustBuffer.ByValue,`msg`: RustBuffer.ByValue,`signature`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Byte external fun uniffi_pvtcoms_ffi_fn_func_version(uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue external fun ffi_pvtcoms_ffi_rustbuffer_alloc(`size`: Long,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue external fun ffi_pvtcoms_ffi_rustbuffer_from_bytes(`bytes`: ForeignBytes.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue external fun ffi_pvtcoms_ffi_rustbuffer_free(`buf`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Unit external fun ffi_pvtcoms_ffi_rustbuffer_reserve(`buf`: RustBuffer.ByValue,`additional`: Long,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue external fun ffi_pvtcoms_ffi_rust_future_poll_u8(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_cancel_u8(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_free_u8(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_complete_u8(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Byte external fun ffi_pvtcoms_ffi_rust_future_poll_i8(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_cancel_i8(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_free_i8(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_complete_i8(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Byte external fun ffi_pvtcoms_ffi_rust_future_poll_u16(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_cancel_u16(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_free_u16(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_complete_u16(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Short external fun ffi_pvtcoms_ffi_rust_future_poll_i16(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_cancel_i16(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_free_i16(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_complete_i16(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Short external fun ffi_pvtcoms_ffi_rust_future_poll_u32(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_cancel_u32(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_free_u32(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_complete_u32(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Int external fun ffi_pvtcoms_ffi_rust_future_poll_i32(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_cancel_i32(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_free_i32(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_complete_i32(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Int external fun ffi_pvtcoms_ffi_rust_future_poll_u64(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_cancel_u64(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_free_u64(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_complete_u64(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Long external fun ffi_pvtcoms_ffi_rust_future_poll_i64(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_cancel_i64(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_free_i64(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_complete_i64(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Long external fun ffi_pvtcoms_ffi_rust_future_poll_f32(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_cancel_f32(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_free_f32(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_complete_f32(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Float external fun ffi_pvtcoms_ffi_rust_future_poll_f64(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_cancel_f64(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_free_f64(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_complete_f64(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Double external fun ffi_pvtcoms_ffi_rust_future_poll_rust_buffer(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_cancel_rust_buffer(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_free_rust_buffer(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_complete_rust_buffer(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue external fun ffi_pvtcoms_ffi_rust_future_poll_void(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_cancel_void(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_free_void(`handle`: Long, ): Unit external fun ffi_pvtcoms_ffi_rust_future_complete_void(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Unit } private fun uniffiCheckContractApiVersion(lib: IntegrityCheckingUniffiLib) { // Get the bindings contract version from our ComponentInterface val bindings_contract_version = 30 // Get the scaffolding contract version by calling the into the dylib val scaffolding_contract_version = lib.ffi_pvtcoms_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: IntegrityCheckingUniffiLib) { if (lib.uniffi_pvtcoms_ffi_checksum_func_fingerprint() != 53473.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_pvtcoms_ffi_checksum_func_open() != 24690.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_pvtcoms_ffi_checksum_func_safety_number() != 40851.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_pvtcoms_ffi_checksum_func_seal() != 32055.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_pvtcoms_ffi_checksum_func_verify() != 64808.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_pvtcoms_ffi_checksum_func_version() != 29400.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_pvtcoms_ffi_checksum_method_identity_fingerprint() != 40654.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_pvtcoms_ffi_checksum_method_identity_public_key() != 58357.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_pvtcoms_ffi_checksum_method_identity_sign() != 43050.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_pvtcoms_ffi_checksum_method_identity_to_sealed() != 20144.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_pvtcoms_ffi_checksum_constructor_identity_from_sealed() != 16893.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_pvtcoms_ffi_checksum_constructor_identity_generate() != 51303.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } } /** * @suppress */ public fun uniffiEnsureInitialized() { IntegrityCheckingUniffiLib // UniffiLib() initialized as objects are used, but we still need to explicitly // reference it so initialization across crates works as expected. UniffiLib } // 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?) { for (arg in args) { when (arg) { is Disposable -> arg.destroy() is ArrayList<*> -> { for (idx in arg.indices) { val element = arg[idx] if (element is Disposable) { element.destroy() } } } is Map<*, *> -> { for (element in arg.values) { if (element is Disposable) { element.destroy() } } } is Iterable<*> -> { for (element in arg) { if (element is Disposable) { element.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 } } /** * Placeholder object used to signal that we're constructing an interface with a FFI handle. * * This is the first argument for interface constructors that input a raw handle. It exists is that * so we can avoid signature conflicts when an interface has a regular constructor than inputs a * Long. * * @suppress * */ object UniffiWithHandle /** * Used to instantiate an interface without an actual pointer, for fakes in tests, mostly. * * @suppress * */ object NoHandle /** * 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() } /** * @suppress */ public object FfiConverterUInt: FfiConverter { override fun lift(value: Int): UInt { return value.toUInt() } override fun read(buf: ByteBuffer): UInt { return lift(buf.getInt()) } override fun lower(value: UInt): Int { return value.toInt() } override fun allocationSize(value: UInt) = 4UL override fun write(value: UInt, buf: ByteBuffer) { buf.putInt(value.toInt()) } } /** * @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) } } /** * @suppress */ public object FfiConverterByteArray: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): ByteArray { val len = buf.getInt() val byteArr = ByteArray(len) buf.get(byteArr) return byteArr } override fun allocationSize(value: ByteArray): ULong { return 4UL + value.size.toULong() } override fun write(value: ByteArray, buf: ByteBuffer) { buf.putInt(value.size) buf.put(value) } } // This template implements a class for working with a Rust struct via a handle // to 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 handle to the underlying Rust struct. // Method calls need to read this handle from the object's state and pass it in to // the Rust FFI. // // * When an instance is no longer needed, its handle 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 handle, 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 handle, but is interrupted // before it can pass the handle over the FFI to Rust. // * Thread B calls `destroy` and frees the underlying Rust struct. // * Thread A resumes, passing the already-read handle 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 // /** * A long-term Ed25519 identity. **Opaque** — the secret key never leaves Rust; the app holds an * `Identity` handle and persists it via [`Identity::to_sealed`]. */ public interface IdentityInterface { /** * Short fingerprint of the public key (for the contact / verify UI). */ fun `fingerprint`(): kotlin.String /** * This identity's 32-byte public key. */ fun `publicKey`(): kotlin.ByteArray /** * Sign a message with the long-term key (64-byte Ed25519 signature). */ fun `sign`(`msg`: kotlin.ByteArray): kotlin.ByteArray /** * Seal this identity (including its secret) at rest under the 32-byte device key, for the app to * persist. Restore later with [`Identity::from_sealed`]. */ fun `toSealed`(`storageKey`: kotlin.ByteArray): kotlin.ByteArray companion object } /** * A long-term Ed25519 identity. **Opaque** — the secret key never leaves Rust; the app holds an * `Identity` handle and persists it via [`Identity::to_sealed`]. */ open class Identity: Disposable, AutoCloseable, IdentityInterface { @Suppress("UNUSED_PARAMETER") /** * @suppress */ constructor(withHandle: UniffiWithHandle, handle: Long) { this.handle = handle this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(handle)) } /** * @suppress * * 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(noHandle: NoHandle) { this.handle = 0 this.cleanable = null } protected val handle: Long 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 callWithHandle(block: (handle: Long) -> 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 handle being freed concurrently. try { return block(this.uniffiCloneHandle()) } 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 handle: Long) : Runnable { override fun run() { if (handle == 0.toLong()) { // Fake object created with `NoHandle`, don't try to free. return; } uniffiRustCall { status -> UniffiLib.uniffi_pvtcoms_ffi_fn_free_identity(handle, status) } } } /** * @suppress */ fun uniffiCloneHandle(): Long { if (handle == 0.toLong()) { throw InternalException("uniffiCloneHandle() called on NoHandle object"); } return uniffiRustCall() { status -> UniffiLib.uniffi_pvtcoms_ffi_fn_clone_identity(handle, status) } } /** * Short fingerprint of the public key (for the contact / verify UI). */override fun `fingerprint`(): kotlin.String { return FfiConverterString.lift( callWithHandle { uniffiRustCall() { _status -> UniffiLib.uniffi_pvtcoms_ffi_fn_method_identity_fingerprint( it, _status) } } ) } /** * This identity's 32-byte public key. */override fun `publicKey`(): kotlin.ByteArray { return FfiConverterByteArray.lift( callWithHandle { uniffiRustCall() { _status -> UniffiLib.uniffi_pvtcoms_ffi_fn_method_identity_public_key( it, _status) } } ) } /** * Sign a message with the long-term key (64-byte Ed25519 signature). */override fun `sign`(`msg`: kotlin.ByteArray): kotlin.ByteArray { return FfiConverterByteArray.lift( callWithHandle { uniffiRustCall() { _status -> UniffiLib.uniffi_pvtcoms_ffi_fn_method_identity_sign( it, FfiConverterByteArray.lower(`msg`),_status) } } ) } /** * Seal this identity (including its secret) at rest under the 32-byte device key, for the app to * persist. Restore later with [`Identity::from_sealed`]. */ @Throws(FfiException::class)override fun `toSealed`(`storageKey`: kotlin.ByteArray): kotlin.ByteArray { return FfiConverterByteArray.lift( callWithHandle { uniffiRustCallWithError(FfiException) { _status -> UniffiLib.uniffi_pvtcoms_ffi_fn_method_identity_to_sealed( it, FfiConverterByteArray.lower(`storageKey`),_status) } } ) } companion object { /** * Restore an identity from the sealed blob produced by [`Identity::to_sealed`] under the same * 32-byte device key. Returns `DecryptFailed` on a wrong key / tampered blob. */ @Throws(FfiException::class) fun `fromSealed`(`storageKey`: kotlin.ByteArray, `blob`: kotlin.ByteArray): Identity { return FfiConverterTypeIdentity.lift( uniffiRustCallWithError(FfiException) { _status -> UniffiLib.uniffi_pvtcoms_ffi_fn_constructor_identity_from_sealed( FfiConverterByteArray.lower(`storageKey`),FfiConverterByteArray.lower(`blob`),_status) } ) } /** * Generate a fresh identity (secret stays in Rust). */ fun `generate`(): Identity { return FfiConverterTypeIdentity.lift( uniffiRustCall() { _status -> UniffiLib.uniffi_pvtcoms_ffi_fn_constructor_identity_generate( _status) } ) } } } /** * @suppress */ public object FfiConverterTypeIdentity: FfiConverter { override fun lower(value: Identity): Long { return value.uniffiCloneHandle() } override fun lift(value: Long): Identity { return Identity(UniffiWithHandle, value) } override fun read(buf: ByteBuffer): Identity { return lift(buf.getLong()) } override fun allocationSize(value: Identity) = 8UL override fun write(value: Identity, buf: ByteBuffer) { buf.putLong(lower(value)) } } /** * Errors surfaced across the FFI boundary (mapped to a Kotlin exception / Swift `throws`). */ sealed class FfiException: kotlin.Exception() { class BadLength( val `expected`: kotlin.UInt ) : FfiException() { override val message get() = "expected=${ `expected` }" } class DecryptFailed( ) : FfiException() { override val message get() = "" } 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.BadLength( FfiConverterUInt.read(buf), ) 2 -> FfiException.DecryptFailed() else -> throw RuntimeException("invalid error enum value, something is very wrong!!") } } override fun allocationSize(value: FfiException): ULong { return when(value) { is FfiException.BadLength -> ( // Add the size for the Int that specifies the variant plus the size needed for all fields 4UL + FfiConverterUInt.allocationSize(value.`expected`) ) is FfiException.DecryptFailed -> ( // Add the size for the Int that specifies the variant plus the size needed for all fields 4UL ) } } override fun write(value: FfiException, buf: ByteBuffer) { when(value) { is FfiException.BadLength -> { buf.putInt(1) FfiConverterUInt.write(value.`expected`, buf) Unit } is FfiException.DecryptFailed -> { buf.putInt(2) Unit } }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } } /** * Fingerprint a 32-byte public key — for the contact / verify UI. */ @Throws(FfiException::class) fun `fingerprint`(`publicKey`: kotlin.ByteArray): kotlin.String { return FfiConverterString.lift( uniffiRustCallWithError(FfiException) { _status -> UniffiLib.uniffi_pvtcoms_ffi_fn_func_fingerprint( FfiConverterByteArray.lower(`publicKey`),_status) } ) } /** * Open bytes sealed with [`seal`]. Returns `DecryptFailed` on a wrong key / tampered blob. */ @Throws(FfiException::class) fun `open`(`key`: kotlin.ByteArray, `aad`: kotlin.ByteArray, `blob`: kotlin.ByteArray): kotlin.ByteArray { return FfiConverterByteArray.lift( uniffiRustCallWithError(FfiException) { _status -> UniffiLib.uniffi_pvtcoms_ffi_fn_func_open( FfiConverterByteArray.lower(`key`),FfiConverterByteArray.lower(`aad`),FfiConverterByteArray.lower(`blob`),_status) } ) } /** * The 16-emoji safety number for a 32-byte pairwise session key — the verify screen. */ @Throws(FfiException::class) fun `safetyNumber`(`sessionKey`: kotlin.ByteArray): kotlin.String { return FfiConverterString.lift( uniffiRustCallWithError(FfiException) { _status -> UniffiLib.uniffi_pvtcoms_ffi_fn_func_safety_number( FfiConverterByteArray.lower(`sessionKey`),_status) } ) } /** * Seal bytes at rest under a 32-byte key — the app's local persistence uses the core's audited AEAD * (per-call random salt → HKDF subkey, so there is no caller-managed nonce). AAD binds context so * blobs of different kinds aren't interchangeable. */ @Throws(FfiException::class) fun `seal`(`key`: kotlin.ByteArray, `aad`: kotlin.ByteArray, `plaintext`: kotlin.ByteArray): kotlin.ByteArray { return FfiConverterByteArray.lift( uniffiRustCallWithError(FfiException) { _status -> UniffiLib.uniffi_pvtcoms_ffi_fn_func_seal( FfiConverterByteArray.lower(`key`),FfiConverterByteArray.lower(`aad`),FfiConverterByteArray.lower(`plaintext`),_status) } ) } /** * Verify an Ed25519 signature (64 bytes) over `msg` against a 32-byte public key. */ @Throws(FfiException::class) fun `verify`(`publicKey`: kotlin.ByteArray, `msg`: kotlin.ByteArray, `signature`: kotlin.ByteArray): kotlin.Boolean { return FfiConverterBoolean.lift( uniffiRustCallWithError(FfiException) { _status -> UniffiLib.uniffi_pvtcoms_ffi_fn_func_verify( FfiConverterByteArray.lower(`publicKey`),FfiConverterByteArray.lower(`msg`),FfiConverterByteArray.lower(`signature`),_status) } ) } /** * Core library version string. */ fun `version`(): kotlin.String { return FfiConverterString.lift( uniffiRustCall() { _status -> UniffiLib.uniffi_pvtcoms_ffi_fn_func_version( _status) } ) }