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
|
/// root starting from idx
|
||||||
pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: usize) !T {
|
pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: usize) !T {
|
||||||
const Schema = @typeInfo(T);
|
const Schema = @typeInfo(T);
|
||||||
const flags = self.language.options.flags;
|
|
||||||
|
|
||||||
if (std.meta.hasFn(T, "toJson")) {
|
if (std.meta.hasFn(T, "toJson")) {
|
||||||
return T.toJson(self, allocator, idx);
|
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)) {
|
switch (self.language.index.get(idx)) {
|
||||||
.null => {
|
.null => {
|
||||||
if (Schema == .null) return null;
|
if (Schema == .null or Schema == .optional) return null;
|
||||||
return error.TypeError;
|
|
||||||
},
|
},
|
||||||
.bool => |b| switch (Schema) {
|
.bool => |b| switch (Schema) {
|
||||||
.bool => return b,
|
.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);
|
r = @unionInit(T, field.name, b);
|
||||||
return r;
|
return r;
|
||||||
},
|
},
|
||||||
else => return error.TypeError,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
.number => |number| switch (Schema) {
|
.number => |number| switch (Schema) {
|
||||||
.int, .comptime_int => return @intCast(number.int),
|
.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);
|
const int: structInfo.backing_integer.? = @intCast(number.int);
|
||||||
return @bitCast(int);
|
return @bitCast(int);
|
||||||
},
|
},
|
||||||
else => return error.TypeError,
|
else => unreachable, // may only cast packed structs
|
||||||
},
|
},
|
||||||
.@"union" => |unionInfo| {
|
.@"union" => |unionInfo| {
|
||||||
inline for (unionInfo.fields) |field| switch (@typeInfo(field.type)) {
|
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| {
|
.array => |arrayInfo| {
|
||||||
assert(arrayInfo.child == u8);
|
assert(arrayInfo.child == u8);
|
||||||
|
|
||||||
const strslice = string.slice(&self.language.strings);
|
const strslice = string.slice(&self.language.strings);
|
||||||
assert(arrayInfo.len == strslice.len - 1);
|
assert(arrayInfo.len == strslice.len - 1);
|
||||||
|
|
||||||
var r: T = undefined;
|
var r: T = undefined;
|
||||||
|
|
||||||
for (strslice, 0..) |char, i|
|
for (strslice, 0..) |char, i| r[i] = char;
|
||||||
r[i] = char;
|
|
||||||
return r;
|
return r;
|
||||||
},
|
},
|
||||||
.pointer => |ptrInfo| switch (ptrInfo.size) {
|
.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();
|
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) {
|
.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| {
|
.array => |arrayInfo| {
|
||||||
assert(slice.len == arrayInfo.len);
|
assert(slice.len == arrayInfo.len);
|
||||||
var r: T = undefined;
|
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);
|
var r: T = try allocator.alloc(ptrInfo.child, slice.len);
|
||||||
|
|
||||||
if (ptrInfo.sentinel_ptr) |some| {
|
if (ptrInfo.sentinel_ptr) |some| {
|
||||||
const sentinel = @as(*align(1) const ptrInfo.child, @ptrCast(some)).*;
|
r[slice.len - 1] = blk: {
|
||||||
r[slice.len - 1] = sentinel;
|
const sentinel: *align(1) const ptrInfo.child = @ptrCast(some);
|
||||||
|
break :blk sentinel.*;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
for (0..slice.len) |i| {
|
for (0..slice.len) |i| {
|
||||||
@ -164,9 +197,9 @@ pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: us
|
|||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
},
|
},
|
||||||
else => return error.TypeError,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
else => return error.TypeError,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
.object => |object| switch (Schema) {
|
.object => |object| switch (Schema) {
|
||||||
.@"struct" => |structInfo| {
|
.@"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| {
|
if (map.get(field.name)) |next_i| {
|
||||||
@field(r, field.name) = try self.reflectT(field.type, allocator, next_i);
|
@field(r, field.name) = try self.reflectT(field.type, allocator, next_i);
|
||||||
} else switch (@typeInfo(field.type)) {
|
} else switch (@typeInfo(field.type)) {
|
||||||
.optional => {
|
.optional => @field(r, field.name) = null,
|
||||||
if (flags.bitfields)
|
|
||||||
@field(r, field.name) = null;
|
|
||||||
@panic("Unknown property: " ++ field.name);
|
|
||||||
},
|
|
||||||
else => @panic("Unknown property: " ++ field.name),
|
else => @panic("Unknown property: " ++ field.name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
},
|
},
|
||||||
else => return error.TypeError,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,7 +250,8 @@ test reflectT {
|
|||||||
\\ "flags": 0,
|
\\ "flags": 0,
|
||||||
\\ "union": ":D",
|
\\ "union": ":D",
|
||||||
\\ "enum": "world",
|
\\ "enum": "world",
|
||||||
\\ "many": [1,2,3]
|
\\ "many": [1,2,3],
|
||||||
|
\\ "tuple": [1, 2]
|
||||||
\\}
|
\\}
|
||||||
;
|
;
|
||||||
var self = try allocator.create(Self);
|
var self = try allocator.create(Self);
|
||||||
@ -245,6 +275,7 @@ test reflectT {
|
|||||||
@"union": union { hi: bool, bye: f64, n128: []const u8 },
|
@"union": union { hi: bool, bye: f64, n128: []const u8 },
|
||||||
@"enum": enum { hello, world },
|
@"enum": enum { hello, world },
|
||||||
many: []const u8,
|
many: []const u8,
|
||||||
|
tuple: struct { u64, u64 },
|
||||||
};
|
};
|
||||||
|
|
||||||
const root = try self.reflectT(UserSchema, allocator, idx);
|
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("hello? {s}\n", .{@tagName(root.@"enum")});
|
||||||
std.debug.print("friend? {s}\n", .{root.@"union".n128});
|
std.debug.print("friend? {s}\n", .{root.@"union".n128});
|
||||||
std.debug.print("many: {any}\n", .{root.many});
|
std.debug.print("many: {any}\n", .{root.many});
|
||||||
|
std.debug.print("tuple: {any}\n", .{root.tuple});
|
||||||
allocator.free(root.many);
|
allocator.free(root.many);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,19 +300,18 @@ pub const Ruleset = packed struct {
|
|||||||
allow_data_cast: bool = false,
|
allow_data_cast: bool = false,
|
||||||
/// ignore comments
|
/// ignore comments
|
||||||
allow_comments: bool = false,
|
allow_comments: bool = false,
|
||||||
|
/// whether to print '*T' as int
|
||||||
|
allow_derefptrs: bool = false,
|
||||||
/// prettify the output
|
/// prettify the output
|
||||||
pretty: bool = false,
|
pretty: bool = false,
|
||||||
|
|
||||||
pub const Pedantic = Ruleset{
|
pub const Pedantic = Ruleset{};
|
||||||
.allow_bitfields = false,
|
|
||||||
.allow_data_cast = false,
|
|
||||||
.allow_comments = false,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Chill = Ruleset{
|
pub const Chill = Ruleset{
|
||||||
.allow_bitfields = true,
|
.allow_bitfields = true,
|
||||||
.allow_data_cast = true,
|
.allow_data_cast = true,
|
||||||
.allow_comments = 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) {
|
if (options.ruleset.allow_data_cast) {
|
||||||
const i: enumInfo.tag_type = @intFromEnum(raw);
|
const i: enumInfo.tag_type = @intFromEnum(raw);
|
||||||
return std.fmt.bufPrint(&buf, "{d}", .{i});
|
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) {
|
.@"struct" => |structInfo| switch (structInfo.layout) {
|
||||||
.@"packed" => {
|
.@"packed" => {
|
||||||
if (options.ruleset.allow_bitfields) {
|
if (options.ruleset.allow_bitfields) {
|
||||||
const i: structInfo.backing_integer.? = @bitCast(raw);
|
const i: structInfo.backing_integer.? = @bitCast(raw);
|
||||||
return std.fmt.bufPrint(&buf, "{d}", .{i});
|
return std.fmt.bufPrint(&buf, "{d}", .{i});
|
||||||
} else {
|
|
||||||
return error.TypeError;
|
|
||||||
}
|
}
|
||||||
|
return error.TypeError;
|
||||||
},
|
},
|
||||||
.auto, .@"extern" => {
|
.auto, .@"extern" => {
|
||||||
var string: std.ArrayListUnmanaged(u8) = .empty;
|
var string: std.ArrayListUnmanaged(u8) = .empty;
|
||||||
@ -380,6 +409,16 @@ pub fn stringify(raw: anytype, comptime options: Options) ![]const u8 {
|
|||||||
return string.toOwnedSlice();
|
return string.toOwnedSlice();
|
||||||
},
|
},
|
||||||
.pointer => |ptrInfo| switch (ptrInfo.size) {
|
.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 => {
|
.slice => {
|
||||||
if (ptrInfo.child == u8) {
|
if (ptrInfo.child == u8) {
|
||||||
if (ptrInfo.is_const)
|
if (ptrInfo.is_const)
|
||||||
@ -422,9 +461,8 @@ pub fn stringify(raw: anytype, comptime options: Options) ![]const u8 {
|
|||||||
return error.TypeError;
|
return error.TypeError;
|
||||||
}
|
}
|
||||||
unreachable;
|
unreachable;
|
||||||
} else {
|
|
||||||
return error.TypeError;
|
|
||||||
}
|
}
|
||||||
|
unreachable; // union has no tag
|
||||||
},
|
},
|
||||||
else => |t| @compileError("Error on " ++ @tagName(t)),
|
else => |t| @compileError("Error on " ++ @tagName(t)),
|
||||||
}
|
}
|
||||||
@ -451,7 +489,10 @@ test stringify {
|
|||||||
},
|
},
|
||||||
@"enum": enum { hello, world },
|
@"enum": enum { hello, world },
|
||||||
many: []const u8,
|
many: []const u8,
|
||||||
|
epicptr: *const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const e: []const u8 = "epic pointer";
|
||||||
const user = UserSchema{
|
const user = UserSchema{
|
||||||
.age = 15.0,
|
.age = 15.0,
|
||||||
.name = "Yuzu",
|
.name = "Yuzu",
|
||||||
@ -460,6 +501,7 @@ test stringify {
|
|||||||
.@"union" = .{ .hi = true },
|
.@"union" = .{ .hi = true },
|
||||||
.@"enum" = .world,
|
.@"enum" = .world,
|
||||||
.many = "hello",
|
.many = "hello",
|
||||||
|
.epicptr = @ptrCast(e[0..1]),
|
||||||
};
|
};
|
||||||
|
|
||||||
const options = Options{
|
const options = Options{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user