more deserialiser work
This commit is contained in:
parent
3fce037239
commit
b2d93a466e
2 changed files with 127 additions and 13 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue