From b2d93a466e3171a7eca2186756b2317f6e776244 Mon Sep 17 00:00:00 2001 From: Moritz Gmeiner Date: Wed, 2 Apr 2025 18:49:28 +0200 Subject: [PATCH] more deserialiser work --- src/serialise.zig | 105 ++++++++++++++++++++++++++++++++++----- tests/serialise/root.zig | 35 +++++++++++++ 2 files changed, 127 insertions(+), 13 deletions(-) diff --git a/src/serialise.zig b/src/serialise.zig index d990b1a..1ba0d3f 100644 --- a/src/serialise.zig +++ b/src/serialise.zig @@ -1,12 +1,16 @@ const std = @import("std"); const Object = @import("root.zig").Object; -const Tag = @import("root.zig").Tag; + +const MapEntry = @import("root.zig").MapEntry; const SerialiseError = error{ OutOfMemory, StringTooLong, BinaryTooLong, + ArrayTooLong, + MapTooLong, + ExtTooLong, }; fn intInRange(comptime T: type, i: i64) bool { @@ -98,15 +102,82 @@ fn serialise_raw(alloc: std.mem.Allocator, buf: *std.ArrayListUnmanaged(u8), s: } fn serialise_array(alloc: std.mem.Allocator, buf: *std.ArrayListUnmanaged(u8), array: []const Object) SerialiseError!void { - _ = alloc; - _ = buf; - _ = array; + if (array.len <= 15) { + try buf.append(alloc, 0b1001_0000 | @as(u8, @intCast(array.len))); + } else if (array.len <= std.math.maxInt(u16)) { + try buf.append(alloc, 0xdc); + + std.mem.writeInt(u16, try buf.addManyAsArray(alloc, @sizeOf(u16)), @intCast(array.len), .big); + } else if (array.len <= std.math.maxInt(u32)) { + try buf.append(alloc, 0xdd); + + std.mem.writeInt(u32, try buf.addManyAsArray(alloc, @sizeOf(u32)), @intCast(array.len), .big); + } else { + return error.ArrayTooLong; + } + + for (array) |obj| { + try serialise_into_buf(alloc, buf, obj); + } } -pub fn serialise(alloc: std.mem.Allocator, obj: Object) SerialiseError![]u8 { - var buf = std.ArrayListUnmanaged(u8){}; - defer buf.deinit(alloc); +fn serialise_map(alloc: std.mem.Allocator, buf: *std.ArrayListUnmanaged(u8), map: []const MapEntry) SerialiseError!void { + if (map.len <= 15) { + try buf.append(alloc, 0b1000_0000 | @as(u8, @intCast(map.len))); + } else if (map.len <= std.math.maxInt(u16)) { + try buf.append(alloc, 0xde); + std.mem.writeInt(u16, try buf.addManyAsArray(alloc, @sizeOf(u16)), @intCast(map.len), .big); + } else if (map.len <= std.math.maxInt(u32)) { + try buf.append(alloc, 0xdf); + + std.mem.writeInt(u32, try buf.addManyAsArray(alloc, @sizeOf(u32)), @intCast(map.len), .big); + } else { + return error.MapTooLong; + } + + for (map) |entry| { + try serialise_into_buf(alloc, buf, entry.key); + try serialise_into_buf(alloc, buf, entry.value); + } +} + +fn serialise_ext(alloc: std.mem.Allocator, buf: *std.ArrayListUnmanaged(u8), type_: u8, bytes: []u8) SerialiseError!void { + // fixext + for (0.., [_]usize{ 1, 2, 4, 8, 16 }) |n, len| { + if (bytes.len == len) { + try buf.ensureUnusedCapacity(alloc, 1 + 1 + len); + + try buf.append(alloc, 0xd4 + @as(u8, @intCast(n))); + try buf.append(alloc, type_); + + try buf.appendSlice(alloc, bytes); + + return; + } + } + + // ext + inline for (0.., [_]type{ u8, u16, u32 }) |n, T| { + if (bytes.len <= std.math.maxInt(T)) { + try buf.ensureUnusedCapacity(alloc, 1 + @sizeOf(T) + bytes.len); + + try buf.append(alloc, 0xc7 + n); + + std.mem.writeInt(T, try buf.addManyAsArray(alloc, @sizeOf(T)), @intCast(bytes.len), .big); + + try buf.append(alloc, type_); + + try buf.appendSlice(alloc, bytes); + + return; + } + } + + return error.ExtTooLong; +} + +fn serialise_into_buf(alloc: std.mem.Allocator, buf: *std.ArrayListUnmanaged(u8), obj: Object) SerialiseError!void { switch (obj) { .nil => try buf.append(alloc, 0xc0), .bool => |b| if (b) { @@ -114,8 +185,8 @@ pub fn serialise(alloc: std.mem.Allocator, obj: Object) SerialiseError![]u8 { } else { try buf.append(alloc, 0xc2); }, - .integer => |i| try serialise_int(alloc, &buf, i), - .uinteger => |u| try serialise_uint(alloc, &buf, u), + .integer => |i| try serialise_int(alloc, buf, i), + .uinteger => |u| try serialise_uint(alloc, buf, u), .float32 => |f| { try buf.ensureUnusedCapacity(alloc, 1 + 4); @@ -130,11 +201,19 @@ pub fn serialise(alloc: std.mem.Allocator, obj: Object) SerialiseError![]u8 { std.mem.writeInt(u64, try buf.addManyAsArray(alloc, 8), @bitCast(f), .big); }, - .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), - else => unreachable, + .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), + .map => |map| try serialise_map(alloc, buf, map), + .extension => |ext| try serialise_ext(alloc, buf, ext.type, ext.bytes), } +} + +pub fn serialise(alloc: std.mem.Allocator, obj: Object) SerialiseError![]u8 { + var buf = std.ArrayListUnmanaged(u8){}; + defer buf.deinit(alloc); + + try serialise_into_buf(alloc, &buf, obj); return try buf.toOwnedSlice(alloc); } diff --git a/tests/serialise/root.zig b/tests/serialise/root.zig index 14d1713..bc6a2b6 100644 --- a/tests/serialise/root.zig +++ b/tests/serialise/root.zig @@ -81,3 +81,38 @@ test "f64" { try std.testing.expectEqualSlices(u8, &[_]u8{ 0xcb, 0x40, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, bytes); } } + +test "array" { + const alloc = std.testing.allocator; + + { + // const obj = try deserialise(alloc, &[_]u8{ 0x92, 0xa2, 0x6c, 0x65, 0xa4, 0x73, 0x68, 0x69, 0x74 }); + // defer obj.deinit(alloc); + + // try std.testing.expectEqual(2, obj.array.len); + + // try std.testing.expectEqualStrings("le", obj.array[0].string); + // try std.testing.expectEqualStrings("shit", obj.array[1].string); + + const bytes = try serialise(alloc, .{ .array = &[_]Object{ .{ .string = "le" }, .{ .string = "shit" } } }); + defer alloc.free(bytes); + + try std.testing.expectEqualSlices(u8, &[_]u8{ 0x92, 0xa2, 0x6c, 0x65, 0xa4, 0x73, 0x68, 0x69, 0x74 }, bytes); + } +} + +test "map" { + const alloc = std.testing.allocator; + + const MapEntry = msgpack.MapEntry; + + { + const bytes = try serialise(alloc, .{ .map = &[_]MapEntry{ + .{ .key = .{ .uinteger = 0 }, .value = .{ .string = "le" } }, + .{ .key = .{ .uinteger = 1 }, .value = .{ .string = "shit" } }, + } }); + defer alloc.free(bytes); + + try std.testing.expectEqualSlices(u8, &[_]u8{ 0x82, 0x00, 0xa2, 0x6c, 0x65, 0x01, 0xa4, 0x73, 0x68, 0x69, 0x74 }, bytes); + } +}