/MessagePack-Swift

Simple Swift 5 MessagePack implementation

Primary LanguageSwiftMIT LicenseMIT

MessagePack

Pure Swift 5 MessagePack library, compatible with macOS, iOS and Linux.

This library does not attempt to implement Codable for simplicity.

Reading

The library implements type-safe lazy readers. See read(_: Type) for more information.

Supported types are:

  • Bool,
  • UInt/8/16/32/64,
  • Int/8/16/32/64,
  • Float,
  • Double,
  • String,
  • Data

Specialized methods are available to read nil, arrays and dictionaries.
Optional helpers are available using read(_: Type?) and readOptional*.

Example:

let data: Data = ......
var reader = MessagePackReader(from: data)
let age = try reader.read(UInt8.self)
let name = try reader.read(String.self)
let subscribed = try reader.read(Bool?.self)

Reading arrays and dictionaries

While you can eagerly read arrays and dictionaries using readArray and readDictionary, they return [Any?] and [AnyHashable: Any?], which require you to carefuly cast the results. This also doesn't support "complex" arrays/maps where the index might represent more than one MessagePack value, which an automatic reader can't know.

To read arrays/maps in a type safe way, this library implements a closure based reader which works like .map.
Alternatively, you can simply read the array/map length and proceed manually, using readArrayHeader

Example:

struct Person {
    var name: String
    var age: UInt8
}

let data: Data = ......
var reader = MessagePackReader(from: data)
let count: [Person] = try reader.readAndMapArray {
    let name = try $0.read(String.self)
    let age = try $0.read(UInt8.self)
    return Person(name: name, age: age)
}

Writing

The library implements type-safe writers. See pack(_: Type) for more information.

Supported types are:

  • Bool,
  • UInt/8/16/32/64,
  • Int/8/16/32/64,
  • Float,
  • Double,
  • String,
  • Data

Specialized methods are available to write nil, arrays, dictionaries and any.

The output data is always available by reading the data property.

Example:

var writer = MessagePackWriter()
writer.pack(Int32(-4))
writer.pack(UInt8(40))
writer.pack("MessagePack")
let packedData = writer.data

Writing an optional

To make sure you don't accidentally pack nil values, optional methods are suffixed by "Optional".

let value: String? = nil
var writer = MessagePackWriter()
writer.packOptional(value)

Writing an array/dictionary

While you can pack arrays and dictionaries using packArray and packDictionary, you might need to write "complex" values.
packFlatArray/packFlatDictionary allows you to pack such values.

Example that packs the Person array read by the reader example:

var writer = MessagePackWriter()
var persons = [MessagePackFlatValue]()
// MessagePackFlatValue is a great candidate to map your original collection to
persons.append(try MessagePackFlatValue {
    $0.pack("John Doe")
    $0.pack(35)
})
persons.append(try MessagePackFlatValue {
    $0.pack("Jane Doe")
    $0.pack(26)
})
try writer.packFlatArray(persons) 
let data = writer.data

Note: MessagePackValue cannot be packed using pack(_: [Any?].Type), as mixing "simple" and "complex" types is usually not wanted.

Extensions

Extensions are currently not supported.
If you can pack/unpack them manuallyn use unsafePackRawData(_: Data)/unsafePeekRawByte() or unsafeReadRawData().

Developing the library

Simply open Package.swift in Xcode. Development in VSCode is also supported even on linux.
Scripts are available in the scripts/ folder, which include building, testing and running SwiftFormat/Swiftlint.

This project uses SwiftFormat and Swiftlint, which are automatically installed locally by SwiftPM: use the provided shell scripts (or vscode tasks) to run them.