feat: prevent some more json encode/decode errors and clean-up error sets

This commit is contained in:
CJ van den Berg 2024-09-19 20:58:39 +02:00
parent 06ff2a148c
commit 6e65fa623a
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9
3 changed files with 99 additions and 90 deletions

View file

@ -10,18 +10,20 @@ const minInt = std.math.minInt;
const json = std.json; const json = std.json;
const fba = std.heap.FixedBufferAllocator; const fba = std.heap.FixedBufferAllocator;
pub const CborError = error{ pub const Error = error{
CborIntegerTooLarge, IntegerTooLarge,
CborIntegerTooSmall, IntegerTooSmall,
CborInvalidType, InvalidType,
CborTooShort, TooShort,
OutOfMemory, OutOfMemory,
}; };
pub const CborJsonError = (CborError || error{ pub const JsonEncodeError = (Error || error{
UnsupportedType,
});
pub const JsonDecodeError = (Error || error{
BufferUnderrun, BufferUnderrun,
CborUnsupportedType,
NoSpaceLeft,
SyntaxError, SyntaxError,
UnexpectedEndOfInput, UnexpectedEndOfInput,
}); });
@ -287,9 +289,9 @@ pub fn fmt(buf: []u8, value: anytype) []const u8 {
const CborType = struct { type: u8, minor: u5, major: u3 }; const CborType = struct { type: u8, minor: u5, major: u3 };
pub fn decodeType(iter: *[]const u8) error{CborTooShort}!CborType { pub fn decodeType(iter: *[]const u8) error{TooShort}!CborType {
if (iter.len < 1) if (iter.len < 1)
return error.CborTooShort; return error.TooShort;
const type_: u8 = iter.*[0]; const type_: u8 = iter.*[0];
const bits: packed struct { minor: u5, major: u3 } = @bitCast(type_); const bits: packed struct { minor: u5, major: u3 } = @bitCast(type_);
iter.* = iter.*[1..]; iter.* = iter.*[1..];
@ -298,7 +300,7 @@ pub fn decodeType(iter: *[]const u8) error{CborTooShort}!CborType {
fn decodeUIntLengthRecurse(iter: *[]const u8, length: usize, acc: u64) !u64 { fn decodeUIntLengthRecurse(iter: *[]const u8, length: usize, acc: u64) !u64 {
if (iter.len < 1) if (iter.len < 1)
return error.CborTooShort; return error.TooShort;
const v: u8 = iter.*[0]; const v: u8 = iter.*[0];
iter.* = iter.*[1..]; iter.* = iter.*[1..];
var i = acc | v; var i = acc | v;
@ -320,48 +322,48 @@ fn decodePInt(iter: *[]const u8, minor: u5) !u64 {
25 => decodeUIntLength(iter, 2), // 2 byte 25 => decodeUIntLength(iter, 2), // 2 byte
26 => decodeUIntLength(iter, 4), // 4 byte 26 => decodeUIntLength(iter, 4), // 4 byte
27 => decodeUIntLength(iter, 8), // 8 byte 27 => decodeUIntLength(iter, 8), // 8 byte
else => error.CborInvalidType, else => error.InvalidType,
}; };
} }
fn decodeNInt(iter: *[]const u8, minor: u5) CborError!i64 { fn decodeNInt(iter: *[]const u8, minor: u5) Error!i64 {
return -@as(i64, @intCast(try decodePInt(iter, minor) + 1)); return -@as(i64, @intCast(try decodePInt(iter, minor) + 1));
} }
pub fn decodeMapHeader(iter: *[]const u8) CborError!usize { pub fn decodeMapHeader(iter: *[]const u8) Error!usize {
const t = try decodeType(iter); const t = try decodeType(iter);
if (t.type == cbor_magic_null) if (t.type == cbor_magic_null)
return 0; return 0;
if (t.major != 5) if (t.major != 5)
return error.CborInvalidType; return error.InvalidType;
return @intCast(try decodePInt(iter, t.minor)); return @intCast(try decodePInt(iter, t.minor));
} }
pub fn decodeArrayHeader(iter: *[]const u8) CborError!usize { pub fn decodeArrayHeader(iter: *[]const u8) Error!usize {
const t = try decodeType(iter); const t = try decodeType(iter);
if (t.type == cbor_magic_null) if (t.type == cbor_magic_null)
return 0; return 0;
if (t.major != 4) if (t.major != 4)
return error.CborInvalidType; return error.InvalidType;
return @intCast(try decodePInt(iter, t.minor)); return @intCast(try decodePInt(iter, t.minor));
} }
fn decodeString(iter_: *[]const u8, minor: u5) CborError![]const u8 { fn decodeString(iter_: *[]const u8, minor: u5) Error![]const u8 {
var iter = iter_.*; var iter = iter_.*;
const len: usize = @intCast(try decodePInt(&iter, minor)); const len: usize = @intCast(try decodePInt(&iter, minor));
if (iter.len < len) if (iter.len < len)
return error.CborTooShort; return error.TooShort;
const s = iter[0..len]; const s = iter[0..len];
iter = iter[len..]; iter = iter[len..];
iter_.* = iter; iter_.* = iter;
return s; return s;
} }
fn decodeBytes(iter: *[]const u8, minor: u5) CborError![]const u8 { fn decodeBytes(iter: *[]const u8, minor: u5) Error![]const u8 {
return decodeString(iter, minor); return decodeString(iter, minor);
} }
fn decodeJsonArray(iter_: *[]const u8, minor: u5, arr: *json.Array) CborError!bool { fn decodeJsonArray(iter_: *[]const u8, minor: u5, arr: *json.Array) Error!bool {
var iter = iter_.*; var iter = iter_.*;
var n = try decodePInt(&iter, minor); var n = try decodePInt(&iter, minor);
while (n > 0) { while (n > 0) {
@ -374,7 +376,7 @@ fn decodeJsonArray(iter_: *[]const u8, minor: u5, arr: *json.Array) CborError!bo
return true; return true;
} }
fn decodeJsonObject(iter_: *[]const u8, minor: u5, obj: *json.ObjectMap) CborError!bool { fn decodeJsonObject(iter_: *[]const u8, minor: u5, obj: *json.ObjectMap) Error!bool {
var iter = iter_.*; var iter = iter_.*;
var n = try decodePInt(&iter, minor); var n = try decodePInt(&iter, minor);
while (n > 0) { while (n > 0) {
@ -393,12 +395,12 @@ fn decodeJsonObject(iter_: *[]const u8, minor: u5, obj: *json.ObjectMap) CborErr
return true; return true;
} }
fn decodeFloat(comptime T: type, iter_: *[]const u8, t: CborType) CborError!T { fn decodeFloat(comptime T: type, iter_: *[]const u8, t: CborType) Error!T {
var v: T = undefined; var v: T = undefined;
var iter = iter_.*; var iter = iter_.*;
switch (t.type) { switch (t.type) {
cbor_magic_float16 => { cbor_magic_float16 => {
if (iter.len < 2) return error.CborTooShort; if (iter.len < 2) return error.TooShort;
var f: f16 = undefined; var f: f16 = undefined;
var f_bytes = std.mem.asBytes(&f); var f_bytes = std.mem.asBytes(&f);
switch (native_endian) { switch (native_endian) {
@ -412,7 +414,7 @@ fn decodeFloat(comptime T: type, iter_: *[]const u8, t: CborType) CborError!T {
iter = iter[2..]; iter = iter[2..];
}, },
cbor_magic_float32 => { cbor_magic_float32 => {
if (iter.len < 4) return error.CborTooShort; if (iter.len < 4) return error.TooShort;
var f: f32 = undefined; var f: f32 = undefined;
var f_bytes = std.mem.asBytes(&f); var f_bytes = std.mem.asBytes(&f);
switch (native_endian) { switch (native_endian) {
@ -428,7 +430,7 @@ fn decodeFloat(comptime T: type, iter_: *[]const u8, t: CborType) CborError!T {
iter = iter[4..]; iter = iter[4..];
}, },
cbor_magic_float64 => { cbor_magic_float64 => {
if (iter.len < 8) return error.CborTooShort; if (iter.len < 8) return error.TooShort;
var f: f64 = undefined; var f: f64 = undefined;
var f_bytes = std.mem.asBytes(&f); var f_bytes = std.mem.asBytes(&f);
switch (native_endian) { switch (native_endian) {
@ -447,26 +449,26 @@ fn decodeFloat(comptime T: type, iter_: *[]const u8, t: CborType) CborError!T {
v = @floatCast(f); v = @floatCast(f);
iter = iter[8..]; iter = iter[8..];
}, },
else => return error.CborInvalidType, else => return error.InvalidType,
} }
iter_.* = iter; iter_.* = iter;
return v; return v;
} }
pub fn matchInt(comptime T: type, iter_: *[]const u8, val: *T) CborError!bool { pub fn matchInt(comptime T: type, iter_: *[]const u8, val: *T) Error!bool {
var iter = iter_.*; var iter = iter_.*;
const t = try decodeType(&iter); const t = try decodeType(&iter);
val.* = switch (t.major) { val.* = switch (t.major) {
0 => blk: { // positive integer 0 => blk: { // positive integer
const v = try decodePInt(&iter, t.minor); const v = try decodePInt(&iter, t.minor);
if (v > maxInt(T)) if (v > maxInt(T))
return error.CborIntegerTooLarge; return error.IntegerTooLarge;
break :blk @intCast(v); break :blk @intCast(v);
}, },
1 => blk: { // negative integer 1 => blk: { // negative integer
const v = try decodeNInt(&iter, t.minor); const v = try decodeNInt(&iter, t.minor);
if (v < minInt(T)) if (v < minInt(T))
return error.CborIntegerTooSmall; return error.IntegerTooSmall;
break :blk @intCast(v); break :blk @intCast(v);
}, },
@ -476,12 +478,12 @@ pub fn matchInt(comptime T: type, iter_: *[]const u8, val: *T) CborError!bool {
return true; return true;
} }
pub fn matchIntValue(comptime T: type, iter: *[]const u8, val: T) CborError!bool { pub fn matchIntValue(comptime T: type, iter: *[]const u8, val: T) Error!bool {
var v: T = 0; var v: T = 0;
return if (try matchInt(T, iter, &v)) v == val else false; return if (try matchInt(T, iter, &v)) v == val else false;
} }
pub fn matchBool(iter_: *[]const u8, v: *bool) CborError!bool { pub fn matchBool(iter_: *[]const u8, v: *bool) Error!bool {
var iter = iter_.*; var iter = iter_.*;
const t = try decodeType(&iter); const t = try decodeType(&iter);
if (t.major == 7) { // special if (t.major == 7) { // special
@ -499,39 +501,39 @@ pub fn matchBool(iter_: *[]const u8, v: *bool) CborError!bool {
return false; return false;
} }
fn matchBoolValue(iter: *[]const u8, val: bool) CborError!bool { fn matchBoolValue(iter: *[]const u8, val: bool) Error!bool {
var v: bool = false; var v: bool = false;
return if (try matchBool(iter, &v)) v == val else false; return if (try matchBool(iter, &v)) v == val else false;
} }
fn matchFloat(comptime T: type, iter_: *[]const u8, v: *T) CborError!bool { fn matchFloat(comptime T: type, iter_: *[]const u8, v: *T) Error!bool {
var iter = iter_.*; var iter = iter_.*;
const t = try decodeType(&iter); const t = try decodeType(&iter);
v.* = decodeFloat(T, &iter, t) catch |e| switch (e) { v.* = decodeFloat(T, &iter, t) catch |e| switch (e) {
error.CborInvalidType => return false, error.InvalidType => return false,
else => return e, else => return e,
}; };
iter_.* = iter; iter_.* = iter;
return true; return true;
} }
fn matchFloatValue(comptime T: type, iter: *[]const u8, val: T) CborError!bool { fn matchFloatValue(comptime T: type, iter: *[]const u8, val: T) Error!bool {
var v: T = 0.0; var v: T = 0.0;
return if (try matchFloat(T, iter, &v)) v == val else false; return if (try matchFloat(T, iter, &v)) v == val else false;
} }
fn skipString(iter: *[]const u8, minor: u5) CborError!void { fn skipString(iter: *[]const u8, minor: u5) Error!void {
const len: usize = @intCast(try decodePInt(iter, minor)); const len: usize = @intCast(try decodePInt(iter, minor));
if (iter.len < len) if (iter.len < len)
return error.CborTooShort; return error.TooShort;
iter.* = iter.*[len..]; iter.* = iter.*[len..];
} }
fn skipBytes(iter: *[]const u8, minor: u5) CborError!void { fn skipBytes(iter: *[]const u8, minor: u5) Error!void {
return skipString(iter, minor); return skipString(iter, minor);
} }
fn skipArray(iter: *[]const u8, minor: u5) CborError!void { fn skipArray(iter: *[]const u8, minor: u5) Error!void {
var len = try decodePInt(iter, minor); var len = try decodePInt(iter, minor);
while (len > 0) { while (len > 0) {
try skipValue(iter); try skipValue(iter);
@ -539,7 +541,7 @@ fn skipArray(iter: *[]const u8, minor: u5) CborError!void {
} }
} }
fn skipMap(iter: *[]const u8, minor: u5) CborError!void { fn skipMap(iter: *[]const u8, minor: u5) Error!void {
var len = try decodePInt(iter, minor); var len = try decodePInt(iter, minor);
len *= 2; len *= 2;
while (len > 0) { while (len > 0) {
@ -548,11 +550,11 @@ fn skipMap(iter: *[]const u8, minor: u5) CborError!void {
} }
} }
pub fn skipValue(iter: *[]const u8) CborError!void { pub fn skipValue(iter: *[]const u8) Error!void {
try skipValueType(iter, try decodeType(iter)); try skipValueType(iter, try decodeType(iter));
} }
fn skipValueType(iter: *[]const u8, t: CborType) CborError!void { fn skipValueType(iter: *[]const u8, t: CborType) Error!void {
switch (t.major) { switch (t.major) {
0 => { // positive integer 0 => { // positive integer
_ = try decodePInt(iter, t.minor); _ = try decodePInt(iter, t.minor);
@ -573,19 +575,19 @@ fn skipValueType(iter: *[]const u8, t: CborType) CborError!void {
try skipMap(iter, t.minor); try skipMap(iter, t.minor);
}, },
6 => { // tag 6 => { // tag
return error.CborInvalidType; return error.InvalidType;
}, },
7 => switch (t.type) { // special 7 => switch (t.type) { // special
cbor_magic_null, cbor_magic_false, cbor_magic_true => return, cbor_magic_null, cbor_magic_false, cbor_magic_true => return,
cbor_magic_float16 => iter.* = iter.*[2..], cbor_magic_float16 => iter.* = iter.*[2..],
cbor_magic_float32 => iter.* = iter.*[4..], cbor_magic_float32 => iter.* = iter.*[4..],
cbor_magic_float64 => iter.* = iter.*[8..], cbor_magic_float64 => iter.* = iter.*[8..],
else => return error.CborInvalidType, else => return error.InvalidType,
}, },
} }
} }
fn matchType(iter_: *[]const u8, v: *value_type) CborError!bool { fn matchType(iter_: *[]const u8, v: *value_type) Error!bool {
var iter = iter_.*; var iter = iter_.*;
const t = try decodeType(&iter); const t = try decodeType(&iter);
try skipValueType(&iter, t); try skipValueType(&iter, t);
@ -607,12 +609,12 @@ fn matchType(iter_: *[]const u8, v: *value_type) CborError!bool {
return true; return true;
} }
fn matchValueType(iter: *[]const u8, t: value_type) CborError!bool { fn matchValueType(iter: *[]const u8, t: value_type) Error!bool {
var v: value_type = value_type.unknown; var v: value_type = value_type.unknown;
return if (try matchType(iter, &v)) (t == value_type.any or t == v) else false; return if (try matchType(iter, &v)) (t == value_type.any or t == v) else false;
} }
pub fn matchString(iter_: *[]const u8, val: *[]const u8) CborError!bool { pub fn matchString(iter_: *[]const u8, val: *[]const u8) Error!bool {
var iter = iter_.*; var iter = iter_.*;
const t = try decodeType(&iter); const t = try decodeType(&iter);
val.* = switch (t.major) { val.* = switch (t.major) {
@ -624,7 +626,7 @@ pub fn matchString(iter_: *[]const u8, val: *[]const u8) CborError!bool {
return true; return true;
} }
fn matchStringValue(iter: *[]const u8, lit: []const u8) CborError!bool { fn matchStringValue(iter: *[]const u8, lit: []const u8) Error!bool {
var val: []const u8 = undefined; var val: []const u8 = undefined;
return if (try matchString(iter, &val)) eql(u8, val, lit) else false; return if (try matchString(iter, &val)) eql(u8, val, lit) else false;
} }
@ -633,7 +635,7 @@ fn matchError(comptime T: type) noreturn {
@compileError("cannot match type '" ++ @typeName(T) ++ "' to cbor stream"); @compileError("cannot match type '" ++ @typeName(T) ++ "' to cbor stream");
} }
pub fn matchValue(iter: *[]const u8, value: anytype) CborError!bool { pub fn matchValue(iter: *[]const u8, value: anytype) Error!bool {
if (@TypeOf(value) == value_type) if (@TypeOf(value) == value_type)
return matchValueType(iter, value); return matchValueType(iter, value);
const T = comptime @TypeOf(value); const T = comptime @TypeOf(value);
@ -659,7 +661,7 @@ pub fn matchValue(iter: *[]const u8, value: anytype) CborError!bool {
}; };
} }
fn matchJsonValue(iter_: *[]const u8, v: *json.Value, a: std.mem.Allocator) CborError!bool { fn matchJsonValue(iter_: *[]const u8, v: *json.Value, a: std.mem.Allocator) Error!bool {
var iter = iter_.*; var iter = iter_.*;
const t = try decodeType(&iter); const t = try decodeType(&iter);
const ret = switch (t.major) { const ret = switch (t.major) {
@ -711,7 +713,7 @@ fn matchJsonValue(iter_: *[]const u8, v: *json.Value, a: std.mem.Allocator) Cbor
return ret; return ret;
} }
fn matchArrayMore(iter_: *[]const u8, n_: u64) CborError!bool { fn matchArrayMore(iter_: *[]const u8, n_: u64) Error!bool {
var iter = iter_.*; var iter = iter_.*;
var n = n_; var n = n_;
while (n > 0) { while (n > 0) {
@ -723,7 +725,7 @@ fn matchArrayMore(iter_: *[]const u8, n_: u64) CborError!bool {
return true; return true;
} }
fn matchArray(iter_: *[]const u8, arr: anytype, info: anytype) CborError!bool { fn matchArray(iter_: *[]const u8, arr: anytype, info: anytype) Error!bool {
var iter = iter_.*; var iter = iter_.*;
var n = try decodeArrayHeader(&iter); var n = try decodeArrayHeader(&iter);
inline for (info.fields) |f| { inline for (info.fields) |f| {
@ -756,13 +758,13 @@ fn matchJsonObject(iter_: *[]const u8, obj: *json.ObjectMap) !bool {
if (t.type == cbor_magic_null) if (t.type == cbor_magic_null)
return true; return true;
if (t.major != 5) if (t.major != 5)
return error.CborInvalidType; return error.InvalidType;
const ret = try decodeJsonObject(&iter, t.minor, obj); const ret = try decodeJsonObject(&iter, t.minor, obj);
if (ret) iter_.* = iter; if (ret) iter_.* = iter;
return ret; return ret;
} }
pub fn match(buf: []const u8, pattern: anytype) CborError!bool { pub fn match(buf: []const u8, pattern: anytype) Error!bool {
var iter: []const u8 = buf; var iter: []const u8 = buf;
return matchValue(&iter, pattern); return matchValue(&iter, pattern);
} }
@ -797,7 +799,7 @@ const JsonValueExtractor = struct {
return .{ .dest = dest }; return .{ .dest = dest };
} }
pub fn extract(self: Self, iter: *[]const u8) CborError!bool { pub fn extract(self: Self, iter: *[]const u8) Error!bool {
var null_heap_: [0]u8 = undefined; var null_heap_: [0]u8 = undefined;
var heap = fba.init(&null_heap_); var heap = fba.init(&null_heap_);
return matchJsonValue(iter, self.dest, heap.allocator()); return matchJsonValue(iter, self.dest, heap.allocator());
@ -814,7 +816,7 @@ const JsonObjectExtractor = struct {
return .{ .dest = dest }; return .{ .dest = dest };
} }
pub fn extract(self: Self, iter: *[]const u8) CborError!bool { pub fn extract(self: Self, iter: *[]const u8) Error!bool {
return matchJsonObject(iter, self.dest); return matchJsonObject(iter, self.dest);
} }
}; };
@ -833,7 +835,7 @@ fn Extractor(comptime T: type) type {
return .{ .dest = dest }; return .{ .dest = dest };
} }
pub fn extract(self: Self, iter: *[]const u8) CborError!bool { pub fn extract(self: Self, iter: *[]const u8) Error!bool {
switch (comptime @typeInfo(T)) { switch (comptime @typeInfo(T)) {
.Int, .ComptimeInt => return matchInt(T, iter, self.dest), .Int, .ComptimeInt => return matchInt(T, iter, self.dest),
.Bool => return matchBool(iter, self.dest), .Bool => return matchBool(iter, self.dest),
@ -882,7 +884,7 @@ const CborExtractor = struct {
return .{ .dest = dest }; return .{ .dest = dest };
} }
pub fn extract(self: Self, iter: *[]const u8) CborError!bool { pub fn extract(self: Self, iter: *[]const u8) Error!bool {
const b = iter.*; const b = iter.*;
try skipValue(iter); try skipValue(iter);
self.dest.* = b[0..(b.len - iter.len)]; self.dest.* = b[0..(b.len - iter.len)];
@ -913,14 +915,14 @@ pub fn JsonStream(comptime T: type) type {
try w.beginObject(); try w.beginObject();
while (count > 0) : (count -= 1) { while (count > 0) : (count -= 1) {
const t = try decodeType(iter); const t = try decodeType(iter);
if (t.major != 3) return error.CborInvalidType; if (t.major != 3) return error.InvalidType;
try w.objectField(try decodeString(iter, t.minor)); try w.objectField(try decodeString(iter, t.minor));
try jsonWriteValue(w, iter); try jsonWriteValue(w, iter);
} }
try w.endObject(); try w.endObject();
} }
pub fn jsonWriteValue(w: *JsonWriter, iter: *[]const u8) (CborJsonError || Writer.Error)!void { pub fn jsonWriteValue(w: *JsonWriter, iter: *[]const u8) (JsonEncodeError || Writer.Error)!void {
const t = try decodeType(iter); const t = try decodeType(iter);
switch (t.type) { switch (t.type) {
cbor_magic_false => return w.write(false), cbor_magic_false => return w.write(false),
@ -934,17 +936,17 @@ pub fn JsonStream(comptime T: type) type {
return switch (t.major) { return switch (t.major) {
0 => w.write(try decodePInt(iter, t.minor)), // positive integer 0 => w.write(try decodePInt(iter, t.minor)), // positive integer
1 => w.write(try decodeNInt(iter, t.minor)), // negative integer 1 => w.write(try decodeNInt(iter, t.minor)), // negative integer
2 => error.CborUnsupportedType, // bytes 2 => error.UnsupportedType, // bytes
3 => w.write(try decodeString(iter, t.minor)), // string 3 => w.write(try decodeString(iter, t.minor)), // string
4 => jsonWriteArray(w, iter, t.minor), // array 4 => jsonWriteArray(w, iter, t.minor), // array
5 => jsonWriteMap(w, iter, t.minor), // map 5 => jsonWriteMap(w, iter, t.minor), // map
else => error.CborInvalidType, else => error.InvalidType,
}; };
} }
}; };
} }
pub fn toJson(cbor_buf: []const u8, json_buf: []u8) CborJsonError![]const u8 { pub fn toJson(cbor_buf: []const u8, json_buf: []u8) (JsonEncodeError || error{NoSpaceLeft})![]const u8 {
var fbs = fixedBufferStream(json_buf); var fbs = fixedBufferStream(json_buf);
var s = json.writeStream(fbs.writer(), .{}); var s = json.writeStream(fbs.writer(), .{});
var iter: []const u8 = cbor_buf; var iter: []const u8 = cbor_buf;
@ -952,7 +954,7 @@ pub fn toJson(cbor_buf: []const u8, json_buf: []u8) CborJsonError![]const u8 {
return fbs.getWritten(); return fbs.getWritten();
} }
pub fn toJsonAlloc(a: std.mem.Allocator, cbor_buf: []const u8) CborJsonError![]const u8 { pub fn toJsonAlloc(a: std.mem.Allocator, cbor_buf: []const u8) (JsonEncodeError)![]const u8 {
var buf = std.ArrayList(u8).init(a); var buf = std.ArrayList(u8).init(a);
defer buf.deinit(); defer buf.deinit();
var s = json.writeStream(buf.writer(), .{}); var s = json.writeStream(buf.writer(), .{});
@ -961,7 +963,7 @@ pub fn toJsonAlloc(a: std.mem.Allocator, cbor_buf: []const u8) CborJsonError![]c
return buf.toOwnedSlice(); return buf.toOwnedSlice();
} }
pub fn toJsonPretty(cbor_buf: []const u8, json_buf: []u8) CborJsonError![]const u8 { pub fn toJsonPretty(cbor_buf: []const u8, json_buf: []u8) (JsonEncodeError || error{NoSpaceLeft})![]const u8 {
var fbs = fixedBufferStream(json_buf); var fbs = fixedBufferStream(json_buf);
var s = json.writeStream(fbs.writer(), .{ .whitespace = .indent_1 }); var s = json.writeStream(fbs.writer(), .{ .whitespace = .indent_1 });
var iter: []const u8 = cbor_buf; var iter: []const u8 = cbor_buf;
@ -969,7 +971,7 @@ pub fn toJsonPretty(cbor_buf: []const u8, json_buf: []u8) CborJsonError![]const
return fbs.getWritten(); return fbs.getWritten();
} }
pub fn toJsonPrettyAlloc(a: std.mem.Allocator, cbor_buf: []const u8) CborJsonError![]const u8 { pub fn toJsonPrettyAlloc(a: std.mem.Allocator, cbor_buf: []const u8) JsonEncodeError![]const u8 {
var buf = std.ArrayList(u8).init(a); var buf = std.ArrayList(u8).init(a);
defer buf.deinit(); defer buf.deinit();
var s = json.writeStream(buf.writer(), .{ .whitespace = .indent_1 }); var s = json.writeStream(buf.writer(), .{ .whitespace = .indent_1 });
@ -978,7 +980,7 @@ pub fn toJsonPrettyAlloc(a: std.mem.Allocator, cbor_buf: []const u8) CborJsonErr
return buf.toOwnedSlice(); return buf.toOwnedSlice();
} }
pub fn toJsonOptsAlloc(a: std.mem.Allocator, cbor_buf: []const u8, opts: std.json.StringifyOptions) CborJsonError![]const u8 { pub fn toJsonOptsAlloc(a: std.mem.Allocator, cbor_buf: []const u8, opts: std.json.StringifyOptions) JsonEncodeError![]const u8 {
var buf = std.ArrayList(u8).init(a); var buf = std.ArrayList(u8).init(a);
defer buf.deinit(); defer buf.deinit();
var s = json.writeStream(buf.writer(), opts); var s = json.writeStream(buf.writer(), opts);
@ -996,10 +998,11 @@ fn writeJsonValue(writer: anytype, value: json.Value) !void {
}; };
} }
fn jsonScanUntil(writer: anytype, scanner: *json.Scanner, end_token: anytype) CborJsonError!usize { fn jsonScanUntil(writer: anytype, scanner: *json.Scanner, end_token: anytype) (JsonDecodeError || @TypeOf(writer).Error)!usize {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit(); defer arena.deinit();
var partial = std.ArrayList(u8).init(arena.allocator()); var sfa = std.heap.stackFallback(local_heap_size, arena.allocator());
var partial = std.ArrayList(u8).init(sfa.get());
var count: usize = 0; var count: usize = 0;
var token = try scanner.next(); var token = try scanner.next();
@ -1057,25 +1060,29 @@ fn jsonScanUntil(writer: anytype, scanner: *json.Scanner, end_token: anytype) Cb
pub const local_heap_size = 4096 * 16; pub const local_heap_size = 4096 * 16;
fn writeJsonArray(writer_: anytype, scanner: *json.Scanner) CborJsonError!void { fn writeJsonArray(writer_: anytype, scanner: *json.Scanner) (JsonDecodeError || @TypeOf(writer_).Error)!void {
var buf: [local_heap_size]u8 = undefined; var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
var stream = fixedBufferStream(&buf); defer arena.deinit();
const writer = stream.writer(); var sfa = std.heap.stackFallback(local_heap_size, arena.allocator());
var buf = std.ArrayList(u8).init(sfa.get());
const writer = buf.writer();
const count = try jsonScanUntil(writer, scanner, .array_end); const count = try jsonScanUntil(writer, scanner, .array_end);
try writeArrayHeader(writer_, count); try writeArrayHeader(writer_, count);
try writer_.writeAll(stream.getWritten()); try writer_.writeAll(buf.items);
} }
fn writeJsonObject(writer_: anytype, scanner: *json.Scanner) CborJsonError!void { fn writeJsonObject(writer_: anytype, scanner: *json.Scanner) (JsonDecodeError || @TypeOf(writer_).Error)!void {
var buf: [local_heap_size]u8 = undefined; var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
var stream = fixedBufferStream(&buf); defer arena.deinit();
const writer = stream.writer(); var sfa = std.heap.stackFallback(local_heap_size, arena.allocator());
var buf = std.ArrayList(u8).init(sfa.get());
const writer = buf.writer();
const count = try jsonScanUntil(writer, scanner, .object_end); const count = try jsonScanUntil(writer, scanner, .object_end);
try writeMapHeader(writer_, count / 2); try writeMapHeader(writer_, count / 2);
try writer_.writeAll(stream.getWritten()); try writer_.writeAll(buf.items);
} }
pub fn fromJson(json_buf: []const u8, cbor_buf: []u8) ![]const u8 { pub fn fromJson(json_buf: []const u8, cbor_buf: []u8) (JsonDecodeError || error{NoSpaceLeft})![]const u8 {
var local_heap_: [local_heap_size]u8 = undefined; var local_heap_: [local_heap_size]u8 = undefined;
var heap = fba.init(&local_heap_); var heap = fba.init(&local_heap_);
var stream = fixedBufferStream(cbor_buf); var stream = fixedBufferStream(cbor_buf);
@ -1088,7 +1095,7 @@ pub fn fromJson(json_buf: []const u8, cbor_buf: []u8) ![]const u8 {
return stream.getWritten(); return stream.getWritten();
} }
pub fn fromJsonAlloc(a: std.mem.Allocator, json_buf: []const u8) ![]const u8 { pub fn fromJsonAlloc(a: std.mem.Allocator, json_buf: []const u8) JsonDecodeError![]const u8 {
var stream = std.ArrayList(u8).init(a); var stream = std.ArrayList(u8).init(a);
defer stream.deinit(); defer stream.deinit();
const writer = stream.writer(); const writer = stream.writer();

View file

@ -47,6 +47,8 @@ pub const Ownership = enum {
Owned, Owned,
}; };
pub const CallError = error{ OutOfMemory, ThespianSpawnFailed, Timeout };
fn Pid(comptime own: Ownership) type { fn Pid(comptime own: Ownership) type {
return struct { return struct {
h: c.thespian_handle, h: c.thespian_handle,
@ -78,7 +80,7 @@ fn Pid(comptime own: Ownership) type {
return self.send_raw(message.fmt(m)); return self.send_raw(message.fmt(m));
} }
pub fn call(self: Self, a: std.mem.Allocator, timeout_ns: u64, request: anytype) error{ OutOfMemory, ThespianSpawnFailed, Timeout }!message { pub fn call(self: Self, a: std.mem.Allocator, timeout_ns: u64, request: anytype) CallError!message {
return CallContext.call(a, self.ref(), timeout_ns, message.fmt(request)); return CallContext.call(a, self.ref(), timeout_ns, message.fmt(request));
} }
@ -192,7 +194,7 @@ pub const message = struct {
return .{ .buf = try a.dupe(u8, self.buf) }; return .{ .buf = try a.dupe(u8, self.buf) };
} }
pub fn to_json(self: *const Self, buffer: []u8) cbor.CborJsonError![]const u8 { pub fn to_json(self: *const Self, buffer: []u8) (cbor.JsonEncodeError || error{NoSpaceLeft})![]const u8 {
return cbor.toJson(self.buf, buffer); return cbor.toJson(self.buf, buffer);
} }
@ -805,7 +807,7 @@ const CallContext = struct {
const Self = @This(); const Self = @This();
const ReceiverT = Receiver(*Self); const ReceiverT = Receiver(*Self);
pub fn call(a: std.mem.Allocator, to: pid_ref, timeout_ns: u64, request: message) error{ OutOfMemory, ThespianSpawnFailed, Timeout }!message { pub fn call(a: std.mem.Allocator, to: pid_ref, timeout_ns: u64, request: message) CallError!message {
var response: ?message = null; var response: ?message = null;
var self: Self = .{ var self: Self = .{
.receiver = undefined, .receiver = undefined,

View file

@ -119,20 +119,20 @@ test "cbor.matchI64 8byte" {
try expectEqual(iter[0], 0xDF); try expectEqual(iter[0], 0xDF);
} }
test "cbor.matchI64 error.CborIntegerTooLarge" { test "cbor.matchI64 error.IntegerTooLarge" {
var buf = [_]u8{ 0x1B, 0xA9, 0x0A, 0xDE, 0x0D, 0x4E, 0x2B, 0x8A, 0x1F, 0xDF }; var buf = [_]u8{ 0x1B, 0xA9, 0x0A, 0xDE, 0x0D, 0x4E, 0x2B, 0x8A, 0x1F, 0xDF };
var iter: []const u8 = &buf; var iter: []const u8 = &buf;
var val: i64 = 0; var val: i64 = 0;
const result = matchInt(i64, &iter, &val); const result = matchInt(i64, &iter, &val);
try expectError(error.CborIntegerTooLarge, result); try expectError(error.IntegerTooLarge, result);
} }
test "cbor.matchI64 error.CborTooShort" { test "cbor.matchI64 error.TooShort" {
var buf = [_]u8{ 0x19, 0x01 }; var buf = [_]u8{ 0x19, 0x01 };
var iter: []const u8 = &buf; var iter: []const u8 = &buf;
var val: i64 = 0; var val: i64 = 0;
const result = matchInt(i64, &iter, &val); const result = matchInt(i64, &iter, &val);
try expectError(error.CborTooShort, result); try expectError(error.TooShort, result);
} }
test "cbor.matchI64Value" { test "cbor.matchI64Value" {
@ -372,7 +372,7 @@ test "cbor.extract_number_limits" {
var i: i64 = undefined; var i: i64 = undefined;
const m = fmt(&buf, bigint); const m = fmt(&buf, bigint);
try expect(try match(m, extract(&u))); try expect(try match(m, extract(&u)));
try expectError(error.CborIntegerTooLarge, match(m, extract(&i))); try expectError(error.IntegerTooLarge, match(m, extract(&i)));
} }
test "cbor.toJson" { test "cbor.toJson" {