uniffi_bindgen 0.32.0

a multi-language bindings generator for rust (codegen and cli tooling)
Documentation
{%- let trait_impl=format!("UniffiCallbackInterface{}", name) %}

// Put the implementation in a struct so we don't pollute the top-level namespace
fileprivate struct {{ trait_impl }} {

    // Create the VTable using a series of closures.
    // Swift automatically converts these into C callback functions.
    //
    // Store the vtable directly.
    static let vtable: {{ vtable|ffi_type_name }} = {{ vtable|ffi_type_name }}(
        uniffiFree: { (uniffiHandle: UInt64) -> () in
            do {
                try {{ ffi_converter_name }}.handleMap.remove(handle: uniffiHandle)
            } catch {
                print("Uniffi callback interface {{ name }}: handle missing in uniffiFree")
            }
        },
        uniffiClone: { (uniffiHandle: UInt64) -> UInt64 in
            do {
                return try {{ ffi_converter_name }}.handleMap.clone(handle: uniffiHandle)
            } catch {
                fatalError("Uniffi callback interface {{ name }}: handle missing in uniffiClone")
            }
        },
        {%- for (ffi_callback, meth) in vtable_methods %}
        {{ meth.name()|fn_name }}: { (
            {%- for arg in ffi_callback.arguments() %}
            {{ arg.name()|var_name }}: {{ arg.type_().borrow()|ffi_type_name }}{% if !loop.last || ffi_callback.has_rust_call_status_arg() %},{% endif %}
            {%- endfor -%}
            {%- if ffi_callback.has_rust_call_status_arg() %}
            uniffiCallStatus: UnsafeMutablePointer<RustCallStatus>
            {%- endif %}
        ) in
            let makeCall = {
                () {% if meth.is_async() %}async {% endif %}throws -> {% match meth.return_type() %}{% when Some(t) %}{{ t|type_name }}{% when None %}(){% endmatch %} in
                guard let uniffiObj = try? {{ ffi_converter_name }}.handleMap.get(handle: uniffiHandle) else {
                    throw UniffiInternalError.unexpectedStaleHandle
                }
                return {% if meth.throws() %}try {% endif %}{% if meth.is_async() %}await {% endif %}uniffiObj.{{ meth.name()|fn_name }}(
                    {%- for arg in meth.arguments() %}
                    {% if !config.omit_argument_labels() %} {{ arg.name()|arg_name }}: {% endif %}try {{ arg|lift_fn }}({{ arg.name()|var_name }}){% if !loop.last %},{% endif %}
                    {%- endfor %}
                )
            }
            {%- if !meth.is_async() %}

            {% match meth.return_type() %}
            {%- when Some(t) %}
            let writeReturn = { uniffiOutReturn.pointee = {{ t|lower_fn }}($0) }
            {%- when None %}
            let writeReturn = { () }
            {%- endmatch %}

            {%- match meth.throws_type() %}
            {%- when None %}
            uniffiTraitInterfaceCall(
                callStatus: uniffiCallStatus,
                makeCall: makeCall,
                writeReturn: writeReturn
            )
            {%- when Some(error_type) %}
            uniffiTraitInterfaceCallWithError(
                callStatus: uniffiCallStatus,
                makeCall: makeCall,
                writeReturn: writeReturn,
                lowerError: {{ error_type|lower_fn }}
            )
            {%- endmatch %}
            {%- else %}

            let uniffiHandleSuccess = { (returnValue: {{ meth.return_type()|return_type_name }}) in
                uniffiFutureCallback(
                    uniffiCallbackData,
                    {{ meth.foreign_future_ffi_result_struct().name()|ffi_struct_name }}(
                        {%- if let Some(return_type) = meth.return_type() %}
                        returnValue: {{ return_type|lower_fn }}(returnValue),
                        {%- endif %}
                        callStatus: RustCallStatus()
                    )
                )
            }
            let uniffiHandleError = { (statusCode, errorBuf) in
                uniffiFutureCallback(
                    uniffiCallbackData,
                    {{ meth.foreign_future_ffi_result_struct().name()|ffi_struct_name }}(
                        {%- if let Some(return_type) = meth.return_type() %}
                        returnValue: {{ meth.return_type().map(FfiType::from)|ffi_default_value }},
                        {%- endif %}
                        callStatus: RustCallStatus(code: statusCode, errorBuf: errorBuf)
                    )
                )
            }

            {%- match meth.throws_type() %}
            {%- when None %}
            uniffiTraitInterfaceCallAsync(
                makeCall: makeCall,
                handleSuccess: uniffiHandleSuccess,
                handleError: uniffiHandleError,
                droppedCallback: uniffiOutDroppedCallback
            )
            {%- when Some(error_type) %}
            uniffiTraitInterfaceCallAsyncWithError(
                makeCall: makeCall,
                handleSuccess: uniffiHandleSuccess,
                handleError: uniffiHandleError,
                lowerError: {{ error_type|lower_fn }},
                droppedCallback: uniffiOutDroppedCallback
            )
            {%- endmatch %}
            {%- endif %}
        }{% if !loop.last %},{% endif %}
        {%- endfor %}
    )

    // Rust stores this pointer for future callback invocations, so it must live
    // for the process lifetime (not just for the init function call).
    //
    // `nonisolated(unsafe)` is needed under Swift 6 strict concurrency.
    // This is safe because the pointee is initialized once during static init
    // and never mutated by either side of the FFI.  Its fields are C function pointers.
    nonisolated(unsafe) static let vtablePtr: UnsafePointer<{{ vtable|ffi_type_name }}> = {
        let ptr = UnsafeMutablePointer<{{ vtable|ffi_type_name }}>.allocate(capacity: 1)
        ptr.initialize(to: vtable)
        return UnsafePointer(ptr)
    }()
}

private func {{ callback_init }}() {
    {{ ffi_init_callback.name() }}({{ trait_impl }}.vtablePtr)
}