I decided to try this, since it seemed funny to me, so I came up with a solution for struct.pack(...) .
You can also apply the bit size for integers in your structure:
struct MyMessage { var version : UInt16 var length : UInt32 var reserved : UInt16 var data : UInt8[] }
Now on packed structures ...
Integer Extensions
extension Int { func loByte() -> UInt8 { return UInt8(self & 0xFF) } func hiByte() -> UInt8 { return UInt8((self >> 8) & 0xFF) } func loWord() -> Int16 { return Int16(self & 0xFFFF) } func hiWord() -> Int16 { return Int16((self >> 16) & 0xFFFF) } } extension Int16 { func loByte() -> UInt8 { return UInt8(self & 0xFF) } func hiByte() -> UInt8 { return UInt8((self >> 8) & 0xFF) } } extension UInt { func loByte() -> UInt8 { return UInt8(self & 0xFF) } func hiByte() -> UInt8 { return UInt8((self >> 8) & 0xFF) } func loWord() -> UInt16 { return UInt16(self & 0xFFFF) } func hiWord() -> UInt16 { return UInt16((self >> 16) & 0xFFFF) } } extension UInt16 { func loByte() -> UInt8 { return UInt8(self & 0xFF) } func hiByte() -> UInt8 { return UInt8((self >> 8) & 0xFF) } }
Data packer
class DataPacker { class func pack(format: String, values: AnyObject...) -> String? { var bytes = UInt8[]() var index = 0 for char in format { let value : AnyObject! = values[index++] switch(char) { case "h": bytes.append((value as Int).loByte()) bytes.append((value as Int).hiByte()) case "H": bytes.append((value as UInt).loByte()) bytes.append((value as UInt).hiByte()) case "i": bytes.append((value as Int).loWord().loByte()) bytes.append((value as Int).loWord().hiByte()) bytes.append((value as Int).hiWord().loByte()) bytes.append((value as Int).hiWord().hiByte()) case "I": bytes.append((value as UInt).loWord().loByte()) bytes.append((value as UInt).loWord().hiByte()) bytes.append((value as UInt).hiWord().loByte()) bytes.append((value as UInt).hiWord().hiByte()) default: println("Unrecognized character: \(char)") } } return String.stringWithBytes(bytes, length: bytes.count, encoding: NSASCIIStringEncoding) } }
To try
let packedString = DataPacker.pack("HHI", values: 0x100, 0x0, 512) println(packedString)
Notes
This example is extremely simple and has no real error or type checking. Furthermore, it does not actually use system byte order (endianness), so this can be problematic. Hope this will be the starting point for those interested.
For unpacking, I noticed that Swift allowed to return a tuple with a variable size. For example: func unpack(format: String) -> (AnyObject...) did not give a compilation warning. However, I have no idea how you will return something like that.
source share