{%- if doc %}
{{ doc }}{%- endif %}
public func {{ method_camel }}(_ handler: @escaping (String) -> String{% if meta_params %}, {{ meta_params }}{% 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.
let rawAddr = RustBridge.{{ service_camel }}RawPtr(inner)
var innerPtr = OpaquePointer(bitPattern: rawAddr)!
let result = _{{ service_snake }}_{{ method_name }}_via_callback(
&innerPtr,
{% for meta_param in metadata_params %}{{ meta_param.name }},
{% endfor %}contextPtr,
trampolineFunc
)
guard result == 0 else { throw ServiceError.registrationFailed }
}