switch serialiser to ArrayList for now
possibly later switch to a Writer or precount the number of bytes that will be written
This commit is contained in:
parent
e1f1084a39
commit
3fce037239
2 changed files with 66 additions and 145 deletions
|
|
@ -34,8 +34,8 @@ pub const Object = union(enum) {
|
||||||
float64: f64,
|
float64: f64,
|
||||||
string: []const u8,
|
string: []const u8,
|
||||||
binary: []const u8,
|
binary: []const u8,
|
||||||
array: []Object,
|
array: []const Object,
|
||||||
map: []MapEntry,
|
map: []const MapEntry,
|
||||||
extension: struct { type: u8, bytes: []u8 },
|
extension: struct { type: u8, bytes: []u8 },
|
||||||
|
|
||||||
pub fn deinit(self: Object, alloc: std.mem.Allocator) void {
|
pub fn deinit(self: Object, alloc: std.mem.Allocator) void {
|
||||||
|
|
|
||||||
|
|
@ -13,165 +13,82 @@ fn intInRange(comptime T: type, i: i64) bool {
|
||||||
return std.math.minInt(T) <= i and i <= std.math.maxInt(T);
|
return std.math.minInt(T) <= i and i <= std.math.maxInt(T);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialise_int(alloc: std.mem.Allocator, i: i64) SerialiseError![]u8 {
|
fn serialise_int(alloc: std.mem.Allocator, buf: *std.ArrayListUnmanaged(u8), i: i64) SerialiseError!void {
|
||||||
if (i < 0 and i >= std.math.minInt(i6)) {
|
if (i < 0 and i >= std.math.minInt(i6)) { // neg fixint
|
||||||
// neg fixint
|
std.mem.writeInt(i8, try buf.addManyAsArray(alloc, 1), @intCast(i), .big);
|
||||||
const bytes = try alloc.alloc(u8, 1);
|
|
||||||
|
|
||||||
std.mem.writeInt(i8, bytes[0..1], @intCast(i), .big);
|
return;
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intInRange(i8, i)) { // int8
|
inline for (0.., &[_]type{ i8, i16, i32, i64 }) |n, T| {
|
||||||
const bytes = try alloc.alloc(u8, 1 + 1);
|
if (intInRange(T, i)) {
|
||||||
|
try buf.ensureUnusedCapacity(alloc, 1 + @sizeOf(T));
|
||||||
|
|
||||||
bytes[0] = 0xd0;
|
try buf.append(alloc, 0xd0 + n);
|
||||||
|
|
||||||
std.mem.writeInt(i8, bytes[1..2], @intCast(i), .big);
|
std.mem.writeInt(T, try buf.addManyAsArray(alloc, @sizeOf(T)), @intCast(i), .big);
|
||||||
|
|
||||||
return bytes;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intInRange(i16, i)) { // int16
|
unreachable;
|
||||||
const bytes = try alloc.alloc(u8, 1 + 2);
|
|
||||||
|
|
||||||
bytes[0] = 0xd1;
|
|
||||||
|
|
||||||
std.mem.writeInt(i16, bytes[1..3], @intCast(i), .big);
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (intInRange(i32, i)) { // int32
|
|
||||||
const bytes = try alloc.alloc(u8, 1 + 4);
|
|
||||||
|
|
||||||
bytes[0] = 0xd2;
|
|
||||||
|
|
||||||
std.mem.writeInt(i32, bytes[1..5], @intCast(i), .big);
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
// int64
|
|
||||||
const bytes = try alloc.alloc(u8, 1 + 8);
|
|
||||||
|
|
||||||
bytes[0] = 0xd3;
|
|
||||||
|
|
||||||
std.mem.writeInt(i64, bytes[1..9], i, .big);
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn uintInRange(comptime T: type, u: u64) bool {
|
fn uintInRange(comptime T: type, u: u64) bool {
|
||||||
return u <= std.math.maxInt(T);
|
return u <= std.math.maxInt(T);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialise_uint(alloc: std.mem.Allocator, u: u64) SerialiseError![]u8 {
|
fn serialise_uint(alloc: std.mem.Allocator, buf: *std.ArrayListUnmanaged(u8), u: u64) SerialiseError!void {
|
||||||
if (uintInRange(u7, u)) { // pos fixint
|
if (uintInRange(u7, u)) { // pos fixint
|
||||||
const bytes = try alloc.alloc(u8, 1);
|
std.mem.writeInt(u8, try buf.addManyAsArray(alloc, 1), @intCast(u), .big);
|
||||||
|
|
||||||
std.mem.writeInt(u8, bytes[0..1], @intCast(u), .big);
|
return;
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uintInRange(u8, u)) { // uint8
|
inline for (0.., &[_]type{ u8, u16, u32, u64 }) |n, T| {
|
||||||
const bytes = try alloc.alloc(u8, 1 + 1);
|
if (uintInRange(T, u)) {
|
||||||
|
try buf.ensureUnusedCapacity(alloc, 1 + @sizeOf(T));
|
||||||
|
|
||||||
bytes[0] = 0xcc;
|
try buf.append(alloc, 0xcc + n);
|
||||||
|
|
||||||
std.mem.writeInt(u8, bytes[1..2], @intCast(u), .big);
|
std.mem.writeInt(T, try buf.addManyAsArray(alloc, @sizeOf(T)), @intCast(u), .big);
|
||||||
|
|
||||||
return bytes;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uintInRange(u16, u)) { // uint16
|
unreachable;
|
||||||
const bytes = try alloc.alloc(u8, 1 + 2);
|
|
||||||
|
|
||||||
bytes[0] = 0xcd;
|
|
||||||
|
|
||||||
std.mem.writeInt(u16, bytes[1..3], @intCast(u), .big);
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uintInRange(u32, u)) { // uint32
|
fn serialise_raw(alloc: std.mem.Allocator, buf: *std.ArrayListUnmanaged(u8), s: []const u8, comptime kind: enum { string, binary }) SerialiseError!void {
|
||||||
const bytes = try alloc.alloc(u8, 1 + 4);
|
// TODO: should we validate that `s` is UTF-8 here?
|
||||||
|
|
||||||
bytes[0] = 0xce;
|
|
||||||
|
|
||||||
std.mem.writeInt(u32, bytes[1..5], @intCast(u), .big);
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
// uint64
|
|
||||||
const bytes = try alloc.alloc(u8, 1 + 8);
|
|
||||||
|
|
||||||
bytes[0] = 0xcf;
|
|
||||||
|
|
||||||
std.mem.writeInt(u64, bytes[1..9], u, .big);
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialise_raw(alloc: std.mem.Allocator, s: []const u8, comptime kind: enum { string, binary }) SerialiseError![]u8 {
|
|
||||||
// TODO: should we validate that s in UTF-8 here?
|
|
||||||
|
|
||||||
if (kind == .string and s.len <= 31) { // fixstr
|
if (kind == .string and s.len <= 31) { // fixstr
|
||||||
const bytes = try alloc.alloc(u8, 1 + s.len);
|
try buf.ensureUnusedCapacity(alloc, 1 + s.len);
|
||||||
|
|
||||||
bytes[0] = 0b101_00000 | @as(u8, @intCast(s.len));
|
try buf.append(alloc, 0b101_00000 | @as(u8, @intCast(s.len)));
|
||||||
|
|
||||||
@memcpy(bytes[1..], s);
|
try buf.appendSlice(alloc, s);
|
||||||
|
|
||||||
return bytes;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s.len <= std.math.maxInt(u8)) { // str8 / bin8
|
inline for (0.., &[_]type{ u8, u16, u32 }) |i, T| {
|
||||||
const bytes = try alloc.alloc(u8, 1 + 1 + s.len);
|
if (s.len <= std.math.maxInt(T)) {
|
||||||
|
try buf.ensureUnusedCapacity(alloc, 1 + @sizeOf(T) + s.len);
|
||||||
|
|
||||||
bytes[0] = switch (kind) {
|
switch (kind) {
|
||||||
.string => 0xd9,
|
.string => try buf.append(alloc, 0xd9 + i),
|
||||||
.binary => 0xc4,
|
.binary => try buf.append(alloc, 0xc4 + i),
|
||||||
};
|
|
||||||
|
|
||||||
bytes[1] = @as(u8, @intCast(s.len));
|
|
||||||
|
|
||||||
@memcpy(bytes[2..], s);
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s.len <= std.math.maxInt(u16)) { // str16 / bin16
|
std.mem.writeInt(T, try buf.addManyAsArray(alloc, @sizeOf(T)), @intCast(s.len), .big);
|
||||||
const bytes = try alloc.alloc(u8, 1 + 2 + s.len);
|
|
||||||
|
|
||||||
bytes[0] = switch (kind) {
|
try buf.appendSlice(alloc, s);
|
||||||
.string => 0xda,
|
|
||||||
.binary => 0xc5,
|
|
||||||
};
|
|
||||||
|
|
||||||
std.mem.writeInt(u16, bytes[1..3], @intCast(s.len), .big);
|
return;
|
||||||
|
|
||||||
@memcpy(bytes[3..], s);
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s.len <= std.math.maxInt(u32)) { // str16 / bin16
|
|
||||||
const bytes = try alloc.alloc(u8, 1 + 4 + s.len);
|
|
||||||
|
|
||||||
bytes[0] = switch (kind) {
|
|
||||||
.string => 0xdb,
|
|
||||||
.binary => 0xc6,
|
|
||||||
};
|
|
||||||
|
|
||||||
std.mem.writeInt(u32, bytes[1..5], @intCast(s.len), .big);
|
|
||||||
|
|
||||||
@memcpy(bytes[5..], s);
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return switch (kind) {
|
return switch (kind) {
|
||||||
|
|
@ -180,40 +97,44 @@ fn serialise_raw(alloc: std.mem.Allocator, s: []const u8, comptime kind: enum {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn serialise_array(alloc: std.mem.Allocator, buf: *std.ArrayListUnmanaged(u8), array: []const Object) SerialiseError!void {
|
||||||
|
_ = alloc;
|
||||||
|
_ = buf;
|
||||||
|
_ = array;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn serialise(alloc: std.mem.Allocator, obj: Object) SerialiseError![]u8 {
|
pub fn serialise(alloc: std.mem.Allocator, obj: Object) SerialiseError![]u8 {
|
||||||
|
var buf = std.ArrayListUnmanaged(u8){};
|
||||||
|
defer buf.deinit(alloc);
|
||||||
|
|
||||||
switch (obj) {
|
switch (obj) {
|
||||||
.nil => return try alloc.dupe(u8, &[_]u8{0xc0}),
|
.nil => try buf.append(alloc, 0xc0),
|
||||||
.bool => |b| if (b) {
|
.bool => |b| if (b) {
|
||||||
return try alloc.dupe(u8, &[_]u8{0xc3});
|
try buf.append(alloc, 0xc3);
|
||||||
} else {
|
} else {
|
||||||
return try alloc.dupe(u8, &[_]u8{0xc2});
|
try buf.append(alloc, 0xc2);
|
||||||
},
|
},
|
||||||
.integer => |i| return try serialise_int(alloc, i),
|
.integer => |i| try serialise_int(alloc, &buf, i),
|
||||||
.uinteger => |u| return try serialise_uint(alloc, u),
|
.uinteger => |u| try serialise_uint(alloc, &buf, u),
|
||||||
.float32 => |f| {
|
.float32 => |f| {
|
||||||
const bytes = try alloc.alloc(u8, 1 + 4);
|
try buf.ensureUnusedCapacity(alloc, 1 + 4);
|
||||||
|
|
||||||
bytes[0] = 0xca;
|
try buf.append(alloc, 0xca);
|
||||||
|
|
||||||
std.mem.writeInt(u32, bytes[1..5], @bitCast(f), .big);
|
std.mem.writeInt(u32, try buf.addManyAsArray(alloc, 4), @bitCast(f), .big);
|
||||||
|
|
||||||
return bytes;
|
|
||||||
},
|
},
|
||||||
.float64 => |f| {
|
.float64 => |f| {
|
||||||
const bytes = try alloc.alloc(u8, 1 + 8);
|
try buf.ensureUnusedCapacity(alloc, 1 + 8);
|
||||||
|
|
||||||
bytes[0] = 0xcb;
|
try buf.append(alloc, 0xcb);
|
||||||
|
|
||||||
std.mem.writeInt(u64, bytes[1..9], @bitCast(f), .big);
|
std.mem.writeInt(u64, try buf.addManyAsArray(alloc, 8), @bitCast(f), .big);
|
||||||
|
|
||||||
return bytes;
|
|
||||||
},
|
},
|
||||||
.string => |s| return try serialise_raw(alloc, s, .string),
|
.string => |s| try serialise_raw(alloc, &buf, s, .string),
|
||||||
.binary => |b| return try serialise_raw(alloc, b, .binary),
|
.binary => |b| try serialise_raw(alloc, &buf, b, .binary),
|
||||||
|
.array => |array| try serialise_array(alloc, &buf, array),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
|
|
||||||
// const bytes = try alloc.alloc(u8, 0);
|
return try buf.toOwnedSlice(alloc);
|
||||||
|
|
||||||
// return bytes;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue