{{ 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{% if ctor.is_optional() %}?{% endif %}({% 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_optional() %}
let ptr = {% for w in ctor.annotated_closure_wrappers() %}{{ w }} {% endfor %}{{ ctor.call_expr() }}{% for _ in ctor.closure_wrappers() %} }{% endfor %}
guard let ptr = ptr else {
return nil
}
{%- elif ctor.is_fallible() %}
let ptr = {% for w in ctor.annotated_closure_wrappers() %}{{ w }} {% endfor %}{{ ctor.call_expr() }}{% for _ in ctor.closure_wrappers() %} }{% endfor %}
guard let ptr = ptr 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_optional() %}?{% endif %} {
{%- if ctor.is_optional() %}
guard let ptr = {{ ctor.ffi_symbol() }}() else {
return nil
}
{%- elif 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{% if ctor.is_optional() %}?{% endif %}({% 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_optional() %}
let ptr = {% for w in ctor.annotated_closure_wrappers() %}{{ w }} {% endfor %}{{ ctor.call_expr() }}{% for _ in ctor.closure_wrappers() %} }{% endfor %}
guard let ptr = ptr else {
return nil
}
{%- elif ctor.is_fallible() %}
let ptr = {% for w in ctor.annotated_closure_wrappers() %}{{ w }} {% endfor %}{{ ctor.call_expr() }}{% for _ in ctor.closure_wrappers() %} }{% endfor %}
guard let ptr = ptr 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_mutating() %} mutating{% elif 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() %}
{%- if result.is_direct() %}
let rawResult = try await boltffiAsyncCallDirect(
futureHandle: futureHandle,
pollFn: {{ poll }},
completeFn: {{ complete }},
cancelFn: {{ cancel }},
freeFn: {{ free }}
)
{%- if let Some(expr) = result.direct_return_expr("rawResult") %}
return {{ expr }}
{%- endif %}
{%- else %}
return try await boltffiAsyncCallDirect(
futureHandle: futureHandle,
pollFn: {{ poll }},
completeFn: {{ complete }},
cancelFn: {{ cancel }},
freeFn: {{ free }}
)
{%- endif %}
{%- 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 failed in async completion with code \(status.code)") }
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 failed in async completion with code \(status.code)") }
{%- 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 %}
{%- if let Some(rs) = method.value_self %}
{%- if let Some(wrapper) = rs.wrapper_code %}
{{ wrapper }}
{%- endif %}
{%- endif %}
{%- for open in method.sync_closure_opens() %}
{{ open }}
{%- endfor %}
{%- if method.returns.is_void() %}
{{ method.method_body_indent() }}{{ method.sync_call_expr() }}
{%- elif method.returns.is_direct_buffer() %}
{{ method.method_body_indent() }}let buf = {{ method.sync_call_expr() }}
{{ 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() %}
{{ method.method_body_indent() }}let buf = {{ method.sync_call_expr() }}
{{ method.method_body_indent() }}defer { {{ prefix }}_free_buf(buf) }
{%- if let Some(reader_expr) = method.returns.reader_decode_expr() %}
{%- if method.is_mutating() %}
{{ method.method_body_indent() }}self = boltffiDecodeOwnedBuf(buf.ptr, Int(buf.len)) { reader in {{ reader_expr }} }
{%- elif 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))
{%- if method.is_mutating() %}
{{ method.method_body_indent() }}self = {{ decode_expr }}
{%- else %}
{{ method.method_body_indent() }}return {{ decode_expr }}
{%- endif %}
{%- 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 %}
{{ method.method_body_indent() }}guard let ptr = {{ method.sync_call_expr() }} else { return nil }
{{ method.method_body_indent() }}return {{ class_name }}(handle: ptr)
{%- else %}
{{ method.method_body_indent() }}let ptr = {{ method.sync_call_expr() }}!
{{ method.method_body_indent() }}return {{ class_name }}(handle: ptr)
{%- endif %}
{%- elif let Some((protocol_name, nullable)) = method.returns.callback_info() %}
{{ method.method_body_indent() }}let callback = {{ method.sync_call_expr() }}
{%- if nullable %}
{{ method.method_body_indent() }}guard callback.handle != 0 else { return nil }
{%- endif %}
{{ method.method_body_indent() }}return {{ protocol_name }}Bridge.wrap(callback)
{%- elif method.returns.is_composite() %}
{%- if let Some(convert_expr) = method.returns.composite_convert_expr("_raw") %}
{{ method.method_body_indent() }}let _raw = {{ method.sync_call_expr() }}
{%- if method.is_mutating() %}
{{ method.method_body_indent() }}self = {{ convert_expr }}
{%- else %}
{{ method.method_body_indent() }}return {{ convert_expr }}
{%- endif %}
{%- endif %}
{%- elif method.returns.is_c_style_enum() %}
{{ method.method_body_indent() }}return {{ method.returns.c_style_enum_type().unwrap() }}(rawValue: {{ method.sync_call_expr() }})!
{%- else %}
{{ method.method_body_indent() }}return {{ method.sync_call_expr() }}
{%- 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 }}() -> _Concurrency.AsyncStream<{{ stream.item_type }}> {
_Concurrency.AsyncStream<{{ stream.item_type }}>(bufferingPolicy: .unbounded) { continuation in
guard let subscription = {{ stream.subscribe }}(self.handle) else {
continuation.finish()
return
}
let context = WireStreamContextBase(
subscription: subscription, batchSize: 16,
drainAvailableItems: { subscription, batchSize in
{%- match stream.item_delivery %}
{%- when SwiftStreamItemDelivery::WireEncoded { .. } %}
boltffiDrainWireStreamBatch(
subscription: subscription,
batchSize: batchSize,
popBatch: {{ stream.pop_batch }},
freeBuf: {{ stream.free_buf }}
) { reader in
let count = Int(reader.readU32())
for _ in 0..<count {
let item = {{ stream.item_delivery.reader_decode_expr().unwrap() }}
_ = continuation.yield(item)
}
}
{%- when SwiftStreamItemDelivery::Direct { c_element_type, .. } %}
boltffiDrainDirectStreamBatch(
subscription: subscription,
batchSize: batchSize,
popBatch: {{ stream.pop_batch }}
) { rawItems in
for rawItem in rawItems {
let item = {{ stream.item_delivery.direct_item_expr("rawItem").unwrap() }}
_ = continuation.yield(item)
}
}
{%- endmatch %}
},
poll: {{ stream.poll }},
unsubscribe: {{ stream.unsubscribe }},
freeFn: {{ stream.free }},
atomicCas: {{ stream.atomic_cas }},
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),
readBatch: { subscription, batchSize in
{%- match stream.item_delivery %}
{%- when SwiftStreamItemDelivery::WireEncoded { .. } %}
boltffiReadWireStreamBatch(
subscription: subscription,
batchSize: batchSize,
popBatch: {{ stream.pop_batch }},
freeBuf: {{ stream.free_buf }}
) { reader in
let count = Int(reader.readU32())
var result: [{{ stream.item_type }}] = []
result.reserveCapacity(count)
for _ in 0..<count {
let item = {{ stream.item_delivery.reader_decode_expr().unwrap() }}
result.append(item)
}
return result
}
{%- when SwiftStreamItemDelivery::Direct { c_element_type, .. } %}
return boltffiReadDirectStreamBatch(
subscription: subscription,
batchSize: batchSize,
popBatch: {{ stream.pop_batch }}
) { rawItems in
rawItems.map { rawItem in
{{ stream.item_delivery.direct_item_expr("rawItem").unwrap() }}
}
}
{%- endmatch %}
},
wait: {{ stream.wait }},
unsubscribe: {{ stream.unsubscribe }},
freeFn: {{ stream.free }}
)
}
{%- 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 drainAvailableItems: (SubscriptionHandle, UInt) -> Bool
let unsubscribe: (SubscriptionHandle?) -> Void
let freeFn: (SubscriptionHandle?) -> 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,
drainAvailableItems: @escaping (SubscriptionHandle, UInt) -> Bool,
poll: @escaping (SubscriptionHandle?, UInt64, StreamContinuationCallback?) -> Void,
unsubscribe: @escaping (SubscriptionHandle?) -> Void,
freeFn: @escaping (SubscriptionHandle?) -> Void,
atomicCas: @escaping (UnsafeMutablePointer<UInt8>?, UInt8, UInt8) -> Bool,
callback: @escaping ({{ stream.item_type }}) -> Void
) {
self.subscription = subscription; self.batchSize = batchSize
self.drainAvailableItems = drainAvailableItems; self.unsubscribe = unsubscribe
self.freeFn = freeFn; 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() { _Concurrency.Task { [self] in await _Concurrency.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 drainAvailableItems(subscription, batchSize) {}
if isClosed { requestTermination(); return }
guard (withUnsafeMutablePointer(to: &lifecycleTag) { atomicCas($0, 0, 0) }) else { return }
schedulePoll()
}
}
let context = CallbackContext(
subscription: subscription, batchSize: 16,
drainAvailableItems: { subscription, batchSize in
{%- match stream.item_delivery %}
{%- when SwiftStreamItemDelivery::WireEncoded { .. } %}
boltffiDrainWireStreamBatch(
subscription: subscription,
batchSize: batchSize,
popBatch: {{ stream.pop_batch }},
freeBuf: {{ stream.free_buf }}
) { reader in
let count = Int(reader.readU32())
for _ in 0..<count {
let item = {{ stream.item_delivery.reader_decode_expr().unwrap() }}
callback(item)
}
}
{%- when SwiftStreamItemDelivery::Direct { c_element_type, .. } %}
boltffiDrainDirectStreamBatch(
subscription: subscription,
batchSize: batchSize,
popBatch: {{ stream.pop_batch }}
) { rawItems in
for rawItem in rawItems {
let item = {{ stream.item_delivery.direct_item_expr("rawItem").unwrap() }}
callback(item)
}
}
{%- endmatch %}
},
poll: {{ stream.poll }},
unsubscribe: {{ stream.unsubscribe }},
freeFn: {{ stream.free }},
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 readBatchFn: (SubscriptionHandle, UInt) -> [{{ stream.item_type }}]
private let waitFn: (SubscriptionHandle, UInt32) -> Int32
private let unsubscribeFn: (SubscriptionHandle?) -> Void
private let freeFn: (SubscriptionHandle?) -> Void
private var isUnsubscribed = false
init(
handle: SubscriptionHandle?,
readBatch: @escaping (SubscriptionHandle, UInt) -> [{{ stream.item_type }}],
wait: @escaping (SubscriptionHandle, UInt32) -> Int32,
unsubscribe: @escaping (SubscriptionHandle?) -> Void,
freeFn: @escaping (SubscriptionHandle?) -> Void
) {
self.handle = handle
self.readBatchFn = readBatch
self.waitFn = wait
self.unsubscribeFn = unsubscribe
self.freeFn = freeFn
}
deinit {
freeFn(handle)
}
public func popBatch(maxCount: UInt = 16) -> [{{ stream.item_type }}] {
guard let h = handle else { return [] }
return readBatchFn(h, maxCount)
}
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 %}