mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
Merge 775b5cc566 into 9082b004b6
This commit is contained in:
commit
120811b6c6
2 changed files with 200 additions and 106 deletions
|
|
@ -122,7 +122,7 @@ pub fn valueMaxDepth(self: *Serializer, val: anytype, options: ValueOptions, dep
|
||||||
|
|
||||||
/// Serialize a value, similar to `serializeArbitraryDepth`.
|
/// Serialize a value, similar to `serializeArbitraryDepth`.
|
||||||
pub fn valueArbitraryDepth(self: *Serializer, val: anytype, options: ValueOptions) Error!void {
|
pub fn valueArbitraryDepth(self: *Serializer, val: anytype, options: ValueOptions) Error!void {
|
||||||
comptime assert(canSerializeType(@TypeOf(val)));
|
comptime assertCanSerializeType(@TypeOf(val));
|
||||||
switch (@typeInfo(@TypeOf(val))) {
|
switch (@typeInfo(@TypeOf(val))) {
|
||||||
.int, .comptime_int => if (options.emit_codepoint_literals.emitAsCodepoint(val)) |c| {
|
.int, .comptime_int => if (options.emit_codepoint_literals.emitAsCodepoint(val)) |c| {
|
||||||
self.codePoint(c) catch |err| switch (err) {
|
self.codePoint(c) catch |err| switch (err) {
|
||||||
|
|
@ -321,7 +321,7 @@ pub fn tupleArbitraryDepth(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tupleImpl(self: *Serializer, val: anytype, options: ValueOptions) Error!void {
|
fn tupleImpl(self: *Serializer, val: anytype, options: ValueOptions) Error!void {
|
||||||
comptime assert(canSerializeType(@TypeOf(val)));
|
comptime assertCanSerializeType(@TypeOf(val));
|
||||||
switch (@typeInfo(@TypeOf(val))) {
|
switch (@typeInfo(@TypeOf(val))) {
|
||||||
.@"struct" => {
|
.@"struct" => {
|
||||||
var container = try self.beginTuple(.{ .whitespace_style = .{ .fields = val.len } });
|
var container = try self.beginTuple(.{ .whitespace_style = .{ .fields = val.len } });
|
||||||
|
|
@ -812,17 +812,36 @@ test checkValueDepth {
|
||||||
try expectValueDepthEquals(3, @as([]const []const u8, &.{&.{ 1, 2, 3 }}));
|
try expectValueDepthEquals(3, @as([]const []const u8, &.{&.{ 1, 2, 3 }}));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn canSerializeType(T: type) bool {
|
fn assertCanSerializeType(T: type) void {
|
||||||
comptime return canSerializeTypeInner(T, &.{}, false);
|
comptime switch (canSerializeType(T)) {
|
||||||
|
.success => {},
|
||||||
|
.failure => |FailedType| {
|
||||||
|
@compileError(std.fmt.comptimePrint("cannot serialize type {}", .{FailedType}));
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CanSerializeTypeResult = union(enum) {
|
||||||
|
success,
|
||||||
|
failure: type,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn canSerializeType(T: type) CanSerializeTypeResult {
|
||||||
|
comptime return canSerializeTypeInner(T, &.{}).result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CanSerializeTypeInnerResult = struct {
|
||||||
|
// Keep track of optionals to reject nested optionals, which cannot be serialized.
|
||||||
|
is_optional: bool = false,
|
||||||
|
result: CanSerializeTypeResult,
|
||||||
|
};
|
||||||
|
|
||||||
fn canSerializeTypeInner(
|
fn canSerializeTypeInner(
|
||||||
T: type,
|
T: type,
|
||||||
/// Visited structs and unions, to avoid infinite recursion.
|
/// Visited structs and unions, to avoid infinite recursion.
|
||||||
/// Tracking more types is unnecessary, and a little complex due to optional nesting.
|
/// Tracking more types is unnecessary, and a little complex due to optional nesting.
|
||||||
visited: []const type,
|
visited: []const type,
|
||||||
parent_is_optional: bool,
|
) CanSerializeTypeInnerResult {
|
||||||
) bool {
|
|
||||||
return switch (@typeInfo(T)) {
|
return switch (@typeInfo(T)) {
|
||||||
.bool,
|
.bool,
|
||||||
.int,
|
.int,
|
||||||
|
|
@ -831,7 +850,7 @@ fn canSerializeTypeInner(
|
||||||
.comptime_int,
|
.comptime_int,
|
||||||
.null,
|
.null,
|
||||||
.enum_literal,
|
.enum_literal,
|
||||||
=> true,
|
=> .{ .result = .success },
|
||||||
|
|
||||||
.noreturn,
|
.noreturn,
|
||||||
.void,
|
.void,
|
||||||
|
|
@ -843,63 +862,92 @@ fn canSerializeTypeInner(
|
||||||
.frame,
|
.frame,
|
||||||
.@"anyframe",
|
.@"anyframe",
|
||||||
.@"opaque",
|
.@"opaque",
|
||||||
=> false,
|
=> .{ .result = .{ .failure = T } },
|
||||||
|
|
||||||
.@"enum" => |@"enum"| @"enum".is_exhaustive,
|
.@"enum" => |@"enum"| .{ .result = if (@"enum".is_exhaustive) .success else .{ .failure = T } },
|
||||||
|
|
||||||
.pointer => |pointer| switch (pointer.size) {
|
.pointer => |pointer| switch (pointer.size) {
|
||||||
.one => canSerializeTypeInner(pointer.child, visited, parent_is_optional),
|
.one => canSerializeTypeInner(pointer.child, visited),
|
||||||
.slice => canSerializeTypeInner(pointer.child, visited, false),
|
.slice => .{ .result = canSerializeTypeInner(pointer.child, visited).result },
|
||||||
.many, .c => false,
|
.many, .c => .{ .result = .{ .failure = T } },
|
||||||
},
|
},
|
||||||
|
|
||||||
.optional => |optional| if (parent_is_optional)
|
.optional => |optional| {
|
||||||
false
|
const inner = canSerializeTypeInner(optional.child, visited);
|
||||||
else
|
return switch (inner.result) {
|
||||||
canSerializeTypeInner(optional.child, visited, true),
|
.success => .{
|
||||||
|
.is_optional = true,
|
||||||
|
.result = if (inner.is_optional) .{ .failure = T } else .success,
|
||||||
|
},
|
||||||
|
.failure => inner,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
.array => |array| canSerializeTypeInner(array.child, visited, false),
|
.array => |array| .{ .result = canSerializeTypeInner(array.child, visited).result },
|
||||||
.vector => |vector| canSerializeTypeInner(vector.child, visited, false),
|
.vector => |vector| .{ .result = canSerializeTypeInner(vector.child, visited).result },
|
||||||
|
|
||||||
.@"struct" => |@"struct"| {
|
.@"struct" => |@"struct"| {
|
||||||
for (visited) |V| if (T == V) return true;
|
for (visited) |V| if (T == V) return .{ .result = .success };
|
||||||
const new_visited = visited ++ .{T};
|
const new_visited = visited ++ .{T};
|
||||||
for (@"struct".fields) |field| {
|
for (@"struct".fields) |field| {
|
||||||
if (!canSerializeTypeInner(field.type, new_visited, false)) return false;
|
const res = canSerializeTypeInner(field.type, new_visited);
|
||||||
|
if (res.result != .success)
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
return true;
|
return .{ .result = .success };
|
||||||
},
|
},
|
||||||
.@"union" => |@"union"| {
|
.@"union" => |@"union"| {
|
||||||
for (visited) |V| if (T == V) return true;
|
for (visited) |V| if (T == V) return .{ .result = .success };
|
||||||
const new_visited = visited ++ .{T};
|
const new_visited = visited ++ .{T};
|
||||||
if (@"union".tag_type == null) return false;
|
if (@"union".tag_type == null) return .{ .result = .{ .failure = T } };
|
||||||
for (@"union".fields) |field| {
|
for (@"union".fields) |field| {
|
||||||
if (field.type != void and !canSerializeTypeInner(field.type, new_visited, false)) {
|
if (field.type == void)
|
||||||
return false;
|
continue;
|
||||||
}
|
const res = canSerializeTypeInner(field.type, new_visited);
|
||||||
|
if (res.result != .success)
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
return true;
|
return .{ .result = .success };
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn canSerializeTypeResultEqual(a: CanSerializeTypeResult, b: CanSerializeTypeResult) bool {
|
||||||
|
const TagType = @typeInfo(CanSerializeTypeResult).@"union".tag_type.?;
|
||||||
|
if (@as(TagType, a) != @as(TagType, b))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return switch (a) {
|
||||||
|
.success => true,
|
||||||
|
.failure => |a_failure| a_failure == b.failure,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expectCanSerializeTypeResult(comptime T: type, result: CanSerializeTypeResult) !void {
|
||||||
|
try std.testing.expect(canSerializeTypeResultEqual(canSerializeType(T), result));
|
||||||
|
}
|
||||||
|
|
||||||
test canSerializeType {
|
test canSerializeType {
|
||||||
try std.testing.expect(!comptime canSerializeType(void));
|
try expectCanSerializeTypeResult(void, .{ .failure = void });
|
||||||
try std.testing.expect(!comptime canSerializeType(struct { f: [*]u8 }));
|
try expectCanSerializeTypeResult(?void, .{ .failure = void });
|
||||||
try std.testing.expect(!comptime canSerializeType(struct { error{foo} }));
|
try expectCanSerializeTypeResult(struct { f: [*]u8 }, .{ .failure = [*]u8 });
|
||||||
try std.testing.expect(!comptime canSerializeType(union(enum) { a: void, f: [*c]u8 }));
|
try expectCanSerializeTypeResult(error{foo}, .{ .failure = error{foo} });
|
||||||
try std.testing.expect(!comptime canSerializeType(@Vector(0, [*c]u8)));
|
try expectCanSerializeTypeResult(union(enum) { a: void, f: [*c]u8 }, .{ .failure = [*c]u8 });
|
||||||
try std.testing.expect(!comptime canSerializeType(*?[*c]u8));
|
try expectCanSerializeTypeResult(@Vector(0, [*c]u8), .{ .failure = [*c]u8 });
|
||||||
try std.testing.expect(!comptime canSerializeType(enum(u8) { _ }));
|
try expectCanSerializeTypeResult(?*u8, .success);
|
||||||
try std.testing.expect(!comptime canSerializeType(union { foo: void }));
|
try expectCanSerializeTypeResult(*?[*c]u8, .{ .failure = [*c]u8 });
|
||||||
try std.testing.expect(comptime canSerializeType(union(enum) { foo: void }));
|
const NonExhaustiveEnum = enum(u8) { _ };
|
||||||
try std.testing.expect(comptime canSerializeType(comptime_float));
|
try expectCanSerializeTypeResult(NonExhaustiveEnum, .{ .failure = NonExhaustiveEnum });
|
||||||
try std.testing.expect(comptime canSerializeType(comptime_int));
|
const NoTagUnion = union { foo: void };
|
||||||
try std.testing.expect(!comptime canSerializeType(struct { comptime foo: ??u8 = null }));
|
try expectCanSerializeTypeResult(NoTagUnion, .{ .failure = NoTagUnion });
|
||||||
try std.testing.expect(comptime canSerializeType(@TypeOf(.foo)));
|
try expectCanSerializeTypeResult(union(enum) { foo: void }, .success);
|
||||||
try std.testing.expect(comptime canSerializeType(?u8));
|
try expectCanSerializeTypeResult(comptime_float, .success);
|
||||||
try std.testing.expect(comptime canSerializeType(*?*u8));
|
try expectCanSerializeTypeResult(comptime_int, .success);
|
||||||
try std.testing.expect(comptime canSerializeType(?struct {
|
try expectCanSerializeTypeResult(struct { comptime foo: ??u8 = null }, .{ .failure = ??u8 });
|
||||||
|
try expectCanSerializeTypeResult(@TypeOf(.foo), .success);
|
||||||
|
try expectCanSerializeTypeResult(?u8, .success);
|
||||||
|
try expectCanSerializeTypeResult(*?*u8, .success);
|
||||||
|
try expectCanSerializeTypeResult(?struct {
|
||||||
foo: ?struct {
|
foo: ?struct {
|
||||||
?union(enum) {
|
?union(enum) {
|
||||||
a: ?@Vector(0, ?*u8),
|
a: ?@Vector(0, ?*u8),
|
||||||
|
|
@ -908,21 +956,21 @@ test canSerializeType {
|
||||||
f: ?[]?u8,
|
f: ?[]?u8,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}));
|
}, .success);
|
||||||
try std.testing.expect(!comptime canSerializeType(??u8));
|
try expectCanSerializeTypeResult(??u8, .{ .failure = ??u8 });
|
||||||
try std.testing.expect(!comptime canSerializeType(?*?u8));
|
try expectCanSerializeTypeResult(?*?u8, .{ .failure = ?*?u8 });
|
||||||
try std.testing.expect(!comptime canSerializeType(*?*?*u8));
|
try expectCanSerializeTypeResult(*?*?u8, .{ .failure = ?*?u8 });
|
||||||
try std.testing.expect(comptime canSerializeType(struct { x: comptime_int = 2 }));
|
try expectCanSerializeTypeResult(struct { x: comptime_int = 2 }, .success);
|
||||||
try std.testing.expect(comptime canSerializeType(struct { x: comptime_float = 2 }));
|
try expectCanSerializeTypeResult(struct { x: comptime_float = 2 }, .success);
|
||||||
try std.testing.expect(comptime canSerializeType(struct { comptime_int }));
|
try expectCanSerializeTypeResult(struct { comptime_int }, .success);
|
||||||
try std.testing.expect(comptime canSerializeType(struct { comptime x: @TypeOf(.foo) = .foo }));
|
try expectCanSerializeTypeResult(struct { comptime x: @TypeOf(.foo) = .foo }, .success);
|
||||||
const Recursive = struct { foo: ?*@This() };
|
const Recursive = struct { foo: ?*@This() };
|
||||||
try std.testing.expect(comptime canSerializeType(Recursive));
|
try expectCanSerializeTypeResult(Recursive, .success);
|
||||||
|
|
||||||
// Make sure we validate nested optional before we early out due to already having seen
|
// Make sure we validate nested optional before we early out due to already having seen
|
||||||
// a type recursion!
|
// a type recursion!
|
||||||
try std.testing.expect(!comptime canSerializeType(struct {
|
try expectCanSerializeTypeResult(struct {
|
||||||
add_to_visited: ?u8,
|
add_to_visited: ?u8,
|
||||||
retrieve_from_visited: ??u8,
|
retrieve_from_visited: ??u8,
|
||||||
}));
|
}, .{ .failure = ??u8 });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -379,7 +379,7 @@ pub fn fromZoirNodeAlloc(
|
||||||
diag: ?*Diagnostics,
|
diag: ?*Diagnostics,
|
||||||
options: Options,
|
options: Options,
|
||||||
) error{ OutOfMemory, ParseZon }!T {
|
) error{ OutOfMemory, ParseZon }!T {
|
||||||
comptime assert(canParseType(T));
|
comptime assertCanParseType(T);
|
||||||
|
|
||||||
if (diag) |s| {
|
if (diag) |s| {
|
||||||
s.assertEmpty();
|
s.assertEmpty();
|
||||||
|
|
@ -1185,24 +1185,43 @@ fn intFromFloatExact(T: type, value: anytype) ?T {
|
||||||
return @intFromFloat(value);
|
return @intFromFloat(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn canParseType(T: type) bool {
|
fn assertCanParseType(T: type) void {
|
||||||
comptime return canParseTypeInner(T, &.{}, false);
|
comptime switch (canParseType(T)) {
|
||||||
|
.success => {},
|
||||||
|
.failure => |FailedType| {
|
||||||
|
@compileError(std.fmt.comptimePrint("cannot parse type {}", .{FailedType}));
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CanParseTypeResult = union(enum) {
|
||||||
|
success,
|
||||||
|
failure: type,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn canParseType(T: type) CanParseTypeResult {
|
||||||
|
comptime return canParseTypeInner(T, &.{}).result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CanParseTypeInnerResult = struct {
|
||||||
|
// Keep track of optionals to reject nested optionals, which cannot be parsed.
|
||||||
|
is_optional: bool = false,
|
||||||
|
result: CanParseTypeResult,
|
||||||
|
};
|
||||||
|
|
||||||
fn canParseTypeInner(
|
fn canParseTypeInner(
|
||||||
T: type,
|
T: type,
|
||||||
/// Visited structs and unions, to avoid infinite recursion.
|
/// Visited structs and unions, to avoid infinite recursion.
|
||||||
/// Tracking more types is unnecessary, and a little complex due to optional nesting.
|
/// Tracking more types is unnecessary, and a little complex due to optional nesting.
|
||||||
visited: []const type,
|
visited: []const type,
|
||||||
parent_is_optional: bool,
|
) CanParseTypeInnerResult {
|
||||||
) bool {
|
|
||||||
return switch (@typeInfo(T)) {
|
return switch (@typeInfo(T)) {
|
||||||
.bool,
|
.bool,
|
||||||
.int,
|
.int,
|
||||||
.float,
|
.float,
|
||||||
.null,
|
.null,
|
||||||
.@"enum",
|
.@"enum",
|
||||||
=> true,
|
=> .{ .result = .success },
|
||||||
|
|
||||||
.noreturn,
|
.noreturn,
|
||||||
.void,
|
.void,
|
||||||
|
|
@ -1217,62 +1236,89 @@ fn canParseTypeInner(
|
||||||
.comptime_int,
|
.comptime_int,
|
||||||
.comptime_float,
|
.comptime_float,
|
||||||
.enum_literal,
|
.enum_literal,
|
||||||
=> false,
|
=> .{ .result = .{ .failure = T } },
|
||||||
|
|
||||||
.pointer => |pointer| switch (pointer.size) {
|
.pointer => |pointer| switch (pointer.size) {
|
||||||
.one => canParseTypeInner(pointer.child, visited, parent_is_optional),
|
.one => canParseTypeInner(pointer.child, visited),
|
||||||
.slice => canParseTypeInner(pointer.child, visited, false),
|
.slice => .{ .result = canParseTypeInner(pointer.child, visited).result },
|
||||||
.many, .c => false,
|
.many, .c => .{ .result = .{ .failure = T } },
|
||||||
},
|
},
|
||||||
|
|
||||||
.optional => |optional| if (parent_is_optional)
|
.optional => |optional| {
|
||||||
false
|
const inner = canParseTypeInner(optional.child, visited);
|
||||||
else
|
return switch (inner.result) {
|
||||||
canParseTypeInner(optional.child, visited, true),
|
.success => .{
|
||||||
|
.is_optional = true,
|
||||||
|
.result = if (inner.is_optional) .{ .failure = T } else .success,
|
||||||
|
},
|
||||||
|
.failure => inner,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
.array => |array| canParseTypeInner(array.child, visited, false),
|
.array => |array| .{ .result = canParseTypeInner(array.child, visited).result },
|
||||||
.vector => |vector| canParseTypeInner(vector.child, visited, false),
|
.vector => |vector| .{ .result = canParseTypeInner(vector.child, visited).result },
|
||||||
|
|
||||||
.@"struct" => |@"struct"| {
|
.@"struct" => |@"struct"| {
|
||||||
for (visited) |V| if (T == V) return true;
|
for (visited) |V| if (T == V) return .{ .result = .success };
|
||||||
const new_visited = visited ++ .{T};
|
const new_visited = visited ++ .{T};
|
||||||
for (@"struct".fields) |field| {
|
for (@"struct".fields) |field| {
|
||||||
if (!field.is_comptime and !canParseTypeInner(field.type, new_visited, false)) {
|
if (field.is_comptime)
|
||||||
return false;
|
continue;
|
||||||
}
|
const res = canParseTypeInner(field.type, new_visited);
|
||||||
|
if (res.result == .failure)
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
return true;
|
return .{ .result = .success };
|
||||||
},
|
},
|
||||||
.@"union" => |@"union"| {
|
.@"union" => |@"union"| {
|
||||||
for (visited) |V| if (T == V) return true;
|
for (visited) |V| if (T == V) return true;
|
||||||
const new_visited = visited ++ .{T};
|
const new_visited = visited ++ .{T};
|
||||||
for (@"union".fields) |field| {
|
for (@"union".fields) |field| {
|
||||||
if (field.type != void and !canParseTypeInner(field.type, new_visited, false)) {
|
if (field.type == void)
|
||||||
return false;
|
continue;
|
||||||
}
|
const res = canParseTypeInner(field.type, new_visited);
|
||||||
|
if (res.result == .failure)
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
return true;
|
return .{ .result = .success };
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn canParseTypeResultEqual(a: CanParseTypeResult, b: CanParseTypeResult) bool {
|
||||||
|
const TagType = @typeInfo(CanParseTypeResult).@"union".tag_type.?;
|
||||||
|
if (@as(TagType, a) != @as(TagType, b))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return switch (a) {
|
||||||
|
.success => true,
|
||||||
|
.failure => |a_failure| a_failure == b.failure,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expectCanParseTypeResult(comptime T: type, result: CanParseTypeResult) !void {
|
||||||
|
try std.testing.expect(canParseTypeResultEqual(canParseType(T), result));
|
||||||
|
}
|
||||||
|
|
||||||
test "std.zon parse canParseType" {
|
test "std.zon parse canParseType" {
|
||||||
try std.testing.expect(!comptime canParseType(void));
|
try expectCanParseTypeResult(void, .{ .failure = void });
|
||||||
try std.testing.expect(!comptime canParseType(struct { f: [*]u8 }));
|
try expectCanParseTypeResult(?void, .{ .failure = void });
|
||||||
try std.testing.expect(!comptime canParseType(struct { error{foo} }));
|
try expectCanParseTypeResult(struct { f: [*]u8 }, .{ .failure = [*]u8 });
|
||||||
try std.testing.expect(!comptime canParseType(union(enum) { a: void, b: [*c]u8 }));
|
try expectCanParseTypeResult(struct { error{foo} }, .{ .failure = error{foo} });
|
||||||
try std.testing.expect(!comptime canParseType(@Vector(0, [*c]u8)));
|
try expectCanParseTypeResult(union(enum) { a: void, b: [*c]u8 }, .{ .failure = [*c]u8 });
|
||||||
try std.testing.expect(!comptime canParseType(*?[*c]u8));
|
try expectCanParseTypeResult(@Vector(0, [*c]u8), .{ .failure = [*c]u8 });
|
||||||
try std.testing.expect(comptime canParseType(enum(u8) { _ }));
|
try expectCanParseTypeResult(*?[*c]u8, .{ .failure = [*c]u8 });
|
||||||
try std.testing.expect(comptime canParseType(union { foo: void }));
|
try expectCanParseTypeResult(*?[*c]u8, .{ .failure = [*c]u8 });
|
||||||
try std.testing.expect(comptime canParseType(union(enum) { foo: void }));
|
try expectCanParseTypeResult(enum(u8) { _ }, .success);
|
||||||
try std.testing.expect(!comptime canParseType(comptime_float));
|
try expectCanParseTypeResult(union { foo: void }, .success);
|
||||||
try std.testing.expect(!comptime canParseType(comptime_int));
|
try expectCanParseTypeResult(union(enum) { foo: void }, .success);
|
||||||
try std.testing.expect(comptime canParseType(struct { comptime foo: ??u8 = null }));
|
try expectCanParseTypeResult(comptime_float, .{ .failure = comptime_float });
|
||||||
try std.testing.expect(!comptime canParseType(@TypeOf(.foo)));
|
try expectCanParseTypeResult(comptime_int, .{ .failure = comptime_int });
|
||||||
try std.testing.expect(comptime canParseType(?u8));
|
try expectCanParseTypeResult(struct { comptime foo: ??u8 = null }, .success);
|
||||||
try std.testing.expect(comptime canParseType(*?*u8));
|
try expectCanParseTypeResult(@TypeOf(.foo), .{ .failure = @TypeOf(.foo) });
|
||||||
try std.testing.expect(comptime canParseType(?struct {
|
try expectCanParseTypeResult(?u8, .success);
|
||||||
|
try expectCanParseTypeResult(*?*u8, .success);
|
||||||
|
try expectCanParseTypeResult(?struct {
|
||||||
foo: ?struct {
|
foo: ?struct {
|
||||||
?union(enum) {
|
?union(enum) {
|
||||||
a: ?@Vector(0, ?*u8),
|
a: ?@Vector(0, ?*u8),
|
||||||
|
|
@ -1281,23 +1327,23 @@ test "std.zon parse canParseType" {
|
||||||
f: ?[]?u8,
|
f: ?[]?u8,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}));
|
}, .success);
|
||||||
try std.testing.expect(!comptime canParseType(??u8));
|
try expectCanParseTypeResult(??u8, .{ .failure = ??u8 });
|
||||||
try std.testing.expect(!comptime canParseType(?*?u8));
|
try expectCanParseTypeResult(?*?u8, .{ .failure = ?*?u8 });
|
||||||
try std.testing.expect(!comptime canParseType(*?*?*u8));
|
try expectCanParseTypeResult(*?*?*u8, .{ .failure = ?*?*u8 });
|
||||||
try std.testing.expect(!comptime canParseType(struct { x: comptime_int = 2 }));
|
try expectCanParseTypeResult(struct { x: comptime_int = 2 }, .{ .failure = comptime_int });
|
||||||
try std.testing.expect(!comptime canParseType(struct { x: comptime_float = 2 }));
|
try expectCanParseTypeResult(struct { x: comptime_float = 2 }, .{ .failure = comptime_float });
|
||||||
try std.testing.expect(comptime canParseType(struct { comptime x: @TypeOf(.foo) = .foo }));
|
try expectCanParseTypeResult(struct { comptime x: @TypeOf(.foo) = .foo }, .success);
|
||||||
try std.testing.expect(!comptime canParseType(struct { comptime_int }));
|
try expectCanParseTypeResult(struct { comptime_int }, .{ .failure = comptime_int });
|
||||||
const Recursive = struct { foo: ?*@This() };
|
const Recursive = struct { foo: ?*@This() };
|
||||||
try std.testing.expect(comptime canParseType(Recursive));
|
try expectCanParseTypeResult(Recursive, .success);
|
||||||
|
|
||||||
// Make sure we validate nested optional before we early out due to already having seen
|
// Make sure we validate nested optional before we early out due to already having seen
|
||||||
// a type recursion!
|
// a type recursion!
|
||||||
try std.testing.expect(!comptime canParseType(struct {
|
try expectCanParseTypeResult(struct {
|
||||||
add_to_visited: ?u8,
|
add_to_visited: ?u8,
|
||||||
retrieve_from_visited: ??u8,
|
retrieve_from_visited: ??u8,
|
||||||
}));
|
}, .{ .failure = ??u8 });
|
||||||
}
|
}
|
||||||
|
|
||||||
test "std.zon requiresAllocator" {
|
test "std.zon requiresAllocator" {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue