How do you convert a uuid_t tuple to an UnsafeMutablePointer<UInt8>?

In Swift, a uuid_t is defined as a tuple of 16 UInt8 elements. How do I get an UnsafePointer to that tuple to pass to an Objective-C class?

The Objective-C class is defined as follows:

@interface Writer

- (void)writeUUID:(_Nonnull uuid_t)value;

@end

The auto-generated Swift 5 interface is defined as follows:

open class Writer : NSObject {   
  open func writeUUID(_ value: UnsafeMutablePointer<UInt8>)
}

Example of trying to create a UUID and then passing its uuid_t to an Objective-C class:

let uuid = UUID().uuid

// Error: Cannot convert value of type 'UnsafeMutablePointer<_>' 
// to expected argument type 'UnsafeMutablePointer<UInt8>'
withUnsafeMutablePointer(to:u) {
  encoder.writeUUID($0)
}

// Error: Cannot convert value of type '(UnsafeMutablePointer<UInt8>) -> Void' 
// to expected argument type '(UnsafeMutablePointer<_>) -> _'
withUnsafeMutablePointer(to:u) { (ptr:UnsafeMutablePointer<UInt8>) in
  encoder.writeUUID(ptr)
}

How can I pass a uuid_t from Swift to Objective-C and back?

I'm prettty sure this is safe, though admittedly I'm never 100% certain when to use withMemoryRebound(to:) and friends. @Andrew_Trick can probably confirm or deny:

import Foundation

var uuid = UUID().uuid

withUnsafeMutablePointer(to: &uuid) { tuplePointer in
 tuplePointer.withMemoryRebound(to: UInt8.self, capacity: 1) { pointer in
   uuid_generate(pointer)
 }
}

(I used uuid_generate in my example instead of your Obj-C API in order to have a self-contained example for testing.)

Unfortunately, withMemoryRebound(to:) requires that the pointer's Pointee and the destination type be the same size, which doesn't work with this tuple -> element conversion. I think you need to round-trip through UnsafeRawPointer(tuplePointer).assumingMemoryBound(to: UInt8.self) in this case.

1 Like

That’s unnecessary: we can use withUnsafeBytes(of:) instead of withUnsafePointer(to:).

import Foundation

var uuid = UUID().uuid

withUnsafeBytesOf(of: &uuid) { pointer in
  uuid_generate(pointer.baseAddress)
}

If it is truly necessary to get UnsafePointer<UInt8> instead of UnsafeRawPointer (and I strongly recommend trying with the raw pointer first), then you can safely use assumingMemoryBound here. This is more or less the only case where it’s safe: the memory is already UInt8s, so you aren’t violating the aliasing rules by accessing it that way.

1 Like

@nnnnnnnn @lukasa Thanks for correcting me. UnsafeRawPointer doesn't match the API @kennyc is trying to call (or uuid_generate), so a working solution would be this:

import Foundation

var uuid = UUID().uuid

withUnsafeMutableBytes(of: &uuid) { rawPointer in
  // Force unwrap is safe because we know rawPointer.count > 0
  let typedPointer = rawPointer.baseAddress!.assumingMemoryBound(to: UInt8.self)
  uuid_generate(typedPointer)
}
1 Like
Terms of Service

Privacy Policy

Cookie Policy