-
Notifications
You must be signed in to change notification settings - Fork 0
Home
prcela edited this page May 24, 2016
·
8 revisions
Un/packing complex hierarchy with MessagePack serialization format.
This readme file is a small helper for using swift project a2/MessagePack.swift
For this concept let use a simple structure that is contained as array in parent structure.
struct Point {
var id: Int64
var x: Double
var y: double
init(id: Int64, x: Double, y: Double)
{
self.id = id
self.x = x
self.y = y
}
}
struct Triangle {
let id: Int64
let points: [Point]
init(id: Int64, points: [Point])
{
self.id = id
self.points = points
}
}
Define the packing behavior with following protocol:
protocol Packable
{
init(value:MessagePackValue)
func messagePackValue() -> MessagePackValue
}
Init function unpacks the native struct from a packed value, while the messagePackValue() packs the struct into packed value.
Extend the Point struct with Packable protocol:
struct Point: Packable {
...
init(value: MessagePackValue)
{
var gen = value.arrayValue!.generate()
id = gen.next()!.integerValue!
x = gen.next()!.doubleValue!
y = gen.next()!.doubleValue!
}
func messagePackValue() -> MessagePackValue
{
let value: MessagePackValue = [
MessagePackValue(id),
MessagePackValue(x),
MessagePackValue(y)
]
return value
}
}
Extend the Triangle struct with Packable protocol:
struct Triangle: Packable {
let id: Int64
let points: [Point]
...
init(value: MessagePackValue)
{
var gen = value.arrayValue!.generate()
id = gen.next()!.integerValue!
points = gen.next()!.arrayValue!.map { (value) -> Point in
return Point(value: value)
}
}
func messagePackValue() -> MessagePackValue
{
let value: MessagePackValue = [
MessagePackValue(id),
MessagePackValue(points.map { (p) -> MessagePackValue in
return p.messagePackValue()
})
]
return value
}
}
Now lets pack some triangle struct into data:
let p0 = Point(id: 1, x: 2, y: 3)
let p1 = Point(id: 2, x: 5, y: 6)
let p2 = Point(id: 3, x: 5, y: 7)
let t = Triangle(id: 7, points: [p0,p1,p2])
let packed = pack(t.messagePackValue())
let data = packed.withUnsafeBufferPointer({ buffer in
return NSData(bytes: buffer.baseAddress, length: buffer.count)
})
Now you have the data ready for writing to file, sending over the net, or similar.
Let us unpack the pack data into triangle
do {
let bytes = data.bytes()
let value = try unpack(bytes)
let triangle = Triangle(value: value)
print("y coord of last point in tringle: \(triangle.points.last!.y)")
} catch let e as NSError
{
print(e.description)
}
For the code purity, the bytes converting function is isolated as the NSData extension:
extension NSData
{
func bytes() -> [Byte]
{
let count = length / sizeof(Byte)
// create array of appropriate length:
var byteData = [Byte](count: count, repeatedValue: 0)
// copy bytes into byte array
getBytes(&byteData, length:count * sizeof(Byte))
return byteData
}
}