I am trying to wrap a C library in a Swift package. The library has a struct
that holds some function pointers. To expose a nicer interface I would like users to be able to pass normal Swift functions (i.e. not handling all the C oddities) and then create a thin wrapper around those functions that handles the type conversions etc.
Here's my approach so far:
public struct SwiftifiedLib {
public init(
callback: (Int) -> Void,
complexCallback: (Int, String, Int) -> Void
) {
// cLibStruct is defined in the wrapped C library
var structInstance = cLibStruct()
structInstance.callback = { (fd: Int32) -> Void in
callback(Int(fd))
}
structInstance.complexCallback = {
(fd: Int32, msg: UnsafePointer<UInt8>?, size: UInt64, type: Int32) -> Void in
let msgBuffer = UnsafeBufferPointer(start: msg, count: Int(size))
let msgString = String(decoding: msgBuffer, as: UTF8.self)
complexCallback(Int(fd), msgString, Int(type))
}
}
}
Compilation fails with
error: a C function pointer cannot be formed from a closure that captures context
structInstance.callback = { (fd: Int32) in
^
I understand that this is expected, given the way I am trying to pass the callback functions. However, I feel like this is a common enough use case for a workaround to exist.
Is there a pattern or construct/type cast/etc that allows me to break that dependency on the context?
I have also tried to use an instance function to wrap the argument and then make the instance function passable as described here but realised that this was just shifting the problem.