alef 0.48.13

Opinionated polyglot binding generator for Rust libraries
Documentation
{%- if doc %}
{{ doc }}{%- endif %}
    public func {{ variant_name }}(_ handler: @escaping (String) -> String{% if signature_params %}, {% for param in signature_params %}{{ param.name }}: {{ param.swift_type }}{{ "," if not loop.last else "" }}{% endfor %}{% endif %}) throws {
        // Box the handler and retain it; the box pointer is passed to the
        // C layer as the trampoline context and released in deinit.
        let handlerBox = HandlerBox(handler)
        let contextPtr = Unmanaged.passRetained(handlerBox).toOpaque()
        handlerBoxes.append(contextPtr)

        // Create a C-compatible callback wrapper
        let trampolineFunc: @convention(c) (UnsafeMutableRawPointer?, UnsafePointer<UInt8>?, Int) -> UnsafeMutablePointer<UInt8>? = { contextPtr, requestPtr, requestLen in
            guard let contextPtr = contextPtr else { return nil }
            guard let requestPtr = requestPtr else { return nil }

            // Recover the boxed handler closure from the context pointer
            let handlerBox = Unmanaged<HandlerBox>.fromOpaque(contextPtr).takeUnretainedValue()
            let requestData = Data(bytes: requestPtr, count: requestLen)
            let requestJSON = String(data: requestData, encoding: .utf8) ?? ""
            let responseJSON = handlerBox.handler(requestJSON)

            // Allocate response string on heap (Rust side frees via extern "C" { fn free })
            let responseBytes = responseJSON.utf8CString
            let responsePtr = UnsafeMutablePointer<UInt8>.allocate(capacity: responseBytes.count)
            for (i, byte) in responseBytes.enumerated() {
                responsePtr[i] = UInt8(bitPattern: byte)
            }
            return responsePtr
        }

        guard let inner = inner else { throw ServiceError.invalidHandle }

        // Call the C function via @_silgen_name. The callback registration is defined
        // OUTSIDE the swift-bridge module as a plain extern "C" function. swift-bridge
        // hides the wrapper's raw pointer behind an `internal` field, so call through
        // the alef-emitted `RustBridge.{{ service_camel }}RawPtr` shim which returns
        // the App address as a `usize` we can reconstitute into an OpaquePointer.
        //
        // NOTE: the Rust side declares `app` as a single level of pointer
        // indirection (`*mut <Service>`). Passing `&innerPtr` instead of
        // `innerPtr` itself would hand Rust a pointer to the stack slot
        // holding the address, not the address of the instance itself.
        let rawAddr = RustBridge.{{ service_camel }}RawPtr(inner)
        let innerPtr = OpaquePointer(bitPattern: rawAddr)!
        {% for arg in wrapper_call_args %}{% if arg.is_opaque_wrapper %}
        // Same reasoning applies to `{{ arg.name }}`: it is a swift-bridge opaque
        // class, ABI-wise a single pointer, so its raw heap address must be
        // extracted explicitly for this plain `extern "C"` function.
        let {{ arg.name }}RawAddr = RustBridge.{{ arg.raw_ptr_swift_name }}({{ arg.name }})
        let {{ arg.name }}Ptr = OpaquePointer(bitPattern: {{ arg.name }}RawAddr)!
        {% endif %}{% endfor %}
        let result = _{{ service_snake }}_{{ base_method_name }}_via_callback(
            innerPtr,
            {% for arg in wrapper_call_args %}{% if arg.is_opaque_wrapper %}{{ arg.name }}Ptr,
            {% else %}{{ arg.name }},
            {% endif %}{% endfor %}contextPtr,
            trampolineFunc
        )
        guard result == 0 else { throw ServiceError.registrationFailed }
    }