// Generated by nim-ffi Swift codegen. Do not edit by hand. // // Idiomatic Swift wrapper over the library's native (zero-serialization) C ABI. // Each call is dispatched on the library's background FFI thread; we block on a // DispatchSemaphore until the result callback fires. A struct return is read out // of the typed C-POD inside the callback — valid only for the callback's // lifetime — and copied into a native Swift value. import CMyTimer import Foundation public enum TimerError: Error, CustomStringConvertible { case failed(String) public var description: String { switch self { case let .failed(m): return m } } } public struct EchoResponse: Equatable { public let echoed: String public let timerName: String } public final class MyTimerNode { private let ctx: UnsafeMutableRawPointer public init(name: String) throws { let box = Box() let ud = Unmanaged.passUnretained(box).toOpaque() var c_config = CMyTimer.TimerConfig() let c_config_name = strdup(name) defer { free(c_config_name) } c_config.name = UnsafePointer(c_config_name) guard let c = my_timer_create(c_config, ackCallback, ud) else { throw TimerError.failed("create returned null") } box.sem.wait() guard box.ret == 0 else { throw TimerError.failed(box.text) } ctx = c } public func echo(_ message: String, delayMs: Int = 0) throws -> EchoResponse { let box = MyTimerEchoBox() let ud = Unmanaged.passUnretained(box).toOpaque() var c_req = CMyTimer.EchoRequest() let c_req_message = strdup(message) defer { free(c_req_message) } c_req.message = UnsafePointer(c_req_message) c_req.delayMs = Int64(delayMs) guard my_timer_echo(ctx, my_timer_echoCallback, ud, c_req) == 0 else { throw TimerError.failed("echo dispatch failed") } box.sem.wait() guard box.ret == 0 else { throw TimerError.failed(box.text) } return EchoResponse(echoed: box.echoed, timerName: box.timerName) } public func version() throws -> String { let box = Box() let ud = Unmanaged.passUnretained(box).toOpaque() guard my_timer_version(ctx, stringCallback, ud) == 0 else { throw TimerError.failed("version dispatch failed") } box.sem.wait() guard box.ret == 0 else { throw TimerError.failed(box.text) } return box.text } deinit { my_timer_destroy(ctx) } } // MARK: - shared callback plumbing final class Box { var ret: Int32 = -1 var text = "" let sem = DispatchSemaphore(value: 0) } func rawText(_ msg: UnsafePointer?, _ len: Int) -> String { guard let m = msg, len > 0 else { return "" } let bytes = UnsafeRawPointer(m).assumingMemoryBound(to: UInt8.self) return String(decoding: UnsafeBufferPointer(start: bytes, count: len), as: UTF8.self) } func ackCallback(_ ret: Int32, _ msg: UnsafePointer?, _ len: Int, _ ud: UnsafeMutableRawPointer?) { let box = Unmanaged.fromOpaque(ud!).takeUnretainedValue() box.ret = ret if ret != 0 { box.text = rawText(msg, len) } box.sem.signal() } func stringCallback(_ ret: Int32, _ msg: UnsafePointer?, _ len: Int, _ ud: UnsafeMutableRawPointer?) { let box = Unmanaged.fromOpaque(ud!).takeUnretainedValue() box.ret = ret box.text = rawText(msg, len) box.sem.signal() } final class MyTimerEchoBox { var ret: Int32 = -1 var text = "" var echoed = "" var timerName = "" let sem = DispatchSemaphore(value: 0) } private func my_timer_echoCallback(_ ret: Int32, _ msg: UnsafePointer?, _ len: Int, _ ud: UnsafeMutableRawPointer?) { let box = Unmanaged.fromOpaque(ud!).takeUnretainedValue() box.ret = ret if ret == 0, let m = msg { let resp = UnsafeRawPointer(m).assumingMemoryBound(to: CMyTimer.EchoResponse.self) box.echoed = resp.pointee.echoed.map { String(cString: $0) } ?? "" box.timerName = resp.pointee.timerName.map { String(cString: $0) } ?? "" } else { box.text = rawText(msg, len) } box.sem.signal() }