Created
June 13, 2015 04:18
-
-
Save mikeash/0ac60ce46f40e9c825a3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
protocol Serializable { | |
static func deserializeInto(bytePtr: UnsafeMutablePointer<UInt8>, bytes: ArraySlice<UInt8>) -> ArraySlice<UInt8> | |
} | |
extension Serializable { | |
typealias WorkaroundSelf = Self | |
static func size() -> Int { | |
return sizeof(Self.self) | |
} | |
static func align() -> Int { | |
return alignof(Self.self) | |
} | |
static func deserializeInto(bytePtr: UnsafeMutablePointer<UInt8>, bytes: ArraySlice<UInt8>) -> ArraySlice<UInt8> { | |
let typedPtr = UnsafeMutablePointer<WorkaroundSelf>(bytePtr) | |
let mirror = reflect(typedPtr.memory) | |
if mirror.count > 0 { | |
var remainingBytes = bytes | |
var cursor = 0 | |
for i in 0..<mirror.count { | |
let child = mirror[i].1 | |
guard let serializableType = child.valueType as? Serializable.Type else { preconditionFailure("All members must be serializable") } | |
let size = serializableType.size() | |
let align = serializableType.align() | |
let misalignment = cursor % align | |
if misalignment != 0 { | |
cursor += align - misalignment | |
} | |
let ptr = bytePtr + cursor | |
remainingBytes = serializableType.deserializeInto(ptr, bytes: remainingBytes) | |
cursor += size | |
} | |
return remainingBytes | |
} else { | |
for i in 0..<size() { | |
bytePtr[i] = bytes[i] | |
} | |
return bytes[size()..<bytes.endIndex] | |
} | |
} | |
static func r() {} | |
static func deserialize(bytes: [UInt8]) -> Self { | |
return deserialize(ArraySlice(bytes)).0 | |
} | |
static func deserialize(bytes: ArraySlice<UInt8>) -> (Self, ArraySlice<UInt8>) { | |
let size = sizeof(Self.self) | |
var backingData = [UInt8](count: size, repeatedValue: 0) | |
return backingData.withUnsafeMutableBufferPointer({ (inout buffer: UnsafeMutableBufferPointer<UInt8>) -> (WorkaroundSelf, ArraySlice<UInt8>) in | |
let bytePtr = buffer.baseAddress | |
let remainder = deserializeInto(bytePtr, bytes: ArraySlice(bytes)) | |
let typedPtr = UnsafeMutablePointer<WorkaroundSelf>(bytePtr) | |
return (typedPtr.memory, remainder) | |
}) | |
} | |
} | |
extension Int64: Serializable {} | |
extension Int32: Serializable {} | |
extension String: Serializable { | |
static func deserializeInto(bytePtr: UnsafeMutablePointer<UInt8>, bytes: ArraySlice<UInt8>) -> ArraySlice<UInt8> { | |
let (length, remainder) = Int64.deserialize(bytes) | |
let utf8Data = remainder[0..<Int(length)] | |
let string = String(bytes: utf8Data, encoding: NSUTF8StringEncoding)! | |
let finalRemainder = remainder[Int(length)..<remainder.endIndex] | |
let stringPointer = UnsafeMutablePointer<String>(bytePtr) | |
stringPointer.initialize(string) | |
return finalRemainder | |
} | |
} | |
struct TestStruct: Serializable { | |
let x: Int32 | |
let y: Int64 | |
let z: String | |
} | |
let bytes: [UInt8] = [1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100] | |
print(TestStruct.deserialize(bytes)) | |
// prints: SerializationExperiment.TestStruct(x: 1, y: 2, z: "Hello, world") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment