Struct to Data and backwards

I need to use a struct to implement some network protocol.
I need to send the struct as a byte stream and when I receive a reply to convert it back to the struct.

Currently, I am using these encode and decode functions:

func encode( value: T) -> NSData {
return withUnsafePointer(to:value) { p in
NSData(bytes: p, length: MemoryLayout.size(ofValue:value))
}
}

func decode<T>(data: NSData) -> T {
    let pointer = UnsafeMutablePointer<T>.allocate(capacity: MemoryLayout.size(ofValue:T.self))
    data.getBytes(pointer)
    
    return pointer.move()
}

The struct which I need to convert looks like this:

struct start_ctrl_conn {
var header:header;
var version:UInt16;
var reserved:UInt8;
var framing_cap:UInt32;
var bearer_cap:UInt32;
var max_channels:UInt16;
var firmware_rev:UInt16; */
var hostname = Array.init(repeating: UInt8(0), count: 64);
var vendor = Array.init(repeating: UInt8(0), count: 64);

};

struct header {
var length:UInt16
var pptp_type:UInt16
var magic:UInt32
var ctrl_type:UInt16
var reserved0:UInt16
}

This doesn't seem to work.
The memory layout size give 48 bytes no matter what, although there at least 156 bytes.

Is there a simple way to encode and decode to struct to byets an visa versa?,
what am I doing wrong?

Cheers

I guess the arrays are the problem; sadly, the usual workaround is a tuple with 64 elements...:frowning:

Do you have a link or code snippet example how to implement this ?

Swift does not make any guarantees about the layout of objects; you should define your data-type in C and import it in to Swift (see any of the SwiftPM tutorials about C interop).

And yes, Swift Arrays are dynamically-resizable (analogous to std::vector), so they are actually wrapped pointers to (generally) heap-allocated storage.

1 Like

Thank you Karl.
Should I do it like this:

https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/using_imported_c_structs_and_unions_in_swift

I think you should use the Codable system, using a custom encoder/decoder that writes/reads byte to/from a Data. That way you can make your layout explicit, rather than piggy backing off of the unfixed layout that the compiler comes up for you.

Yes.

The easiest way to get a small C module building and all the correct paths sent to your Swift module is via SwiftPM. It will automatically detect a C library target, and your Swift module can depend on it and use the type defined there.