feat: add support for allocating extractors
This commit is contained in:
parent
285f64ede6
commit
769bff078f
1 changed files with 97 additions and 2 deletions
99
src/cbor.zig
99
src/cbor.zig
|
@ -818,7 +818,11 @@ pub fn match(buf: []const u8, pattern: anytype) Error!bool {
|
|||
}
|
||||
|
||||
fn extractError(comptime T: type) noreturn {
|
||||
@compileError("cannot extract type '" ++ @typeName(T) ++ "' from cbor stream");
|
||||
@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");
|
||||
}
|
||||
|
||||
fn hasExtractorTag(info: anytype) bool {
|
||||
|
@ -837,6 +841,79 @@ 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();
|
||||
|
@ -914,7 +991,10 @@ 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 Extractor(T_type_info.pointer.child);
|
||||
return if (isExtractableAlloc(T_type_info.pointer.child))
|
||||
extractErrorAlloc(T_type_info.pointer.child)
|
||||
else
|
||||
Extractor(T_type_info.pointer.child);
|
||||
}
|
||||
|
||||
pub fn extract(dest: anytype) ExtractorType(@TypeOf(dest)) {
|
||||
|
@ -925,6 +1005,21 @@ 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();
|
||||
|
|
Loading…
Add table
Reference in a new issue