Confusing pointer conversion

I've tried to follow to shifting model of pointers in Swift (I understand it's for the best)… but now I'm completly lost.


How would I cast/convert a `sockaddr_in6` to an `UnsafePointer<sockaddr>!` type?


var s = sockaddr_in6()
// ... assign values members/properties of `s`

var fileDescriptor = socket(socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)
// ... handle errors

Darwin.bind(fileDescriptor, &s ,socklen_t(MemoryLayout<sockaddr_in6>.size))
//                          ^^ ###### can't convert sockaddr_in6 to sockaddr



I've tried many things without success (withUnsafePointer(…), OpaquePointers<T>, etc.).


My (current) understanding is that I would need to go from:

sockaddr_in6 ⇒ UnsafePointer<sockaddr_in6> ⇒ UnsafePointer<sockaddr>!


But there doesn't seem to be anyway to cast UnsafePointer between themselves. I'm sure there's a logical reason somehwere but it eludes me.


Thank you!

Accepted Reply

Re-read documentation I had initially misunderstood. Had misread UnsafePointer's `withMemoryRebound<U>()`.


var s = sockaddr_in6();
// ...

withUnsafePointer(to: &s) {
    (p1: UnsafePointer<sockaddr_in6>) in
    p1.withMemoryRebound(to: sockaddr.self, capacity: 1) {
        (p2: UnsafeMutablePointer<sockaddr>) in
        bind(fileDescriptor, p2, /*....*/ )
    }
}

Replies

The above example shows how to use UnsafeRawPointer instead of UnsafePointer<UInt8> for dataBuffer.

This is great, thanks hawkart.

I was kinda wondering about using the pointer directly, rather than the buffer. Will look it over in more detail.


cheers,


J.

Sorry, I can't get the forum to take my full messages.


Viewing the data as bytes is a little cumbersome, but there's a language proposal being discussed to make this case more convenient. Until then, if you really want to view dataBuffer as a UInt8 array (or have code compatibility constraints), you could do this instead:


func withMIDIDataOfType<T>(for eventPtr: UnsafePointer<MIDIMetaEvent>, body: (_ data: UnsafeRawPointer) throws -> T) rethrows -> T {
    let dataLength = Int(eventPtr.pointee.dataLength)
    let bytesBuffer = UnsafeRawPointer(eventPtr) + OffsetOfDataInMIDIMetaEvent
    return try body(bytesBuffer.bindMemory(to: UInt8.self, capacity: dataLength)
}
...
  case 0x58:
      withMIDIDataOfType(for: meta!, body: { dataBuffer in
          var ts_num: Int = 4
          var ts_denom: Int = 4
          ts_num = Int(dataBuffer[0])
          let pow = Float(dataBuffer[1])


It's fine to call bindMemory(to:capacity:) as long as the memory will continue to be viewed as that type until the next call to bindMemory.


Incidentally, one thing confused me in the migrated code... bindMemory(to: MIDIMetaEvent.self, capacity: 8) indicates that 8 MIDIDataEvents are laid out contiguously in memory. I don't think that was the intention.

Quite right. Thankfully, someone straightened out my misunderstanding about "capacity" over on Stack Overflow, so the version I'm using is different now (just says "1" for capacity). Thanks for pointing it out though!