Wrapping C callbacks in Swift closures

What's the dirty way? As andyliu already shown?

ps: an interesting link

but I keep getting:

I don’t have time to read through all the gory details of this thread right now (sorry!) but I think this DevForums post has what you need.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

1 Like

Hi @eskimo,

I like reading this:

I was intrigued by your question because I often end up using low-level APIs that have C callbacks.

because then you may have already the solution

The post you suggested doesnt seem to work for my case though:

public class glfw {
   typealias ErrorFun = (Error, _ description: String) -> Void
   static func setErrorCallback(cbFun: ErrorFun) {
      withUnsafePointer(to: &self) { // error: cannot pass immutable value as inout argument: 'self' is immutable
         ..
      }
   }
}

No problem, I'll be more than happy to summarize it for you:
wrapping Swift capturing Closures around C Callbacks, which have no context parameter.

this seems to work

public struct glfw {
    static func setErrorCallback(cbFun: @escaping ErrorFun) {
        _g.errorCB = cbFun
        glfwSetErrorCallback { err, desc in
            _g.errorCB!(Error(rawValue: err)!, String(utf8String: desc!)!)
        }        
    }
    var errorCB: ErrorFun?
}
var _g = glfw()
1 Like

which have no context parameter

Ah, that’s the bit I missed. Thanks for summarising!

Converting from a callback without a context parameter to a callback with one (which is equivalent to a Swift closure) is messy. There’s only two options I can think of:

  • Using a global variable, which is what you’re doing here

  • Using thread-local storage

Given that the error callback is a global anyway, using a global variable is probably the best option.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

Performance-wise, what's the best option?

A global.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

1 Like