Passing a pointer to self to C function


(John Brownie) #1

Still working on the expat wrapper. The thing I need to do is to pass a pointer to self to be stored in the userData that will be passed to callbacks, allowing me to get at the local instance. I did this in Swift 2.2 as:

XML_SetUserData(parser, unsafeBitCast(self, UnsafeMutablePointer<Void>.self))

The migrator turned this into:

XML_SetUserData(parser, unsafeBitCast(self, to: UnsafeMutableRawPointer.self))

but it doesn't work. I don't get an appropriate pointer back in the callback that I can turn into what I need.

From reading the migration documentation, I don't want to use unsafeBitCast if at all possible, but I'm not clear what the alternative is.

Also, getting the userData back is something I will need. I currently use:

let theParser = userData!.bindMemory(to: ExpatSwift.self, capacity: 1)

I think that's correct, but I'm not getting a valid object reference.

Any insight is greatly appreciated!

···

--
John Brownie
In Finland on furlough from SIL Papua New Guinea


(Michael Ferenduros) #2

The way to do this is via Unmanaged:
    let raw = Unmanaged.passUnretained(expat).toOpaque()
gets you an UnsafeMutableRawPointer you can pass into C functions. You can
turn this back into an ExpatSwift with
    let expat = Unmanaged<ExpatSwift>.fromOpaque(raw).takeUnretainedValue()

There are also retained variants that will add or remove a reference to the
object in question.
Basically, if you know that the pointer won't outlive the thing it
references, you want the unretained variants. This is usually what you want
when you're wrapping C APIs with callbacks, especially if callbacks happen
synchronously.

On the other hand, if the pointer lives independently of the Whatever then
you may want to
- create the pointer with passRetained(), which will keep the object it
points to alive
- access the object with take*Un*retainedValue() (so you don't prematurely
release your reference to it), and
- call release() on it when you're done with it.
If you forget the 3rd step then you're leaking memory, and if you
miscalculate and do it twice then you crash.

Or if you're just passing a pointer from A to B one time, you can use
passRetained() + takeRetainedValue().

Hope that helps
Mike

···

On Fri, 30 Sep 2016 at 13:11 John Brownie via swift-users < swift-users@swift.org> wrote:

Still working on the expat wrapper. The thing I need to do is to pass a
pointer to self to be stored in the userData that will be passed to
callbacks, allowing me to get at the local instance. I did this in Swift
2.2 as:

XML_SetUserData(parser, unsafeBitCast(self,
UnsafeMutablePointer<Void>.self))

The migrator turned this into:

XML_SetUserData(parser, unsafeBitCast(self, to:
UnsafeMutableRawPointer.self))

but it doesn't work. I don't get an appropriate pointer back in the
callback that I can turn into what I need.

>From reading the migration documentation, I don't want to use
unsafeBitCast if at all possible, but I'm not clear what the alternative is.

Also, getting the userData back is something I will need. I currently use:

let theParser = userData!.bindMemory(to: ExpatSwift.self, capacity: 1)

I think that's correct, but I'm not getting a valid object reference.

Any insight is greatly appreciated!
--
John Brownie
In Finland on furlough from SIL Papua New Guinea
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(John Brownie) #3

Thanks! That works just as it should. It's all compiling and unit tests are passing, so I can move on now.

···

Mike Ferenduros <mailto:mike.ferenduros@gmail.com>
30 September 2016 at 14:14
The way to do this is via Unmanaged:
    let raw = Unmanaged.passUnretained(expat).toOpaque()
gets you an UnsafeMutableRawPointer you can pass into C functions. You can turn this back into an ExpatSwift with
    let expat = Unmanaged<ExpatSwift>.fromOpaque(raw).takeUnretainedValue()

There are also retained variants that will add or remove a reference to the object in question.
Basically, if you know that the pointer won't outlive the thing it references, you want the unretained variants. This is usually what you want when you're wrapping C APIs with callbacks, especially if callbacks happen synchronously.

On the other hand, if the pointer lives independently of the Whatever then you may want to
- create the pointer with passRetained(), which will keep the object it points to alive
- access the object with take*Un*retainedValue() (so you don't prematurely release your reference to it), and
- call release() on it when you're done with it.
If you forget the 3rd step then you're leaking memory, and if you miscalculate and do it twice then you crash.

Or if you're just passing a pointer from A to B one time, you can use passRetained() + takeRetainedValue().

--
John Brownie
In Finland on furlough from SIL Papua New Guinea