{{ self::swift_doc_block(cls.doc, "") }}public final class {{ cls.name }} {
let handle: OpaquePointer
init(handle: OpaquePointer) {
self.handle = handle
}
{%- for ctor in cls.constructors %}
{%- if ctor.is_designated() %}
{{ self::swift_doc_block(ctor.doc(), " ") }} public init({% for p in ctor.params() %}{{ p.signature() }}{% if !loop.last %}, {% endif %}{% endfor %}){% if ctor.is_fallible() %} throws{% endif %} {
{%- for param in ctor.params() %}
{%- if let Some(wrapper) = param.wrapper_code() %}
{{ wrapper }}
{%- endif %}
{%- endfor %}
{%- if ctor.is_fallible() %}
guard let ptr = {% for w in ctor.annotated_closure_wrappers() %}{{ w }} {% endfor %}{{ ctor.call_expr() }}{% for _ in ctor.closure_wrappers() %} }{% endfor %} else {
throw FfiError(message: takeLastErrorMessage())
}
{%- else %}
let ptr = {% for w in ctor.annotated_closure_wrappers() %}{{ w }} {% endfor %}{{ ctor.call_expr() }}{% for _ in ctor.closure_wrappers() %} }{% endfor %}!
{%- endif %}
self.handle = ptr
}
{%- else if ctor.is_factory() %}
{{ self::swift_doc_block(ctor.doc(), " ") }} public static func {{ ctor.name().unwrap() }}(){% if ctor.is_fallible() %} throws{% endif %} -> {{ cls.name }} {
{%- if ctor.is_fallible() %}
guard let ptr = {{ ctor.ffi_symbol() }}() else {
throw FfiError(message: takeLastErrorMessage())
}
{%- else %}
let ptr = {{ ctor.ffi_symbol() }}()!
{%- endif %}
return {{ cls.name }}(handle: ptr)
}
{%- else if ctor.is_convenience() %}
{{ self::swift_doc_block(ctor.doc(), " ") }} public convenience init({% for p in ctor.params() %}{{ p.signature() }}{% if !loop.last %}, {% endif %}{% endfor %}){% if ctor.is_fallible() %} throws{% endif %} {
{%- for param in ctor.params() %}
{%- if let Some(wrapper) = param.wrapper_code() %}
{{ wrapper }}
{%- endif %}
{%- endfor %}
{%- if ctor.is_fallible() %}
guard let ptr = {% for w in ctor.annotated_closure_wrappers() %}{{ w }} {% endfor %}{{ ctor.call_expr() }}{% for _ in ctor.closure_wrappers() %} }{% endfor %} else {
throw FfiError(message: takeLastErrorMessage())
}
{%- else %}
let ptr = {% for w in ctor.annotated_closure_wrappers() %}{{ w }} {% endfor %}{{ ctor.call_expr() }}{% for _ in ctor.closure_wrappers() %} }{% endfor %}!
{%- endif %}
self.init(handle: ptr)
}
{%- endif %}
{%- endfor %}
deinit {
{{ cls.ffi_free }}(handle)
}
{%- for method in cls.methods %}
{{ self::swift_doc_block(method.doc, " ") }} public{% if method.is_static %} static{% endif %} func {{ method.name }}({% for p in method.params %}{{ p.signature() }}{% if !loop.last %}, {% endif %}{% endfor %}){% if method.mode.is_async() %} async throws{% if let Some(result) = method.mode.async_result() %}{% if let Some(ret) = result.swift_type() %} -> {{ ret }}{% endif %}{% endif %}{% else %}{% if method.returns.is_throws() %} throws{% endif %}{% if let Some(ret) = method.returns.swift_type() %} -> {{ ret }}{% endif %}{% endif %} {
{%- match method.mode %}
{%- when SwiftCallMode::Async { start, poll, complete, cancel, free, result } %}
{%- for param in method.params %}
{%- if let Some(wrapper) = param.wrapper_code() %}
{{ wrapper }}
{%- endif %}
{%- endfor %}
let futureHandle = {% for w in method.closure_wrappers() %}{{ w }} {% endfor %}{{ method.start_call_expr() }}{% for _ in method.closure_wrappers() %} }{% endfor %}
{%- if result.is_direct() || result.is_unit() %}
return try await boltffiAsyncCallDirect(
futureHandle: futureHandle,
pollFn: {{ poll }},
completeFn: {{ complete }},
cancelFn: {{ cancel }},
freeFn: {{ free }}
)
{%- elif result.is_direct_buffer() %}
return try await boltffiAsyncCall(
futureHandle: futureHandle,
pollFn: {{ poll }},
completeFn: {{ complete }},
cancelFn: {{ cancel }},
freeFn: {{ free }}
) { buf, status in
guard status.code == 0 else { {{ prefix }}_free_buf(buf); throw FfiError(message: "ffi call failed") }
defer { {{ prefix }}_free_buf(buf) }
{%- if result.direct_buffer_is_data() %}
guard buf.len > 0, let ptr = buf.ptr else { return Data() }
return Data(bytes: ptr, count: Int(buf.len))
{%- else %}
guard buf.len > 0, let ptr = buf.ptr else { return [] }
let count = Int(buf.len) / MemoryLayout<{{ result.direct_buffer_element_type().unwrap() }}>.stride
let rawPtr = UnsafeRawPointer(ptr).assumingMemoryBound(to: {{ result.direct_buffer_element_type().unwrap() }}.self)
{%- if let Some(mapping) = result.direct_buffer_composite_mapping() %}
return (0..<count).map { i in
let _raw = rawPtr[i]
return {{ mapping.swift_record_type }}({% for f in mapping.fields %}{{ f.swift_name }}: _raw.{{ f.c_name }}{% if !loop.last %}, {% endif %}{% endfor %})
}
{%- elif let Some(enum_name) = result.direct_buffer_enum_mapping() %}
return Array(UnsafeBufferPointer(start: UnsafeRawPointer(rawPtr).assumingMemoryBound(to: {{ enum_name }}.self), count: count))
{%- else %}
return Array(UnsafeBufferPointer(start: rawPtr, count: count))
{%- endif %}
{%- endif %}
}
{%- else %}
return try await boltffiAsyncCall(
futureHandle: futureHandle,
pollFn: {{ poll }},
completeFn: {{ complete }},
cancelFn: {{ cancel }},
freeFn: {{ free }}
) { buf, status in
guard status.code == 0 else { {{ prefix }}_free_buf(buf); throw FfiError(message: "ffi call failed") }
{%- if result.throws() %}
defer { {{ prefix }}_free_buf(buf) }
return try boltffiDecodeOwnedBuf(buf.ptr, Int(buf.len)) { reader in {{ result.reader_decode_expr().unwrap() }} }
{%- else %}
defer { {{ prefix }}_free_buf(buf) }
return boltffiDecodeOwnedBuf(buf.ptr, Int(buf.len)) { reader in {{ result.reader_decode_expr().unwrap() }} }
{%- endif %}
}
{%- endif %}
{%- when SwiftCallMode::Sync { symbol } %}
{%- for param in method.params %}
{%- if let Some(wrapper) = param.wrapper_code() %}
{{ wrapper }}
{%- endif %}
{%- endfor %}
{%- for open in method.sync_closure_opens() %}
{{ open }}
{%- endfor %}
{%- if method.returns.is_void() %}
{%- if method.needs_handle() %}
{{ method.method_body_indent() }}{{ symbol }}(handle{% for p in method.params %}, {{ p.ffi_arg() }}{% endfor %})
{%- else %}
{{ method.method_body_indent() }}{{ symbol }}({% for p in method.params %}{{ p.ffi_arg() }}{% if !loop.last %}, {% endif %}{% endfor %})
{%- endif %}
{%- elif method.returns.is_direct_buffer() %}
{%- if method.needs_handle() %}
{{ method.method_body_indent() }}let buf = {{ symbol }}(handle{% for p in method.params %}, {{ p.ffi_arg() }}{% endfor %})
{%- else %}
{{ method.method_body_indent() }}let buf = {{ symbol }}({% for p in method.params %}{{ p.ffi_arg() }}{% if !loop.last %}, {% endif %}{% endfor %})
{%- endif %}
{{ method.method_body_indent() }}defer { {{ prefix }}_free_buf(buf) }
{%- if method.returns.direct_buffer_is_data() %}
{{ method.method_body_indent() }}guard buf.len > 0, let ptr = buf.ptr else { return Data() }
{{ method.method_body_indent() }}return Data(bytes: ptr, count: Int(buf.len))
{%- else %}
{{ method.method_body_indent() }}guard buf.len > 0, let ptr = buf.ptr else { return [] }
{{ method.method_body_indent() }}let count = Int(buf.len) / MemoryLayout<{{ method.returns.direct_buffer_element_type().unwrap() }}>.stride
{{ method.method_body_indent() }}let rawPtr = UnsafeRawPointer(ptr).assumingMemoryBound(to: {{ method.returns.direct_buffer_element_type().unwrap() }}.self)
{%- if let Some(mapping) = method.returns.direct_buffer_composite_mapping() %}
{{ method.method_body_indent() }}return (0..<count).map { i in
{{ method.method_body_indent() }} let _raw = rawPtr[i]
{{ method.method_body_indent() }} return {{ mapping.swift_record_type }}({% for f in mapping.fields %}{{ f.swift_name }}: _raw.{{ f.c_name }}{% if !loop.last %}, {% endif %}{% endfor %})
{{ method.method_body_indent() }}}
{%- elif let Some(enum_name) = method.returns.direct_buffer_enum_mapping() %}
{{ method.method_body_indent() }}return Array(UnsafeBufferPointer(start: UnsafeRawPointer(rawPtr).assumingMemoryBound(to: {{ enum_name }}.self), count: count))
{%- else %}
{{ method.method_body_indent() }}return Array(UnsafeBufferPointer(start: rawPtr, count: count))
{%- endif %}
{%- endif %}
{%- elif method.returns.is_wire_encoded() %}
{%- if method.needs_handle() %}
{{ method.method_body_indent() }}let buf = {{ symbol }}(handle{% for p in method.params %}, {{ p.ffi_arg() }}{% endfor %})
{%- else %}
{{ method.method_body_indent() }}let buf = {{ symbol }}({% for p in method.params %}{{ p.ffi_arg() }}{% if !loop.last %}, {% endif %}{% endfor %})
{%- endif %}
{{ method.method_body_indent() }}defer { {{ prefix }}_free_buf(buf) }
{%- if let Some(reader_expr) = method.returns.reader_decode_expr() %}
{%- if method.returns.is_throws() %}
{{ method.method_body_indent() }}return try boltffiDecodeOwnedBuf(buf.ptr, Int(buf.len)) { reader in {{ reader_expr }} }
{%- else %}
{{ method.method_body_indent() }}return boltffiDecodeOwnedBuf(buf.ptr, Int(buf.len)) { reader in {{ reader_expr }} }
{%- endif %}
{%- elif let Some(decode_expr) = method.returns.decode_expr() %}
{{ method.method_body_indent() }}let wire = WireBuffer(ptr: buf.ptr!, len: Int(buf.len))
{{ method.method_body_indent() }}return {{ decode_expr }}
{%- endif %}
{%- elif method.returns.is_throws() %}
{{ method.method_body_indent() }}fatalError("throwing methods not yet implemented in IR backend")
{%- elif let Some((class_name, nullable)) = method.returns.handle_info() %}
{%- if nullable %}
{%- if method.needs_handle() %}
{{ method.method_body_indent() }}guard let ptr = {{ symbol }}(handle{% for p in method.params %}, {{ p.ffi_arg() }}{% endfor %}) else { return nil }
{%- else %}
{{ method.method_body_indent() }}guard let ptr = {{ symbol }}({% for p in method.params %}{{ p.ffi_arg() }}{% if !loop.last %}, {% endif %}{% endfor %}) else { return nil }
{%- endif %}
{{ method.method_body_indent() }}return {{ class_name }}(handle: ptr)
{%- else %}
{%- if method.needs_handle() %}
{{ method.method_body_indent() }}let ptr = {{ symbol }}(handle{% for p in method.params %}, {{ p.ffi_arg() }}{% endfor %})!
{%- else %}
{{ method.method_body_indent() }}let ptr = {{ symbol }}({% for p in method.params %}{{ p.ffi_arg() }}{% if !loop.last %}, {% endif %}{% endfor %})!
{%- endif %}
{{ method.method_body_indent() }}return {{ class_name }}(handle: ptr)
{%- endif %}
{%- elif method.returns.is_composite() %}
{%- if let Some(convert_expr) = method.returns.composite_convert_expr("_raw") %}
{%- if method.needs_handle() %}
{{ method.method_body_indent() }}let _raw = {{ symbol }}(handle{% for p in method.params %}, {{ p.ffi_arg() }}{% endfor %})
{%- else %}
{{ method.method_body_indent() }}let _raw = {{ symbol }}({% for p in method.params %}{{ p.ffi_arg() }}{% if !loop.last %}, {% endif %}{% endfor %})
{%- endif %}
{{ method.method_body_indent() }}return {{ convert_expr }}
{%- endif %}
{%- else %}
{%- if method.needs_handle() %}
{{ method.method_body_indent() }}return {{ symbol }}(handle{% for p in method.params %}, {{ p.ffi_arg() }}{% endfor %})
{%- else %}
{{ method.method_body_indent() }}return {{ symbol }}({% for p in method.params %}{{ p.ffi_arg() }}{% if !loop.last %}, {% endif %}{% endfor %})
{%- endif %}
{%- endif %}
{%- for close in method.sync_closure_closes() %}
{{ close }}
{%- endfor %}
{%- endmatch %}
}
{%- endfor %}
{% for stream in cls.streams %}
{%- match stream.mode %}
{%- when SwiftStreamMode::Async %}
public func {{ stream.name }}() -> AsyncStream<{{ stream.item_type }}> {
AsyncStream<{{ stream.item_type }}> { continuation in
guard let subscription = {{ stream.subscribe }}(self.handle) else {
continuation.finish()
return
}
let context = WireStreamContextBase(
subscription: subscription, batchSize: 16,
popBatch: {{ stream.pop_batch }},
poll: {{ stream.poll }},
unsubscribe: {{ stream.unsubscribe }},
freeFn: {{ stream.free }},
freeBuf: {{ stream.free_buf }},
atomicCas: {{ stream.atomic_cas }},
processItems: { reader in
let count = Int(reader.readU32())
for _ in 0..<count {
let item = {{ stream.item_reader_decode_expr() }}
_ = continuation.yield(item)
}
},
finish: { continuation.finish() }
)
continuation.onTermination = { @Sendable _ in context.requestTermination() }
context.start()
}
}
{%- when SwiftStreamMode::Batch { class_name, method_name_pascal } %}
public func {{ stream.name }}() -> {{ class_name }}{{ method_name_pascal }}Subscription {
{{ class_name }}{{ method_name_pascal }}Subscription(
handle: {{ stream.subscribe }}(self.handle),
popBatch: {{ stream.pop_batch }},
wait: {{ stream.wait }},
unsubscribe: {{ stream.unsubscribe }},
freeFn: {{ stream.free }},
freeBuf: {{ stream.free_buf }}
)
}
{%- when SwiftStreamMode::Callback { class_name, method_name_pascal } %}
public func {{ stream.name }}(callback: @escaping ({{ stream.item_type }}) -> Void) -> {{ class_name }}{{ method_name_pascal }}Cancellable {
guard let subscription = {{ stream.subscribe }}(self.handle) else {
return {{ class_name }}{{ method_name_pascal }}Cancellable {}
}
final class CallbackContext: @unchecked Sendable {
let subscription: SubscriptionHandle
let batchSize: UInt
let popBatch: (SubscriptionHandle, UInt) -> FfiBuf_u8
let unsubscribe: (SubscriptionHandle?) -> Void
let freeFn: (SubscriptionHandle?) -> Void
let freeBuf: (FfiBuf_u8) -> Void
let atomicCas: (UnsafeMutablePointer<UInt8>?, UInt8, UInt8) -> Bool
let callback: ({{ stream.item_type }}) -> Void
private var lifecycleTag: UInt8 = 0
private var callbackTag: UInt8 = 0
init(
subscription: SubscriptionHandle, batchSize: UInt,
popBatch: @escaping (SubscriptionHandle, UInt) -> FfiBuf_u8,
poll: @escaping (SubscriptionHandle?, UInt64, StreamContinuationCallback?) -> Void,
unsubscribe: @escaping (SubscriptionHandle?) -> Void,
freeFn: @escaping (SubscriptionHandle?) -> Void,
freeBuf: @escaping (FfiBuf_u8) -> Void,
atomicCas: @escaping (UnsafeMutablePointer<UInt8>?, UInt8, UInt8) -> Bool,
callback: @escaping ({{ stream.item_type }}) -> Void
) {
self.subscription = subscription; self.batchSize = batchSize
self.popBatch = popBatch; self.unsubscribe = unsubscribe
self.freeFn = freeFn; self.freeBuf = freeBuf; self.atomicCas = atomicCas
self.callback = callback
}
func start() { registerPoll() }
func requestTermination() {
let started = withUnsafeMutablePointer(to: &lifecycleTag) { atomicCas($0, 0, 1) }
if started { unsubscribe(subscription); _ = withUnsafeMutablePointer(to: &lifecycleTag) { atomicCas($0, 1, 2) } }
attemptFinalize()
}
private func attemptFinalize() {
guard (withUnsafeMutablePointer(to: &callbackTag) { atomicCas($0, 0, 0) }) else { return }
guard (withUnsafeMutablePointer(to: &lifecycleTag) { atomicCas($0, 2, 3) }) else { return }
freeFn(subscription)
}
private func schedulePoll() { Task { [self] in await Task.yield(); registerPoll() } }
private func registerPoll() {
guard (withUnsafeMutablePointer(to: &lifecycleTag) { atomicCas($0, 0, 0) }) else { attemptFinalize(); return }
let data = UInt64(UInt(bitPattern: Unmanaged.passRetained(self).toOpaque()))
{{ stream.poll }}(subscription, data) { data, result in
Unmanaged<CallbackContext>.fromOpaque(UnsafeRawPointer(bitPattern: UInt(data))!).takeRetainedValue().handlePoll(result)
}
}
private func handlePoll(_ pollResult: Int8) {
let isClosed = pollResult == StreamPollResult.closed.rawValue
guard (withUnsafeMutablePointer(to: &callbackTag) { atomicCas($0, 0, 1) }) else { attemptFinalize(); return }
defer { _ = withUnsafeMutablePointer(to: &callbackTag) { atomicCas($0, 1, 0) }; attemptFinalize() }
guard (withUnsafeMutablePointer(to: &lifecycleTag) { atomicCas($0, 0, 0) }) else { return }
while true {
let buf = popBatch(subscription, batchSize)
guard buf.len > 0, let ptr = buf.ptr else { freeBuf(buf); break }
var reader = WireReader(ptr: ptr, len: Int(buf.len))
freeBuf(buf)
let count = Int(reader.readU32())
for _ in 0..<count {
let item = {{ stream.item_reader_decode_expr() }}
callback(item)
}
}
if isClosed { requestTermination(); return }
guard (withUnsafeMutablePointer(to: &lifecycleTag) { atomicCas($0, 0, 0) }) else { return }
schedulePoll()
}
}
let context = CallbackContext(
subscription: subscription, batchSize: 16,
popBatch: {{ stream.pop_batch }},
poll: {{ stream.poll }},
unsubscribe: {{ stream.unsubscribe }},
freeFn: {{ stream.free }},
freeBuf: {{ stream.free_buf }},
atomicCas: {{ stream.atomic_cas }},
callback: callback
)
context.start()
return {{ class_name }}{{ method_name_pascal }}Cancellable { context.requestTermination() }
}
{%- endmatch %}
{%- endfor %}
}
{%- for stream in cls.streams %}
{%- match stream.mode %}
{%- when SwiftStreamMode::Batch { class_name, method_name_pascal } %}
public final class {{ class_name }}{{ method_name_pascal }}Subscription {
private let handle: SubscriptionHandle?
private let popBatchFn: (SubscriptionHandle, UInt) -> FfiBuf_u8
private let waitFn: (SubscriptionHandle, UInt32) -> Int32
private let unsubscribeFn: (SubscriptionHandle?) -> Void
private let freeFn: (SubscriptionHandle?) -> Void
private let freeBuf: (FfiBuf_u8) -> Void
private var isUnsubscribed = false
init(
handle: SubscriptionHandle?,
popBatch: @escaping (SubscriptionHandle, UInt) -> FfiBuf_u8,
wait: @escaping (SubscriptionHandle, UInt32) -> Int32,
unsubscribe: @escaping (SubscriptionHandle?) -> Void,
freeFn: @escaping (SubscriptionHandle?) -> Void,
freeBuf: @escaping (FfiBuf_u8) -> Void
) {
self.handle = handle
self.popBatchFn = popBatch
self.waitFn = wait
self.unsubscribeFn = unsubscribe
self.freeFn = freeFn
self.freeBuf = freeBuf
}
deinit {
freeFn(handle)
}
public func popBatch(maxCount: UInt = 16) -> [{{ stream.item_type }}] {
guard let h = handle else { return [] }
let buf = popBatchFn(h, maxCount)
guard buf.len > 0, let ptr = buf.ptr else { freeBuf(buf); return [] }
var reader = WireReader(ptr: ptr, len: Int(buf.len))
freeBuf(buf)
let count = Int(reader.readU32())
var result: [{{ stream.item_type }}] = []
result.reserveCapacity(count)
for _ in 0..<count {
let item = {{ stream.item_reader_decode_expr() }}
result.append(item)
}
return result
}
public func wait(timeout: UInt32) -> Int32 {
guard let h = handle else { return -1 }
return waitFn(h, timeout)
}
public func unsubscribe() {
guard !isUnsubscribed else { return }
isUnsubscribed = true
unsubscribeFn(handle)
}
}
{%- when SwiftStreamMode::Callback { class_name, method_name_pascal } %}
public final class {{ class_name }}{{ method_name_pascal }}Cancellable {
private var isCancelled = false
private let cancelAction: () -> Void
init(onCancel: @escaping () -> Void = {}) {
self.cancelAction = onCancel
}
deinit {
cancel()
}
public func cancel() {
guard !isCancelled else { return }
isCancelled = true
cancelAction()
}
}
{%- when SwiftStreamMode::Async %}
{%- endmatch %}
{%- endfor %}