mzg is a MessagePack library for Zig with no allocations, and the API favors
the streaming usage.
-
Run the following command to add this project as a dependency
zig fetch --save git+https://github.com/uyha/mzg.git#v0.2.1
-
In your
build.zig, add the followingconst mzg = b.dependency("mzg", .{ .target = target, .optimize = optimize, }); // Replace `exe` with your actual library or executable exe.root_module.addImport("mzg", mzg.module("mzg"));
packis for packing Zig values using awriterpackAdaptedis likepackbut it accepts a map that defines how certain types should be packed.packWithOptionsis likepackbut it accepts amzg.PackOptionsparameter to control the packing behavior.packAdaptedWithOptionsis likepackWithOptionsbut it accepts a map that defines how certain types should be packed.
unpackis for unpacking a MessagePack message into a Zig object and it does not allocate memory.unpackAdaptedis likeunpackbut it accepts a map that defines how certain types should be unpacked.unpackAllocateis likeunpackbut it accepts anAllocatorthat allows the unpacking process to allocate memory.unpackAdaptedAllocateis likeunpackAllocatebut it accepts a map that defines how a particular type should be packed.
adapter.packArrayandadapter.unpackArraypack and unpack structs likestd.ArrayListUnmanagedadapter.packMapandadapter.unpackMappack and unpack structs likestd.ArrayHashMapUnmanaged.adapter.packStreamandadapter.unpackStreampack and unpack structs in a stream like manner (length is not specified in the beginning).
There are a set of pack* and unpack* functions that translate between a
precise set of Zig types and MessagePack. These functions can be used when
implementing custom packing and unpacking.
All examples live in examples directory.
Converting a byte slice to MessagePack and back
pub fn main() !void {
const allocator = std.heap.page_allocator;
var allocWriter: Writer.Allocating = .init(allocator);
defer allocWriter.deinit();
const writer: *Writer = &allocWriter.writer;
try mzg.pack(
"a string with some characters for demonstration purpose",
writer,
);
var string: []const u8 = undefined;
const size = try mzg.unpack(writer.buffer[0..writer.end], &string);
std.debug.print("Consumed {} bytes\n", .{size});
std.debug.print("string: {s}\n", .{string});
}
const std = @import("std");
const Writer = std.Io.Writer;
const mzg = @import("mzg");Certain types can be packed and unpacked by default (refer to Mapping for more details)
pub fn main() !void {
const allocator = std.heap.page_allocator;
var allocWriter: Writer.Allocating = .init(allocator);
defer allocWriter.deinit();
const writer: *Writer = &allocWriter.writer;
try mzg.pack(
Targets{ .position = .init(2000), .velocity = .init(10) },
writer,
);
var targets: Targets = undefined;
const size = try mzg.unpack(writer.buffer[0..writer.end], &targets);
std.debug.print("Consumed {} bytes\n", .{size});
std.debug.print("Targets: {}\n", .{targets});
}
const Position = enum(i32) {
_,
pub fn init(raw: std.meta.Tag(@This())) @This() {
return @enumFromInt(raw);
}
};
const Velocity = enum(i32) {
_,
pub fn init(raw: std.meta.Tag(@This())) @This() {
return @enumFromInt(raw);
}
};
const Targets = struct {
position: Position,
velocity: Velocity,
};
const std = @import("std");
const Writer = std.Io.Writer;
const mzg = @import("mzg");
const adapter = mzg.adapter;Many container types in the std library cannot be packed or unpacked by
default, but the adapter functions make it easy to work with these types.
pub fn main() !void {
const allocator = std.heap.page_allocator;
var allocWriter: Writer.Allocating = .init(allocator);
defer allocWriter.deinit();
const writer: *Writer = &allocWriter.writer;
var in: std.ArrayList(u32) = .empty;
defer in.deinit(allocator);
try in.append(allocator, 42);
try in.append(allocator, 75);
try mzg.pack(adapter.packArray(&in), writer);
var out: std.ArrayList(u32) = .empty;
defer out.deinit(allocator);
const size = try mzg.unpackAllocate(
allocator,
writer.buffer[0..writer.end],
adapter.unpackArray(&out),
);
std.debug.print("Consumed {} bytes\n", .{size});
std.debug.print("out: {any}\n", .{out.items});
}
const std = @import("std");
const Writer = std.Io.Writer;
const mzg = @import("mzg");
const adapter = mzg.adapter;| Zig Type | MessagePack |
|---|---|
void, null |
nil |
bool |
bool |
| integers (<=64 bits) | int |
| floats (<=64 bits) | float |
?T |
nil if value is null, pack according to T otherwise |
| enums | int |
| enum literals | str |
| tagged unions | array of 2 elements: int and the value of the union |
| packed structs | int |
| structs and tuples | array of fields in the order they are declared |
[N], [], [:X], and @Vec of u8 |
str |
[N], [], [:X], and @Vec of T |
array of T |
Ext |
ext |
Timestamp |
Timestamp |
*T |
T |
| MessagePack | Compatible Zig Type |
|---|---|
nil |
void, ?T |
bool |
bool |
int |
integers, enums |
float |
floats |
str |
[]const u8 |
bin |
[]const u8 |
array |
The length can be read into integers |
map |
The length can be read into integers |
ext |
Ext |
Timestamp |
Timestamp |
When an enum/union/struct has an mzgPack function that returns
mzg.PackError!void can be called with
// Value cares about the options passed by the caller
value.mzgPack(options, map, writer);With the arguments being
valueis the enum/union/struct being packed.optionsismzg.PackOptions.mapis a tuple of 2 element tuples whose 1st element being a type and 2nd element being a packing adapter function.writerisstd.Io.Writer.
The function will be called when the mzg.pack function is used.
When an enum/union/struct has
-
mzgUnpackfunction that returnsUnpackError!usizeand can be called without.mzgUnpack(map, buffer);
-
mzgUnpackAllocatefunction that returnsUnpackAllocateError!usizeand can be called without.mzgUnpackAllocate(allocator, map, buffer);
With the arguments being
outis the enum/union/struct being unpacked.allocatoris anstd.mem.Allocator.mapis a tuple of 2 element tuples whose 1st element being a type and 2nd element being an unpacking adapter function.bufferis[]const u8.
The mzgUnpack function is called when either mzg.unpack or
mzg.unpackAdapted is used.
The mzgUnpackAllocate function is called when either mzg.unpackAllocate or
mzg.unpackAdaptedAllocate is used.