minor improvements
This commit is contained in:
parent
25aa6fa37d
commit
656bc667e6
104
reflection.zig
104
reflection.zig
@ -37,7 +37,6 @@ pub fn deinit(self: *Self, allocator: mem.Allocator) void {
|
||||
/// root starting from idx
|
||||
pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: usize) !T {
|
||||
const Schema = @typeInfo(T);
|
||||
const flags = self.language.options.flags;
|
||||
|
||||
if (std.meta.hasFn(T, "toJson")) {
|
||||
return T.toJson(self, allocator, idx);
|
||||
@ -45,8 +44,7 @@ pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: us
|
||||
|
||||
switch (self.language.index.get(idx)) {
|
||||
.null => {
|
||||
if (Schema == .null) return null;
|
||||
return error.TypeError;
|
||||
if (Schema == .null or Schema == .optional) return null;
|
||||
},
|
||||
.bool => |b| switch (Schema) {
|
||||
.bool => return b,
|
||||
@ -55,7 +53,7 @@ pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: us
|
||||
r = @unionInit(T, field.name, b);
|
||||
return r;
|
||||
},
|
||||
else => return error.TypeError,
|
||||
else => unreachable,
|
||||
},
|
||||
.number => |number| switch (Schema) {
|
||||
.int, .comptime_int => return @intCast(number.int),
|
||||
@ -72,7 +70,7 @@ pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: us
|
||||
const int: structInfo.backing_integer.? = @intCast(number.int);
|
||||
return @bitCast(int);
|
||||
},
|
||||
else => return error.TypeError,
|
||||
else => unreachable, // may only cast packed structs
|
||||
},
|
||||
.@"union" => |unionInfo| {
|
||||
inline for (unionInfo.fields) |field| switch (@typeInfo(field.type)) {
|
||||
@ -101,13 +99,13 @@ pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: us
|
||||
},
|
||||
.array => |arrayInfo| {
|
||||
assert(arrayInfo.child == u8);
|
||||
|
||||
const strslice = string.slice(&self.language.strings);
|
||||
assert(arrayInfo.len == strslice.len - 1);
|
||||
|
||||
var r: T = undefined;
|
||||
|
||||
for (strslice, 0..) |char, i|
|
||||
r[i] = char;
|
||||
for (strslice, 0..) |char, i| r[i] = char;
|
||||
return r;
|
||||
},
|
||||
.pointer => |ptrInfo| switch (ptrInfo.size) {
|
||||
@ -135,11 +133,44 @@ pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: us
|
||||
}
|
||||
return try arraylist.toOwnedSlice();
|
||||
},
|
||||
else => return error.TypeError,
|
||||
.many => {
|
||||
assert(ptrInfo.child == u8);
|
||||
const strslice = string.slice(&self.language.strings);
|
||||
var arraylist: std.ArrayList(u8) = .init(allocator);
|
||||
try arraylist.ensureUnusedCapacity(strslice.len);
|
||||
|
||||
for (strslice) |char|
|
||||
arraylist.appendAssumeCapacity(char);
|
||||
|
||||
if (ptrInfo.sentinel_ptr) |some| {
|
||||
return arraylist.toOwnedSliceSentinel(blk: {
|
||||
const sentinel: *align(1) const ptrInfo.child = @ptrCast(some);
|
||||
break :blk sentinel.*;
|
||||
});
|
||||
}
|
||||
return arraylist.toOwnedSlice();
|
||||
},
|
||||
else => return error.TypeError,
|
||||
else => unreachable,
|
||||
},
|
||||
else => unreachable,
|
||||
},
|
||||
.array => |slice| switch (Schema) {
|
||||
.@"struct" => |structInfo| {
|
||||
if (structInfo.is_tuple) {
|
||||
assert(structInfo.fields.len == slice.len);
|
||||
|
||||
var r: T = undefined;
|
||||
inline for (structInfo.fields, 0..slice.len) |field, i| {
|
||||
if (field.is_comptime)
|
||||
@panic(@typeName(T) ++ "." ++ field.name ++ " may not be a comptime field");
|
||||
|
||||
@field(r, field.name) = try self.reflectT(field.type, allocator, slice.tip + i);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
unreachable; // may only reflect tuples
|
||||
},
|
||||
.array => |arrayInfo| {
|
||||
assert(slice.len == arrayInfo.len);
|
||||
var r: T = undefined;
|
||||
@ -153,8 +184,10 @@ pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: us
|
||||
var r: T = try allocator.alloc(ptrInfo.child, slice.len);
|
||||
|
||||
if (ptrInfo.sentinel_ptr) |some| {
|
||||
const sentinel = @as(*align(1) const ptrInfo.child, @ptrCast(some)).*;
|
||||
r[slice.len - 1] = sentinel;
|
||||
r[slice.len - 1] = blk: {
|
||||
const sentinel: *align(1) const ptrInfo.child = @ptrCast(some);
|
||||
break :blk sentinel.*;
|
||||
};
|
||||
}
|
||||
|
||||
for (0..slice.len) |i| {
|
||||
@ -164,9 +197,9 @@ pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: us
|
||||
}
|
||||
return r;
|
||||
},
|
||||
else => return error.TypeError,
|
||||
else => unreachable,
|
||||
},
|
||||
else => return error.TypeError,
|
||||
else => unreachable,
|
||||
},
|
||||
.object => |object| switch (Schema) {
|
||||
.@"struct" => |structInfo| {
|
||||
@ -192,18 +225,14 @@ pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: us
|
||||
if (map.get(field.name)) |next_i| {
|
||||
@field(r, field.name) = try self.reflectT(field.type, allocator, next_i);
|
||||
} else switch (@typeInfo(field.type)) {
|
||||
.optional => {
|
||||
if (flags.bitfields)
|
||||
@field(r, field.name) = null;
|
||||
@panic("Unknown property: " ++ field.name);
|
||||
},
|
||||
.optional => @field(r, field.name) = null,
|
||||
else => @panic("Unknown property: " ++ field.name),
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
},
|
||||
else => return error.TypeError,
|
||||
else => unreachable,
|
||||
},
|
||||
}
|
||||
|
||||
@ -221,7 +250,8 @@ test reflectT {
|
||||
\\ "flags": 0,
|
||||
\\ "union": ":D",
|
||||
\\ "enum": "world",
|
||||
\\ "many": [1,2,3]
|
||||
\\ "many": [1,2,3],
|
||||
\\ "tuple": [1, 2]
|
||||
\\}
|
||||
;
|
||||
var self = try allocator.create(Self);
|
||||
@ -245,6 +275,7 @@ test reflectT {
|
||||
@"union": union { hi: bool, bye: f64, n128: []const u8 },
|
||||
@"enum": enum { hello, world },
|
||||
many: []const u8,
|
||||
tuple: struct { u64, u64 },
|
||||
};
|
||||
|
||||
const root = try self.reflectT(UserSchema, allocator, idx);
|
||||
@ -252,6 +283,7 @@ test reflectT {
|
||||
std.debug.print("hello? {s}\n", .{@tagName(root.@"enum")});
|
||||
std.debug.print("friend? {s}\n", .{root.@"union".n128});
|
||||
std.debug.print("many: {any}\n", .{root.many});
|
||||
std.debug.print("tuple: {any}\n", .{root.tuple});
|
||||
allocator.free(root.many);
|
||||
}
|
||||
|
||||
@ -268,19 +300,18 @@ pub const Ruleset = packed struct {
|
||||
allow_data_cast: bool = false,
|
||||
/// ignore comments
|
||||
allow_comments: bool = false,
|
||||
/// whether to print '*T' as int
|
||||
allow_derefptrs: bool = false,
|
||||
/// prettify the output
|
||||
pretty: bool = false,
|
||||
|
||||
pub const Pedantic = Ruleset{
|
||||
.allow_bitfields = false,
|
||||
.allow_data_cast = false,
|
||||
.allow_comments = false,
|
||||
};
|
||||
pub const Pedantic = Ruleset{};
|
||||
|
||||
pub const Chill = Ruleset{
|
||||
.allow_bitfields = true,
|
||||
.allow_data_cast = true,
|
||||
.allow_comments = true,
|
||||
.allow_derefptrs = true,
|
||||
};
|
||||
};
|
||||
|
||||
@ -321,18 +352,16 @@ pub fn stringify(raw: anytype, comptime options: Options) ![]const u8 {
|
||||
if (options.ruleset.allow_data_cast) {
|
||||
const i: enumInfo.tag_type = @intFromEnum(raw);
|
||||
return std.fmt.bufPrint(&buf, "{d}", .{i});
|
||||
} else {
|
||||
return std.fmt.bufPrint(&buf, "{s}", .{@tagName(raw)});
|
||||
}
|
||||
return std.fmt.bufPrint(&buf, "{s}", .{@tagName(raw)});
|
||||
},
|
||||
.@"struct" => |structInfo| switch (structInfo.layout) {
|
||||
.@"packed" => {
|
||||
if (options.ruleset.allow_bitfields) {
|
||||
const i: structInfo.backing_integer.? = @bitCast(raw);
|
||||
return std.fmt.bufPrint(&buf, "{d}", .{i});
|
||||
} else {
|
||||
return error.TypeError;
|
||||
}
|
||||
return error.TypeError;
|
||||
},
|
||||
.auto, .@"extern" => {
|
||||
var string: std.ArrayListUnmanaged(u8) = .empty;
|
||||
@ -380,6 +409,16 @@ pub fn stringify(raw: anytype, comptime options: Options) ![]const u8 {
|
||||
return string.toOwnedSlice();
|
||||
},
|
||||
.pointer => |ptrInfo| switch (ptrInfo.size) {
|
||||
.one => {
|
||||
if (options.ruleset.allow_derefptrs) {
|
||||
return stringify(blk: {
|
||||
const ptr: *align(ptrInfo.alignment) const ptrInfo.child = @ptrCast(raw);
|
||||
break :blk ptr.*;
|
||||
}, options);
|
||||
}
|
||||
|
||||
return std.fmt.bufPrint(&buf, "{d}", .{@intFromPtr(raw)});
|
||||
},
|
||||
.slice => {
|
||||
if (ptrInfo.child == u8) {
|
||||
if (ptrInfo.is_const)
|
||||
@ -422,9 +461,8 @@ pub fn stringify(raw: anytype, comptime options: Options) ![]const u8 {
|
||||
return error.TypeError;
|
||||
}
|
||||
unreachable;
|
||||
} else {
|
||||
return error.TypeError;
|
||||
}
|
||||
unreachable; // union has no tag
|
||||
},
|
||||
else => |t| @compileError("Error on " ++ @tagName(t)),
|
||||
}
|
||||
@ -451,7 +489,10 @@ test stringify {
|
||||
},
|
||||
@"enum": enum { hello, world },
|
||||
many: []const u8,
|
||||
epicptr: *const u8,
|
||||
};
|
||||
|
||||
const e: []const u8 = "epic pointer";
|
||||
const user = UserSchema{
|
||||
.age = 15.0,
|
||||
.name = "Yuzu",
|
||||
@ -460,6 +501,7 @@ test stringify {
|
||||
.@"union" = .{ .hi = true },
|
||||
.@"enum" = .world,
|
||||
.many = "hello",
|
||||
.epicptr = @ptrCast(e[0..1]),
|
||||
};
|
||||
|
||||
const options = Options{
|
||||
|
Loading…
x
Reference in New Issue
Block a user