Compare commits

..

No commits in common. "master" and "v1.0.0" have entirely different histories.

View file

@ -16,11 +16,6 @@ pub const Error = error{
InvalidType,
TooShort,
OutOfMemory,
InvalidFloatType,
InvalidArrayType,
InvalidPIntType,
JsonIncompatibleType,
NotAnObject,
};
pub const JsonEncodeError = (Error || error{
@ -127,8 +122,8 @@ pub fn writeMapHeader(writer: anytype, sz: usize) @TypeOf(writer).Error!void {
pub fn writeArray(writer: anytype, args: anytype) @TypeOf(writer).Error!void {
const args_type_info = @typeInfo(@TypeOf(args));
if (args_type_info != .@"struct") @compileError("expected tuple or struct argument");
const fields_info = args_type_info.@"struct".fields;
if (args_type_info != .Struct) @compileError("expected tuple or struct argument");
const fields_info = args_type_info.Struct.fields;
try writeArrayHeader(writer, fields_info.len);
inline for (fields_info) |field_info|
try writeValue(writer, @field(args, field_info.name));
@ -220,9 +215,6 @@ pub fn writeValue(writer: anytype, value: anytype) @TypeOf(writer).Error!void {
.error_union => return if (value) |v| writeValue(writer, v) else |err| writeValue(writer, err),
.error_set => return writeErrorset(writer, value),
.@"union" => |info| {
if (std.meta.hasFn(T, "cborEncode")) {
return value.cborEncode(writer);
}
if (info.tag_type) |TagType| {
comptime var v = void;
inline for (info.fields) |u_field| {
@ -239,9 +231,6 @@ pub fn writeValue(writer: anytype, value: anytype) @TypeOf(writer).Error!void {
}
},
.@"struct" => |info| {
if (std.meta.hasFn(T, "cborEncode")) {
return value.cborEncode(writer);
}
if (info.is_tuple) {
if (info.fields.len == 0) return writeNull(writer);
try writeArrayHeader(writer, info.fields.len);
@ -288,12 +277,6 @@ pub fn writeValue(writer: anytype, value: anytype) @TypeOf(writer).Error!void {
64 => try writeF64(writer, value),
else => @compileError("cannot write type '" ++ @typeName(T) ++ "' to cbor stream"),
},
.@"enum" => {
if (std.meta.hasFn(T, "cborEncode")) {
return value.cborEncode(writer);
}
return writeString(writer, @tagName(value));
},
else => @compileError("cannot write type '" ++ @typeName(T) ++ "' to cbor stream"),
}
}
@ -315,7 +298,7 @@ pub fn decodeType(iter: *[]const u8) error{TooShort}!CborType {
return .{ .type = type_, .minor = bits.minor, .major = bits.major };
}
fn decodeUIntLengthRecurse(iter: *[]const u8, length: usize, acc: u64) error{TooShort}!u64 {
fn decodeUIntLengthRecurse(iter: *[]const u8, length: usize, acc: u64) !u64 {
if (iter.len < 1)
return error.TooShort;
const v: u8 = iter.*[0];
@ -332,14 +315,14 @@ fn decodeUIntLength(iter: *[]const u8, length: usize) !u64 {
return decodeUIntLengthRecurse(iter, length, 0);
}
fn decodePInt(iter: *[]const u8, minor: u5) error{ TooShort, InvalidPIntType }!u64 {
fn decodePInt(iter: *[]const u8, minor: u5) !u64 {
if (minor < 24) return minor;
return switch (minor) {
24 => decodeUIntLength(iter, 1), // 1 byte
25 => decodeUIntLength(iter, 2), // 2 byte
26 => decodeUIntLength(iter, 4), // 4 byte
27 => decodeUIntLength(iter, 8), // 8 byte
else => error.InvalidPIntType,
else => error.InvalidType,
};
}
@ -347,21 +330,21 @@ fn decodeNInt(iter: *[]const u8, minor: u5) Error!i64 {
return -@as(i64, @intCast(try decodePInt(iter, minor) + 1));
}
pub fn decodeMapHeader(iter: *[]const u8) error{ TooShort, InvalidMapType, InvalidPIntType }!usize {
pub fn decodeMapHeader(iter: *[]const u8) Error!usize {
const t = try decodeType(iter);
if (t.type == cbor_magic_null)
return 0;
if (t.major != 5)
return error.InvalidMapType;
return error.InvalidType;
return @intCast(try decodePInt(iter, t.minor));
}
pub fn decodeArrayHeader(iter: *[]const u8) error{ TooShort, InvalidArrayType, InvalidPIntType }!usize {
pub fn decodeArrayHeader(iter: *[]const u8) Error!usize {
const t = try decodeType(iter);
if (t.type == cbor_magic_null)
return 0;
if (t.major != 4)
return error.InvalidArrayType;
return error.InvalidType;
return @intCast(try decodePInt(iter, t.minor));
}
@ -466,7 +449,7 @@ fn decodeFloat(comptime T: type, iter_: *[]const u8, t: CborType) Error!T {
v = @floatCast(f);
iter = iter[8..];
},
else => return error.InvalidFloatType,
else => return error.InvalidType,
}
iter_.* = iter;
return v;
@ -760,11 +743,7 @@ fn matchArrayMore(iter_: *[]const u8, n_: u64) Error!bool {
fn matchArray(iter_: *[]const u8, arr: anytype, info: anytype) Error!bool {
var iter = iter_.*;
var n = decodeArrayHeader(&iter) catch |e| switch (e) {
error.InvalidArrayType => return false,
error.InvalidPIntType => return e,
error.TooShort => return e,
};
var n = try decodeArrayHeader(&iter);
inline for (info.fields) |f| {
const value = @field(arr, f.name);
if (isMore(value))
@ -789,25 +768,13 @@ fn matchArray(iter_: *[]const u8, arr: anytype, info: anytype) Error!bool {
return n == 0;
}
fn matchArrayScalar(iter: *[]const u8, arr: anytype) Error!bool {
var i: usize = 0;
var n = try decodeArrayHeader(iter);
if (n != arr.len) return false;
while (n > 0) : (n -= 1) {
if (!(matchValue(iter, extract(&arr[i])) catch return false))
return false;
i += 1;
}
return true;
}
fn matchJsonObject(iter_: *[]const u8, obj: *json.ObjectMap) !bool {
var iter = iter_.*;
const t = try decodeType(&iter);
if (t.type == cbor_magic_null)
return true;
if (t.major != 5)
return error.NotAnObject;
return error.InvalidType;
const ret = try decodeJsonObject(&iter, t.minor, obj);
if (ret) iter_.* = iter;
return ret;
@ -819,11 +786,7 @@ pub fn match(buf: []const u8, pattern: anytype) Error!bool {
}
fn extractError(comptime T: type) noreturn {
@compileError("cannot extract type '" ++ @typeName(T) ++ "' from a cbor stream");
}
fn extractErrorAlloc(comptime T: type) noreturn {
@compileError("extracting type '" ++ @typeName(T) ++ "' from a cbor stream requires an allocating extractor, use extractAlloc");
@compileError("cannot extract type '" ++ @typeName(T) ++ "' from cbor stream");
}
fn hasExtractorTag(info: anytype) bool {
@ -842,79 +805,6 @@ fn isExtractor(comptime T: type) bool {
};
}
fn ExtractDef(comptime T: type) type {
return fn (*T, *[]const u8) Error!bool;
}
fn hasExtractMethod(T: type, info: anytype) bool {
const result = blk: {
if (info.is_tuple) break :blk false;
for (info.decls) |decl| {
if (std.mem.eql(u8, decl.name, "cborExtract") and @TypeOf(@field(T, decl.name)) == ExtractDef(T))
break :blk true;
}
break :blk false;
};
// @compileLog("hasExtractMethod", @typeName(T), result);
return result;
}
pub fn isExtractable(comptime T: type) bool {
return comptime switch (@typeInfo(T)) {
.@"struct" => |info| hasExtractMethod(T, info),
.@"enum" => |info| hasExtractMethod(T, info),
.@"union" => |info| hasExtractMethod(T, info),
else => false,
};
}
fn ExtractAllocDef(comptime T: type) type {
return fn (*T, *[]const u8, std.mem.Allocator) Error!bool;
}
fn hasExtractMethodAlloc(T: type, info: anytype) bool {
const result = blk: {
if (@hasField(@TypeOf(info), "is_tuple") and info.is_tuple) break :blk false;
for (info.decls) |decl| {
if (std.mem.eql(u8, decl.name, "cborExtract") and @TypeOf(@field(T, decl.name)) == ExtractAllocDef(T))
break :blk true;
}
break :blk false;
};
// @compileLog("hasExtractMethodAlloc", @typeName(T), result);
return result;
}
pub fn isExtractableAlloc(comptime T: type) bool {
return comptime switch (@typeInfo(T)) {
.@"struct" => |info| hasExtractMethodAlloc(T, info),
.@"enum" => |info| hasExtractMethodAlloc(T, info),
.@"union" => |info| hasExtractMethodAlloc(T, info),
else => false,
};
}
fn GenericExtractorAlloc(T: type) type {
return struct {
dest: *T,
allocator: std.mem.Allocator,
const Self = @This();
pub const EXTRACTOR_TAG = struct {};
pub fn init(dest: *T, allocator: std.mem.Allocator) Self {
return .{ .dest = dest, .allocator = allocator };
}
pub fn extract(self: Self, iter: *[]const u8) Error!bool {
if (comptime isExtractableAlloc(T)) {
return self.dest.cborExtract(iter, self.allocator);
} else {
return self.dest.cborExtract(iter);
}
}
};
}
const JsonValueExtractor = struct {
dest: *T,
const Self = @This();
@ -982,8 +872,7 @@ fn Extractor(comptime T: type) type {
},
.float => return matchFloat(T, iter, self.dest),
.@"enum" => return matchEnum(T, iter, self.dest),
.array => return matchArrayScalar(iter, self.dest),
else => return self.dest.cborExtract(iter),
else => extractError(T),
}
}
};
@ -992,10 +881,7 @@ fn Extractor(comptime T: type) type {
fn ExtractorType(comptime T: type) type {
const T_type_info = @typeInfo(T);
if (T_type_info != .pointer) @compileError("extract requires a pointer argument");
return if (isExtractableAlloc(T_type_info.pointer.child))
extractErrorAlloc(T_type_info.pointer.child)
else
Extractor(T_type_info.pointer.child);
return Extractor(T_type_info.pointer.child);
}
pub fn extract(dest: anytype) ExtractorType(@TypeOf(dest)) {
@ -1006,21 +892,6 @@ pub fn extract(dest: anytype) ExtractorType(@TypeOf(dest)) {
return ExtractorType(@TypeOf(dest)).init(dest);
}
fn ExtractorTypeAlloc(comptime T: type) type {
const T_type_info = @typeInfo(T);
if (T_type_info != .pointer) @compileError("extractAlloc requires a pointer argument");
// @compileLog("ExtractorTypeAlloc", @typeName(T), isExtractableAlloc(T_type_info.pointer.child));
return GenericExtractorAlloc(T_type_info.pointer.child);
}
pub fn extractAlloc(dest: anytype, allocator: std.mem.Allocator) ExtractorTypeAlloc(@TypeOf(dest)) {
comptime {
if (!isExtractor(ExtractorTypeAlloc(@TypeOf(dest))))
@compileError("isExtractor self check failed for " ++ @typeName(ExtractorTypeAlloc(@TypeOf(dest))));
}
return ExtractorTypeAlloc(@TypeOf(dest)).init(dest, allocator);
}
const CborExtractor = struct {
dest: *[]const u8,
const Self = @This();
@ -1089,7 +960,7 @@ pub fn JsonStreamWriter(comptime Writer: type) type {
3 => w.write(try decodeString(iter, t.minor)), // string
4 => jsonWriteArray(w, iter, t.minor), // array
5 => jsonWriteMap(w, iter, t.minor), // map
else => error.JsonIncompatibleType,
else => error.InvalidType,
};
}
};