msgpack-zig/src/serialise.zig

140 lines
4 KiB
Zig
Raw Normal View History

2025-04-02 02:44:26 +02:00
const std = @import("std");
const Object = @import("root.zig").Object;
const Tag = @import("root.zig").Tag;
const SerialiseError = error{
OutOfMemory,
StringTooLong,
BinaryTooLong,
};
fn intInRange(comptime T: type, i: i64) bool {
return std.math.minInt(T) <= i and i <= std.math.maxInt(T);
}
fn serialise_int(alloc: std.mem.Allocator, buf: *std.ArrayListUnmanaged(u8), i: i64) SerialiseError!void {
if (i < 0 and i >= std.math.minInt(i6)) { // neg fixint
std.mem.writeInt(i8, try buf.addManyAsArray(alloc, 1), @intCast(i), .big);
2025-04-02 02:44:26 +02:00
return;
2025-04-02 02:44:26 +02:00
}
inline for (0.., &[_]type{ i8, i16, i32, i64 }) |n, T| {
if (intInRange(T, i)) {
try buf.ensureUnusedCapacity(alloc, 1 + @sizeOf(T));
2025-04-02 02:44:26 +02:00
try buf.append(alloc, 0xd0 + n);
2025-04-02 02:44:26 +02:00
std.mem.writeInt(T, try buf.addManyAsArray(alloc, @sizeOf(T)), @intCast(i), .big);
2025-04-02 02:44:26 +02:00
return;
}
2025-04-02 02:44:26 +02:00
}
unreachable;
2025-04-02 02:44:26 +02:00
}
fn uintInRange(comptime T: type, u: u64) bool {
return u <= std.math.maxInt(T);
}
fn serialise_uint(alloc: std.mem.Allocator, buf: *std.ArrayListUnmanaged(u8), u: u64) SerialiseError!void {
2025-04-02 02:44:26 +02:00
if (uintInRange(u7, u)) { // pos fixint
std.mem.writeInt(u8, try buf.addManyAsArray(alloc, 1), @intCast(u), .big);
2025-04-02 02:44:26 +02:00
return;
2025-04-02 02:44:26 +02:00
}
inline for (0.., &[_]type{ u8, u16, u32, u64 }) |n, T| {
if (uintInRange(T, u)) {
try buf.ensureUnusedCapacity(alloc, 1 + @sizeOf(T));
2025-04-02 02:44:26 +02:00
try buf.append(alloc, 0xcc + n);
2025-04-02 02:44:26 +02:00
std.mem.writeInt(T, try buf.addManyAsArray(alloc, @sizeOf(T)), @intCast(u), .big);
2025-04-02 02:44:26 +02:00
return;
}
2025-04-02 02:44:26 +02:00
}
unreachable;
2025-04-02 02:44:26 +02:00
}
fn serialise_raw(alloc: std.mem.Allocator, buf: *std.ArrayListUnmanaged(u8), s: []const u8, comptime kind: enum { string, binary }) SerialiseError!void {
// TODO: should we validate that `s` is UTF-8 here?
2025-04-02 02:44:26 +02:00
if (kind == .string and s.len <= 31) { // fixstr
try buf.ensureUnusedCapacity(alloc, 1 + s.len);
2025-04-02 02:44:26 +02:00
try buf.append(alloc, 0b101_00000 | @as(u8, @intCast(s.len)));
2025-04-02 02:44:26 +02:00
try buf.appendSlice(alloc, s);
2025-04-02 02:44:26 +02:00
return;
2025-04-02 02:44:26 +02:00
}
inline for (0.., &[_]type{ u8, u16, u32 }) |i, T| {
if (s.len <= std.math.maxInt(T)) {
try buf.ensureUnusedCapacity(alloc, 1 + @sizeOf(T) + s.len);
2025-04-02 02:44:26 +02:00
switch (kind) {
.string => try buf.append(alloc, 0xd9 + i),
.binary => try buf.append(alloc, 0xc4 + i),
}
2025-04-02 02:44:26 +02:00
std.mem.writeInt(T, try buf.addManyAsArray(alloc, @sizeOf(T)), @intCast(s.len), .big);
2025-04-02 02:44:26 +02:00
try buf.appendSlice(alloc, s);
2025-04-02 02:44:26 +02:00
return;
}
2025-04-02 02:44:26 +02:00
}
return switch (kind) {
.string => error.StringTooLong,
.binary => error.BinaryTooLong,
};
}
fn serialise_array(alloc: std.mem.Allocator, buf: *std.ArrayListUnmanaged(u8), array: []const Object) SerialiseError!void {
_ = alloc;
_ = buf;
_ = array;
}
2025-04-02 02:44:26 +02:00
pub fn serialise(alloc: std.mem.Allocator, obj: Object) SerialiseError![]u8 {
var buf = std.ArrayListUnmanaged(u8){};
defer buf.deinit(alloc);
2025-04-02 02:44:26 +02:00
switch (obj) {
.nil => try buf.append(alloc, 0xc0),
2025-04-02 02:44:26 +02:00
.bool => |b| if (b) {
try buf.append(alloc, 0xc3);
2025-04-02 02:44:26 +02:00
} else {
try buf.append(alloc, 0xc2);
2025-04-02 02:44:26 +02:00
},
.integer => |i| try serialise_int(alloc, &buf, i),
.uinteger => |u| try serialise_uint(alloc, &buf, u),
2025-04-02 02:44:26 +02:00
.float32 => |f| {
try buf.ensureUnusedCapacity(alloc, 1 + 4);
2025-04-02 02:44:26 +02:00
try buf.append(alloc, 0xca);
2025-04-02 02:44:26 +02:00
std.mem.writeInt(u32, try buf.addManyAsArray(alloc, 4), @bitCast(f), .big);
2025-04-02 02:44:26 +02:00
},
.float64 => |f| {
try buf.ensureUnusedCapacity(alloc, 1 + 8);
2025-04-02 02:44:26 +02:00
try buf.append(alloc, 0xcb);
2025-04-02 02:44:26 +02:00
std.mem.writeInt(u64, try buf.addManyAsArray(alloc, 8), @bitCast(f), .big);
2025-04-02 02:44:26 +02:00
},
.string => |s| try serialise_raw(alloc, &buf, s, .string),
.binary => |b| try serialise_raw(alloc, &buf, b, .binary),
.array => |array| try serialise_array(alloc, &buf, array),
2025-04-02 02:44:26 +02:00
else => unreachable,
}
return try buf.toOwnedSlice(alloc);
2025-04-02 02:44:26 +02:00
}