How to convert Data to UnsafeMutablePointer<UInt8>?

I am working on a mixed project with swift and C.

I use modulemap,so I can use C in swift.

The C code is like

int write_message_data(model_struct *model, unsigned char *message_data,
                            int message_data_size)

which convert to swift is

public func write_message_data(_ model: UnsafeMutablePointer<model_struct>!, _ message_data: UnsafeMutablePointer<UInt8>!, _ message_data_size: Int32) -> Int32

Then I need to use a Data produced by the protobuf,set it as message_data.
But I can not convert this Data to UnsafeMutablePointer!

I just want Data's pointer and fits the type.

The easiest way to solve this problem is to change your C code to use void * for this untyped memory. For example:

// Assuming this new C declaration:

int write_message_data2(
    model_struct *model,
    void * message_data,
    size_t message_data_size
);

// here’s how to call it from Swift:

var d: Data = …
let result = d.withUnsafeMutableBytes { buf in
    write_message_data2(model, buf.baseAddress!, buf.count)
}

Note that the force unwrap is safe as long as d is not empty.

If you can’t do that then you need some type conversions:

let result = d.withUnsafeMutableBytes { buf in
    write_message_data(model, buf.baseAddress!.assumingMemoryBound(to: UInt8.self), Int32(buf.count))
}

Two things to note here:

  • assumingMemoryBound(to:) is kinda suspect in general but it’s justified here because the data isn’t an array of UInt8 but rather untyped memory.

  • The conversion to Int32 could trap, which is why my first example used size_t.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

2 Likes