Expanding on using Unmanaged, you can write a wrapper that bundles up a Swift closure as your context object and executes it on the event loop, which will let you use normal closure capture rules with the C API:
extension EventLoop {
func addTask(task: @escaping () -> Void) {
class Context {
let task: () -> Void
init(task: @escaping () -> Void) {
self.task = task
}
}
let context = Context(task: task)
EventLoopAddTask(self, Unmanaged.passRetained(context).toOpaque()) { ptr in
let local = Unmanaged<Context>.fromOpaque(ptr!).takeRetainedValue()
local.task()
}
}
}
You can use it with normal captures like this:
let name = "Jayson"
eventLoop.addTask {
print("ran task with \(name) via Swift closure")
}
I uploaded a demo here:
(Don't judge the EventLoop implementation, I just wanted to quickly throw together a representative example)