Updating C-wrapper to Swift 3


(John Brownie) #1

I have a Swift wrapper for the expat XML parser, and I just went through the update to Swift 3, and I'm thrown a series of errors that mostly appear to be of two types. Here is a representative function of the first type:

     func parse() throws {
         var done = false
         while !done {
             let buffer: UnsafeMutablePointer<Void> = XML_GetBuffer(parser, Int32(bufsize))
             if buffer == nil {
                 let errorCode = XML_GetErrorCode(parser)
                 throw ExpatError(reason: "Error \(errorCode), \(XML_ErrorString(errorCode))")
             }
             let bytesRead = readData(UnsafeMutablePointer<UInt8>(buffer), bufferLength: bufsize)
             done = bytesRead < bufsize
             if XML_ParseBuffer(parser, Int32(bytesRead), Int32(done ? 1 : 0)) != XML_STATUS_OK {
                 let errorCode = XML_GetErrorCode(parser)
                 throw ExpatError(reason: "Error \(errorCode), \(XML_ErrorString(errorCode))")
             }
         }
     }

Xcode 8's migrator changed the declaration of buffer to UnsafeMutableRawPointer?, but the readData call gives an error:

Cannot invoke initializer for type 'UnsafeMutablePointer<UInt8>' with an argument list of type '(UnsafeMutableRawPointer?)'
Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type.
Overloads for 'UnsafeMutablePointer<UInt8>' exist with these partially matching parameter lists: (RawPointer), (OpaquePointer), (OpaquePointer?), (UnsafeMutablePointer<Pointee>), (UnsafeMutablePointer<Pointee>?)

Where can I read up on how to make the conversion? My initial effort is:

             let bytesRead = readData(buffer!.bindMemory(to: UInt8.self, capacity: bufsize), bufferLength: bufsize)

That's more or less thrashing around with no real understanding.

The second type is turning a closure into the appropriate C function pointer. For example:

             XML_SetEndElementHandler(parser) { (userData: UnsafeMutableRawPointer, name: UnsafePointer<XML_Char>) -> Void in
                 let theParser = unsafeBitCast(userData, to: ExpatSwift.self)
                 let theName = ExpatSwift.getString(name)
                 theParser.endElement(theName)
             }

This gets an error:

Cannot convert value of type '(UnsafeMutableRawPointer, UnsafePointer<XML_Char>) -> Void' to expected argument type 'XML_EndElementHandler!'

XML_EndElementHandler is defined as:

typedef void (XMLCALL *XML_EndElementHandler) (void *userData,
                                                const XML_Char *name);

Here I have no real clue as to how to fix it.

So, any pointers to either how to fix these problems or to a good source to read to understand them?

John

···

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


(Quinn “The Eskimo!”) #2

I recommend reading the whole “Migrating to Swift 2.3 or Swift 3 from Swift 2.2” doc, but for this specific issue you should start with the “UnsafeRawPointer Migration” doc that it links to.

<https://swift.org/migration-guide/>

<https://swift.org/migration-guide/se-0107-migrate.html>

Share and Enjoy

···

On 28 Sep 2016, at 07:29, John Brownie via swift-users <swift-users@swift.org> wrote:

Where can I read up on how to make the conversion?

--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware


(John Brownie) #3

Thanks for the pointers. Good reading, but I'm still confused. I think that the first issue is clear to me now, but I don't know what I have to do to make the closure be seen as satisfying the type of the function pointer. It worked in Swift 2.2 as

             XML_SetEndElementHandler(parser) { (userData: UnsafeMutablePointer<Void>, name: UnsafePointer<XML_Char>) -> Void in

All that's changed is making the UnsafeMutablePointer<Void> into UnsafeMutableRawPointer, unless it's the unwrapped nature of the parameter in the error message:

Cannot convert value of type '(UnsafeMutableRawPointer, UnsafePointer<XML_Char>) -> Void' to expected argument type 'XML_EndElementHandler!'

I don't know what I need to do next. Any help is much appreciated.

···

Quinn "The Eskimo!" via swift-users <mailto:swift-users@swift.org>
28 September 2016 at 11:26

I recommend reading the whole “Migrating to Swift 2.3 or Swift 3 from Swift 2.2” doc, but for this specific issue you should start with the “UnsafeRawPointer Migration” doc that it links to.

<https://swift.org/migration-guide/>

<https://swift.org/migration-guide/se-0107-migrate.html>

Share and Enjoy
--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users
John Brownie <mailto:john_brownie@sil.org>
28 September 2016 at 9:29
I have a Swift wrapper for the expat XML parser, and I just went through the update to Swift 3, and I'm thrown a series of errors that mostly appear to be of two types. Here is a representative function of the first type:

    func parse() throws {
        var done = false
        while !done {
            let buffer: UnsafeMutablePointer<Void> = XML_GetBuffer(parser, Int32(bufsize))
            if buffer == nil {
                let errorCode = XML_GetErrorCode(parser)
                throw ExpatError(reason: "Error \(errorCode), \(XML_ErrorString(errorCode))")
            }
            let bytesRead = readData(UnsafeMutablePointer<UInt8>(buffer), bufferLength: bufsize)
            done = bytesRead < bufsize
            if XML_ParseBuffer(parser, Int32(bytesRead), Int32(done ? 1 : 0)) != XML_STATUS_OK {
                let errorCode = XML_GetErrorCode(parser)
                throw ExpatError(reason: "Error \(errorCode), \(XML_ErrorString(errorCode))")
            }
        }
    }

Xcode 8's migrator changed the declaration of buffer to UnsafeMutableRawPointer?, but the readData call gives an error:

Cannot invoke initializer for type 'UnsafeMutablePointer<UInt8>' with an argument list of type '(UnsafeMutableRawPointer?)'
Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type.
Overloads for 'UnsafeMutablePointer<UInt8>' exist with these partially matching parameter lists: (RawPointer), (OpaquePointer), (OpaquePointer?), (UnsafeMutablePointer<Pointee>), (UnsafeMutablePointer<Pointee>?)

Where can I read up on how to make the conversion? My initial effort is:

            let bytesRead = readData(buffer!.bindMemory(to: UInt8.self, capacity: bufsize), bufferLength: bufsize)

That's more or less thrashing around with no real understanding.

The second type is turning a closure into the appropriate C function pointer. For example:

            XML_SetEndElementHandler(parser) { (userData: UnsafeMutableRawPointer, name: UnsafePointer<XML_Char>) -> Void in
                let theParser = unsafeBitCast(userData, to: ExpatSwift.self)
                let theName = ExpatSwift.getString(name)
                theParser.endElement(theName)
            }

This gets an error:

Cannot convert value of type '(UnsafeMutableRawPointer, UnsafePointer<XML_Char>) -> Void' to expected argument type 'XML_EndElementHandler!'

XML_EndElementHandler is defined as:

typedef void (XMLCALL *XML_EndElementHandler) (void *userData,
                                               const XML_Char *name);

Here I have no real clue as to how to fix it.

So, any pointers to either how to fix these problems or to a good source to read to understand them?

John

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


(Michael Ilseman) #4

Thanks for the pointers. Good reading, but I'm still confused. I think that the first issue is clear to me now, but I don't know what I have to do to make the closure be seen as satisfying the type of the function pointer. It worked in Swift 2.2 as

            XML_SetEndElementHandler(parser) { (userData: UnsafeMutablePointer<Void>, name: UnsafePointer<XML_Char>) -> Void in

All that's changed is making the UnsafeMutablePointer<Void> into UnsafeMutableRawPointer, unless it's the unwrapped nature of the parameter in the error message:

Cannot convert value of type '(UnsafeMutableRawPointer, UnsafePointer<XML_Char>) -> Void' to expected argument type 'XML_EndElementHandler!'

I don't know what I need to do next. Any help is much appreciated.

Could you share the generated interface for these functions, so that we can see how they are being imported into Swift? Also, do you know exactly what version of the Swift compiler you’re using (I ask because there have been recent improvements in error messages)?

···

On Sep 28, 2016, at 10:03 AM, John Brownie via swift-users <swift-users@swift.org> wrote:

Quinn "The Eskimo!" via swift-users <mailto:swift-users@swift.org> 28 September 2016 at 11:26

I recommend reading the whole “Migrating to Swift 2.3 or Swift 3 from Swift 2.2” doc, but for this specific issue you should start with the “UnsafeRawPointer Migration” doc that it links to.

<https://swift.org/migration-guide/> <https://swift.org/migration-guide/>

<https://swift.org/migration-guide/se-0107-migrate.html> <https://swift.org/migration-guide/se-0107-migrate.html>

Share and Enjoy
--
Quinn "The Eskimo!" <http://www.apple.com/developer/> <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users
John Brownie <mailto:john_brownie@sil.org> 28 September 2016 at 9:29
I have a Swift wrapper for the expat XML parser, and I just went through the update to Swift 3, and I'm thrown a series of errors that mostly appear to be of two types. Here is a representative function of the first type:

    func parse() throws {
        var done = false
        while !done {
            let buffer: UnsafeMutablePointer<Void> = XML_GetBuffer(parser, Int32(bufsize))
            if buffer == nil {
                let errorCode = XML_GetErrorCode(parser)
                throw ExpatError(reason: "Error \(errorCode), \(XML_ErrorString(errorCode))")
            }
            let bytesRead = readData(UnsafeMutablePointer<UInt8>(buffer), bufferLength: bufsize)
            done = bytesRead < bufsize
            if XML_ParseBuffer(parser, Int32(bytesRead), Int32(done ? 1 : 0)) != XML_STATUS_OK {
                let errorCode = XML_GetErrorCode(parser)
                throw ExpatError(reason: "Error \(errorCode), \(XML_ErrorString(errorCode))")
            }
        }
    }

Xcode 8's migrator changed the declaration of buffer to UnsafeMutableRawPointer?, but the readData call gives an error:

Cannot invoke initializer for type 'UnsafeMutablePointer<UInt8>' with an argument list of type '(UnsafeMutableRawPointer?)'
Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type.
Overloads for 'UnsafeMutablePointer<UInt8>' exist with these partially matching parameter lists: (RawPointer), (OpaquePointer), (OpaquePointer?), (UnsafeMutablePointer<Pointee>), (UnsafeMutablePointer<Pointee>?)

Where can I read up on how to make the conversion? My initial effort is:

            let bytesRead = readData(buffer!.bindMemory(to: UInt8.self, capacity: bufsize), bufferLength: bufsize)

That's more or less thrashing around with no real understanding.

The second type is turning a closure into the appropriate C function pointer. For example:

            XML_SetEndElementHandler(parser) { (userData: UnsafeMutableRawPointer, name: UnsafePointer<XML_Char>) -> Void in
                let theParser = unsafeBitCast(userData, to: ExpatSwift.self)
                let theName = ExpatSwift.getString(name)
                theParser.endElement(theName)
            }

This gets an error:

Cannot convert value of type '(UnsafeMutableRawPointer, UnsafePointer<XML_Char>) -> Void' to expected argument type 'XML_EndElementHandler!'

XML_EndElementHandler is defined as:

typedef void (XMLCALL *XML_EndElementHandler) (void *userData,
                                               const XML_Char *name);

Here I have no real clue as to how to fix it.

So, any pointers to either how to fix these problems or to a good source to read to understand them?

John

--
John Brownie
In Finland on furlough from SIL Papua New Guinea
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users


(Quinn “The Eskimo!”) #5

Based on some random expat docs I found on the ’net [1], I grabbed the relevant declarations and put them in a bridging header.

···

On 28 Sep 2016, at 18:39, Michael Ilseman <milseman@apple.com> wrote:

Could you share the generated interface for these functions, so that we can see how they are being imported into Swift?

---------------------------------------------------------------------------
typedef struct XML_Parser_struct * XML_Parser;
typedef uint8_t XML_Char;

typedef void
(*XML_EndElementHandler)(void *userData,
                         const XML_Char *name);

void XML_SetEndElementHandler(XML_Parser p,
                         XML_EndElementHandler);
---------------------------------------------------------------------------

With that I see that XML_EndElementHandler has the signature:

typealias XML_EndElementHandler = (UnsafeMutableRawPointer?, UnsafePointer<XML_Char>?) -> Void

However, John is trying to use:

{ (userData: UnsafeMutableRawPointer, name: UnsafePointer<XML_Char>) -> Void in … }

where the parameters differ in optionality. The fix is to make both parameters optional:

{ (userData: UnsafeMutableRawPointer?, name: UnsafePointer<XML_Char>?) in … }

I belive this change is the result of:

* SE-0055 “Make unsafe pointer nullability explicit using Optional”

<https://github.com/apple/swift-evolution/blob/master/proposals/0055-optional-unsafe-pointers.md>

* SE-0054 “Abolish ImplicitlyUnwrappedOptional type”

<https://github.com/apple/swift-evolution/blob/master/proposals/0054-abolish-iuo.md>

Share and Enjoy
--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

[1] <http://www.hpc.wm.edu/SciClone/documentation/software/misc/expat/reference.html>