Commit c3da98cf5a
Changed files (5)
lib
std
lib/std/Build/Cache/Path.zig
@@ -161,17 +161,19 @@ pub fn formatEscapeString(path: Path, writer: *std.io.Writer) std.io.Writer.Erro
}
}
+/// Deprecated, use double quoted escape to print paths.
pub fn fmtEscapeChar(path: Path) std.fmt.Formatter(Path, formatEscapeChar) {
return .{ .data = path };
}
+/// Deprecated, use double quoted escape to print paths.
pub fn formatEscapeChar(path: Path, writer: *std.io.Writer) std.io.Writer.Error!void {
if (path.root_dir.path) |p| {
- try std.zig.charEscape(p, writer);
- if (path.sub_path.len > 0) try std.zig.charEscape(fs.path.sep_str, writer);
+ for (p) |byte| try std.zig.charEscape(byte, writer);
+ if (path.sub_path.len > 0) try writer.writeByte(fs.path.sep);
}
if (path.sub_path.len > 0) {
- try std.zig.charEscape(path.sub_path, writer);
+ for (path.sub_path) |byte| try std.zig.charEscape(byte, writer);
}
}
lib/std/zig/Ast.zig
@@ -574,7 +574,7 @@ pub fn renderError(tree: Ast, parse_error: Error, w: *Writer) Writer.Error!void
'/' => "comment",
else => unreachable,
},
- std.zig.fmtChar(tok_slice[parse_error.extra.offset..][0..1]),
+ std.zig.fmtChar(tok_slice[parse_error.extra.offset]),
});
},
lib/std/zon/parse.zig
@@ -64,14 +64,14 @@ pub const Error = union(enum) {
}
};
- fn formatMessage(self: []const u8, w: *std.io.Writer) std.io.Writer.Error!void {
+ fn formatMessage(self: []const u8, w: *std.Io.Writer) std.Io.Writer.Error!void {
// Just writes the string for now, but we're keeping this behind a formatter so we have
// the option to extend it in the future to print more advanced messages (like `Error`
// does) without breaking the API.
try w.writeAll(self);
}
- pub fn fmtMessage(self: Note, diag: *const Diagnostics) std.fmt.Formatter([]const u8, Note.formatMessage) {
+ pub fn fmtMessage(self: Note, diag: *const Diagnostics) std.fmt.Alt([]const u8, Note.formatMessage) {
return .{ .data = switch (self) {
.zoir => |note| note.msg.get(diag.zoir),
.type_check => |note| note.msg,
@@ -147,14 +147,14 @@ pub const Error = union(enum) {
diag: *const Diagnostics,
};
- fn formatMessage(self: FormatMessage, w: *std.io.Writer) std.io.Writer.Error!void {
+ fn formatMessage(self: FormatMessage, w: *std.Io.Writer) std.Io.Writer.Error!void {
switch (self.err) {
.zoir => |err| try w.writeAll(err.msg.get(self.diag.zoir)),
.type_check => |tc| try w.writeAll(tc.message),
}
}
- pub fn fmtMessage(self: @This(), diag: *const Diagnostics) std.fmt.Formatter(FormatMessage, formatMessage) {
+ pub fn fmtMessage(self: @This(), diag: *const Diagnostics) std.fmt.Alt(FormatMessage, formatMessage) {
return .{ .data = .{
.err = self,
.diag = diag,
@@ -226,7 +226,7 @@ pub const Diagnostics = struct {
return .{ .diag = self };
}
- pub fn format(self: *const @This(), w: *std.io.Writer) std.io.Writer.Error!void {
+ pub fn format(self: *const @This(), w: *std.Io.Writer) std.Io.Writer.Error!void {
var errors = self.iterateErrors();
while (errors.next()) |err| {
const loc = err.getLocation(self);
@@ -606,7 +606,7 @@ const Parser = struct {
}
}
- fn parseSlicePointer(self: *@This(), T: type, node: Zoir.Node.Index) !T {
+ fn parseSlicePointer(self: *@This(), T: type, node: Zoir.Node.Index) ParseExprInnerError!T {
switch (node.get(self.zoir)) {
.string_literal => return self.parseString(T, node),
.array_literal => |nodes| return self.parseSlice(T, nodes),
@@ -1048,6 +1048,7 @@ const Parser = struct {
name: []const u8,
) error{ OutOfMemory, ParseZon } {
@branchHint(.cold);
+ const gpa = self.gpa;
const token = if (field) |f| b: {
var buf: [2]Ast.Node.Index = undefined;
const struct_init = self.ast.fullStructInit(&buf, node.getAstNode(self.zoir)).?;
@@ -1065,13 +1066,12 @@ const Parser = struct {
};
} else b: {
const msg = "supported: ";
- var buf: std.ArrayListUnmanaged(u8) = try .initCapacity(self.gpa, 64);
- defer buf.deinit(self.gpa);
- const writer = buf.writer(self.gpa);
- try writer.writeAll(msg);
+ var buf: std.ArrayListUnmanaged(u8) = try .initCapacity(gpa, 64);
+ defer buf.deinit(gpa);
+ try buf.appendSlice(gpa, msg);
inline for (info.fields, 0..) |field_info, i| {
- if (i != 0) try writer.writeAll(", ");
- try writer.print("'{f}'", .{std.zig.fmtIdFlags(field_info.name, .{
+ if (i != 0) try buf.appendSlice(gpa, ", ");
+ try buf.print(gpa, "'{f}'", .{std.zig.fmtIdFlags(field_info.name, .{
.allow_primitive = true,
.allow_underscore = true,
})});
@@ -1079,7 +1079,7 @@ const Parser = struct {
break :b .{
.token = token,
.offset = 0,
- .msg = try buf.toOwnedSlice(self.gpa),
+ .msg = try buf.toOwnedSlice(gpa),
.owned = true,
};
};
lib/std/zon/stringify.zig
@@ -22,6 +22,7 @@
const std = @import("std");
const assert = std.debug.assert;
+const Writer = std.Io.Writer;
/// Options for `serialize`.
pub const SerializeOptions = struct {
@@ -40,15 +41,12 @@ pub const SerializeOptions = struct {
/// Serialize the given value as ZON.
///
/// It is asserted at comptime that `@TypeOf(val)` is not a recursive type.
-pub fn serialize(
- val: anytype,
- options: SerializeOptions,
- writer: anytype,
-) @TypeOf(writer).Error!void {
- var sz = serializer(writer, .{
- .whitespace = options.whitespace,
- });
- try sz.value(val, .{
+pub fn serialize(val: anytype, options: SerializeOptions, writer: *Writer) Writer.Error!void {
+ var s: Serializer = .{
+ .writer = writer,
+ .options = .{ .whitespace = options.whitespace },
+ };
+ try s.value(val, .{
.emit_codepoint_literals = options.emit_codepoint_literals,
.emit_strings_as_containers = options.emit_strings_as_containers,
.emit_default_optional_fields = options.emit_default_optional_fields,
@@ -62,13 +60,14 @@ pub fn serialize(
pub fn serializeMaxDepth(
val: anytype,
options: SerializeOptions,
- writer: anytype,
+ writer: *Writer,
depth: usize,
-) (@TypeOf(writer).Error || error{ExceededMaxDepth})!void {
- var sz = serializer(writer, .{
- .whitespace = options.whitespace,
- });
- try sz.valueMaxDepth(val, .{
+) Serializer.DepthError!void {
+ var s: Serializer = .{
+ .writer = writer,
+ .options = .{ .whitespace = options.whitespace },
+ };
+ try s.valueMaxDepth(val, .{
.emit_codepoint_literals = options.emit_codepoint_literals,
.emit_strings_as_containers = options.emit_strings_as_containers,
.emit_default_optional_fields = options.emit_default_optional_fields,
@@ -81,44 +80,45 @@ pub fn serializeMaxDepth(
pub fn serializeArbitraryDepth(
val: anytype,
options: SerializeOptions,
- writer: anytype,
-) @TypeOf(writer).Error!void {
- var sz = serializer(writer, .{
- .whitespace = options.whitespace,
- });
- try sz.valueArbitraryDepth(val, .{
+ writer: *Writer,
+) Serializer.Error!void {
+ var s: Serializer = .{
+ .writer = writer,
+ .options = .{ .whitespace = options.whitespace },
+ };
+ try s.valueArbitraryDepth(val, .{
.emit_codepoint_literals = options.emit_codepoint_literals,
.emit_strings_as_containers = options.emit_strings_as_containers,
.emit_default_optional_fields = options.emit_default_optional_fields,
});
}
-fn typeIsRecursive(comptime T: type) bool {
- return comptime typeIsRecursiveImpl(T, &.{});
+inline fn typeIsRecursive(comptime T: type) bool {
+ return comptime typeIsRecursiveInner(T, &.{});
}
-fn typeIsRecursiveImpl(comptime T: type, comptime prev_visited: []const type) bool {
+fn typeIsRecursiveInner(comptime T: type, comptime prev_visited: []const type) bool {
for (prev_visited) |V| {
if (V == T) return true;
}
const visited = prev_visited ++ .{T};
return switch (@typeInfo(T)) {
- .pointer => |pointer| typeIsRecursiveImpl(pointer.child, visited),
- .optional => |optional| typeIsRecursiveImpl(optional.child, visited),
- .array => |array| typeIsRecursiveImpl(array.child, visited),
- .vector => |vector| typeIsRecursiveImpl(vector.child, visited),
+ .pointer => |pointer| typeIsRecursiveInner(pointer.child, visited),
+ .optional => |optional| typeIsRecursiveInner(optional.child, visited),
+ .array => |array| typeIsRecursiveInner(array.child, visited),
+ .vector => |vector| typeIsRecursiveInner(vector.child, visited),
.@"struct" => |@"struct"| for (@"struct".fields) |field| {
- if (typeIsRecursiveImpl(field.type, visited)) break true;
+ if (typeIsRecursiveInner(field.type, visited)) break true;
} else false,
.@"union" => |@"union"| inline for (@"union".fields) |field| {
- if (typeIsRecursiveImpl(field.type, visited)) break true;
+ if (typeIsRecursiveInner(field.type, visited)) break true;
} else false,
else => false,
};
}
-fn canSerializeType(T: type) bool {
+inline fn canSerializeType(T: type) bool {
comptime return canSerializeTypeInner(T, &.{}, false);
}
@@ -343,12 +343,6 @@ test "std.zon checkValueDepth" {
try expectValueDepthEquals(3, @as([]const []const u8, &.{&.{ 1, 2, 3 }}));
}
-/// Options for `Serializer`.
-pub const SerializerOptions = struct {
- /// If false, only syntactically necessary whitespace is emitted.
- whitespace: bool = true,
-};
-
/// Determines when to emit Unicode code point literals as opposed to integer literals.
pub const EmitCodepointLiterals = enum {
/// Never emit Unicode code point literals.
@@ -440,634 +434,616 @@ pub const SerializeContainerOptions = struct {
/// For manual serialization of containers, see:
/// * `beginStruct`
/// * `beginTuple`
-///
-/// # Example
-/// ```zig
-/// var sz = serializer(writer, .{});
-/// var vec2 = try sz.beginStruct(.{});
-/// try vec2.field("x", 1.5, .{});
-/// try vec2.fieldPrefix();
-/// try sz.value(2.5);
-/// try vec2.end();
-/// ```
-pub fn Serializer(Writer: type) type {
- return struct {
- const Self = @This();
-
- options: SerializerOptions,
- indent_level: u8,
- writer: Writer,
-
- /// Initialize a serializer.
- fn init(writer: Writer, options: SerializerOptions) Self {
- return .{
- .options = options,
- .writer = writer,
- .indent_level = 0,
- };
- }
+pub const Serializer = struct {
+ options: Options = .{},
+ indent_level: u8 = 0,
+ writer: *Writer,
- /// Serialize a value, similar to `serialize`.
- pub fn value(self: *Self, val: anytype, options: ValueOptions) Writer.Error!void {
- comptime assert(!typeIsRecursive(@TypeOf(val)));
- return self.valueArbitraryDepth(val, options);
- }
+ pub const Error = Writer.Error;
+ pub const DepthError = Error || error{ExceededMaxDepth};
- /// Serialize a value, similar to `serializeMaxDepth`.
- pub fn valueMaxDepth(
- self: *Self,
- val: anytype,
- options: ValueOptions,
- depth: usize,
- ) (Writer.Error || error{ExceededMaxDepth})!void {
- try checkValueDepth(val, depth);
- return self.valueArbitraryDepth(val, options);
- }
+ pub const Options = struct {
+ /// If false, only syntactically necessary whitespace is emitted.
+ whitespace: bool = true,
+ };
- /// Serialize a value, similar to `serializeArbitraryDepth`.
- pub fn valueArbitraryDepth(
- self: *Self,
- val: anytype,
- options: ValueOptions,
- ) Writer.Error!void {
- comptime assert(canSerializeType(@TypeOf(val)));
- switch (@typeInfo(@TypeOf(val))) {
- .int, .comptime_int => if (options.emit_codepoint_literals.emitAsCodepoint(val)) |c| {
- self.codePoint(c) catch |err| switch (err) {
- error.InvalidCodepoint => unreachable, // Already validated
- else => |e| return e,
- };
- } else {
- try self.int(val);
- },
- .float, .comptime_float => try self.float(val),
- .bool, .null => try std.fmt.format(self.writer, "{}", .{val}),
- .enum_literal => try self.ident(@tagName(val)),
- .@"enum" => try self.ident(@tagName(val)),
- .pointer => |pointer| {
- // Try to serialize as a string
- const item: ?type = switch (@typeInfo(pointer.child)) {
- .array => |array| array.child,
- else => if (pointer.size == .slice) pointer.child else null,
- };
- if (item == u8 and
- (pointer.sentinel() == null or pointer.sentinel() == 0) and
- !options.emit_strings_as_containers)
- {
- return try self.string(val);
- }
+ /// Serialize a value, similar to `serialize`.
+ pub fn value(self: *Serializer, val: anytype, options: ValueOptions) Error!void {
+ comptime assert(!typeIsRecursive(@TypeOf(val)));
+ return self.valueArbitraryDepth(val, options);
+ }
- // Serialize as either a tuple or as the child type
- switch (pointer.size) {
- .slice => try self.tupleImpl(val, options),
- .one => try self.valueArbitraryDepth(val.*, options),
- else => comptime unreachable,
- }
- },
- .array => {
- var container = try self.beginTuple(
- .{ .whitespace_style = .{ .fields = val.len } },
- );
- for (val) |item_val| {
- try container.fieldArbitraryDepth(item_val, options);
- }
- try container.end();
- },
- .@"struct" => |@"struct"| if (@"struct".is_tuple) {
- var container = try self.beginTuple(
- .{ .whitespace_style = .{ .fields = @"struct".fields.len } },
- );
- inline for (val) |field_value| {
- try container.fieldArbitraryDepth(field_value, options);
- }
- try container.end();
- } else {
- // Decide which fields to emit
- const fields, const skipped: [@"struct".fields.len]bool = if (options.emit_default_optional_fields) b: {
- break :b .{ @"struct".fields.len, @splat(false) };
- } else b: {
- var fields = @"struct".fields.len;
- var skipped: [@"struct".fields.len]bool = @splat(false);
- inline for (@"struct".fields, &skipped) |field_info, *skip| {
- if (field_info.default_value_ptr) |ptr| {
- const default: *const field_info.type = @ptrCast(@alignCast(ptr));
- const field_value = @field(val, field_info.name);
- if (std.meta.eql(field_value, default.*)) {
- skip.* = true;
- fields -= 1;
- }
+ /// Serialize a value, similar to `serializeMaxDepth`.
+ /// Can return `error.ExceededMaxDepth`.
+ pub fn valueMaxDepth(self: *Serializer, val: anytype, options: ValueOptions, depth: usize) DepthError!void {
+ try checkValueDepth(val, depth);
+ return self.valueArbitraryDepth(val, options);
+ }
+
+ /// Serialize a value, similar to `serializeArbitraryDepth`.
+ pub fn valueArbitraryDepth(self: *Serializer, val: anytype, options: ValueOptions) Error!void {
+ comptime assert(canSerializeType(@TypeOf(val)));
+ switch (@typeInfo(@TypeOf(val))) {
+ .int, .comptime_int => if (options.emit_codepoint_literals.emitAsCodepoint(val)) |c| {
+ self.codePoint(c) catch |err| switch (err) {
+ error.InvalidCodepoint => unreachable, // Already validated
+ else => |e| return e,
+ };
+ } else {
+ try self.int(val);
+ },
+ .float, .comptime_float => try self.float(val),
+ .bool, .null => try self.writer.print("{}", .{val}),
+ .enum_literal => try self.ident(@tagName(val)),
+ .@"enum" => try self.ident(@tagName(val)),
+ .pointer => |pointer| {
+ // Try to serialize as a string
+ const item: ?type = switch (@typeInfo(pointer.child)) {
+ .array => |array| array.child,
+ else => if (pointer.size == .slice) pointer.child else null,
+ };
+ if (item == u8 and
+ (pointer.sentinel() == null or pointer.sentinel() == 0) and
+ !options.emit_strings_as_containers)
+ {
+ return try self.string(val);
+ }
+
+ // Serialize as either a tuple or as the child type
+ switch (pointer.size) {
+ .slice => try self.tupleImpl(val, options),
+ .one => try self.valueArbitraryDepth(val.*, options),
+ else => comptime unreachable,
+ }
+ },
+ .array => {
+ var container = try self.beginTuple(
+ .{ .whitespace_style = .{ .fields = val.len } },
+ );
+ for (val) |item_val| {
+ try container.fieldArbitraryDepth(item_val, options);
+ }
+ try container.end();
+ },
+ .@"struct" => |@"struct"| if (@"struct".is_tuple) {
+ var container = try self.beginTuple(
+ .{ .whitespace_style = .{ .fields = @"struct".fields.len } },
+ );
+ inline for (val) |field_value| {
+ try container.fieldArbitraryDepth(field_value, options);
+ }
+ try container.end();
+ } else {
+ // Decide which fields to emit
+ const fields, const skipped: [@"struct".fields.len]bool = if (options.emit_default_optional_fields) b: {
+ break :b .{ @"struct".fields.len, @splat(false) };
+ } else b: {
+ var fields = @"struct".fields.len;
+ var skipped: [@"struct".fields.len]bool = @splat(false);
+ inline for (@"struct".fields, &skipped) |field_info, *skip| {
+ if (field_info.default_value_ptr) |ptr| {
+ const default: *const field_info.type = @ptrCast(@alignCast(ptr));
+ const field_value = @field(val, field_info.name);
+ if (std.meta.eql(field_value, default.*)) {
+ skip.* = true;
+ fields -= 1;
}
}
- break :b .{ fields, skipped };
- };
-
- // Emit those fields
- var container = try self.beginStruct(
- .{ .whitespace_style = .{ .fields = fields } },
- );
- inline for (@"struct".fields, skipped) |field_info, skip| {
- if (!skip) {
- try container.fieldArbitraryDepth(
- field_info.name,
- @field(val, field_info.name),
- options,
- );
- }
- }
- try container.end();
- },
- .@"union" => |@"union"| {
- comptime assert(@"union".tag_type != null);
- switch (val) {
- inline else => |pl, tag| if (@TypeOf(pl) == void)
- try self.writer.print(".{s}", .{@tagName(tag)})
- else {
- var container = try self.beginStruct(.{ .whitespace_style = .{ .fields = 1 } });
-
- try container.fieldArbitraryDepth(
- @tagName(tag),
- pl,
- options,
- );
-
- try container.end();
- },
}
- },
- .optional => if (val) |inner| {
- try self.valueArbitraryDepth(inner, options);
- } else {
- try self.writer.writeAll("null");
- },
- .vector => |vector| {
- var container = try self.beginTuple(
- .{ .whitespace_style = .{ .fields = vector.len } },
- );
- for (0..vector.len) |i| {
- try container.fieldArbitraryDepth(val[i], options);
+ break :b .{ fields, skipped };
+ };
+
+ // Emit those fields
+ var container = try self.beginStruct(
+ .{ .whitespace_style = .{ .fields = fields } },
+ );
+ inline for (@"struct".fields, skipped) |field_info, skip| {
+ if (!skip) {
+ try container.fieldArbitraryDepth(
+ field_info.name,
+ @field(val, field_info.name),
+ options,
+ );
}
- try container.end();
- },
+ }
+ try container.end();
+ },
+ .@"union" => |@"union"| {
+ comptime assert(@"union".tag_type != null);
+ switch (val) {
+ inline else => |pl, tag| if (@TypeOf(pl) == void)
+ try self.writer.print(".{s}", .{@tagName(tag)})
+ else {
+ var container = try self.beginStruct(.{ .whitespace_style = .{ .fields = 1 } });
+
+ try container.fieldArbitraryDepth(
+ @tagName(tag),
+ pl,
+ options,
+ );
+
+ try container.end();
+ },
+ }
+ },
+ .optional => if (val) |inner| {
+ try self.valueArbitraryDepth(inner, options);
+ } else {
+ try self.writer.writeAll("null");
+ },
+ .vector => |vector| {
+ var container = try self.beginTuple(
+ .{ .whitespace_style = .{ .fields = vector.len } },
+ );
+ for (0..vector.len) |i| {
+ try container.fieldArbitraryDepth(val[i], options);
+ }
+ try container.end();
+ },
- else => comptime unreachable,
- }
+ else => comptime unreachable,
}
+ }
- /// Serialize an integer.
- pub fn int(self: *Self, val: anytype) Writer.Error!void {
- //try self.writer.printInt(val, 10, .lower, .{});
- try std.fmt.format(self.writer, "{d}", .{val});
- }
-
- /// Serialize a float.
- pub fn float(self: *Self, val: anytype) Writer.Error!void {
- switch (@typeInfo(@TypeOf(val))) {
- .float => if (std.math.isNan(val)) {
- return self.writer.writeAll("nan");
- } else if (std.math.isPositiveInf(val)) {
- return self.writer.writeAll("inf");
- } else if (std.math.isNegativeInf(val)) {
- return self.writer.writeAll("-inf");
- } else if (std.math.isNegativeZero(val)) {
- return self.writer.writeAll("-0.0");
- } else {
- try std.fmt.format(self.writer, "{d}", .{val});
- },
- .comptime_float => if (val == 0) {
- return self.writer.writeAll("0");
- } else {
- try std.fmt.format(self.writer, "{d}", .{val});
- },
- else => comptime unreachable,
- }
- }
+ /// Serialize an integer.
+ pub fn int(self: *Serializer, val: anytype) Error!void {
+ try self.writer.printInt(val, 10, .lower, .{});
+ }
- /// Serialize `name` as an identifier prefixed with `.`.
- ///
- /// Escapes the identifier if necessary.
- pub fn ident(self: *Self, name: []const u8) Writer.Error!void {
- try self.writer.print(".{f}", .{std.zig.fmtIdPU(name)});
+ /// Serialize a float.
+ pub fn float(self: *Serializer, val: anytype) Error!void {
+ switch (@typeInfo(@TypeOf(val))) {
+ .float => if (std.math.isNan(val)) {
+ return self.writer.writeAll("nan");
+ } else if (std.math.isPositiveInf(val)) {
+ return self.writer.writeAll("inf");
+ } else if (std.math.isNegativeInf(val)) {
+ return self.writer.writeAll("-inf");
+ } else if (std.math.isNegativeZero(val)) {
+ return self.writer.writeAll("-0.0");
+ } else {
+ try self.writer.print("{d}", .{val});
+ },
+ .comptime_float => if (val == 0) {
+ return self.writer.writeAll("0");
+ } else {
+ try self.writer.print("{d}", .{val});
+ },
+ else => comptime unreachable,
}
+ }
- /// Serialize `val` as a Unicode codepoint.
- ///
- /// Returns `error.InvalidCodepoint` if `val` is not a valid Unicode codepoint.
- pub fn codePoint(
- self: *Self,
- val: u21,
- ) (Writer.Error || error{InvalidCodepoint})!void {
- var buf: [8]u8 = undefined;
- const len = std.unicode.utf8Encode(val, &buf) catch return error.InvalidCodepoint;
- const str = buf[0..len];
- try std.fmt.format(self.writer, "'{f}'", .{std.zig.fmtChar(str)});
- }
-
- /// Like `value`, but always serializes `val` as a tuple.
- ///
- /// Will fail at comptime if `val` is not a tuple, array, pointer to an array, or slice.
- pub fn tuple(self: *Self, val: anytype, options: ValueOptions) Writer.Error!void {
- comptime assert(!typeIsRecursive(@TypeOf(val)));
- try self.tupleArbitraryDepth(val, options);
- }
+ /// Serialize `name` as an identifier prefixed with `.`.
+ ///
+ /// Escapes the identifier if necessary.
+ pub fn ident(self: *Serializer, name: []const u8) Error!void {
+ try self.writer.print(".{f}", .{std.zig.fmtIdPU(name)});
+ }
- /// Like `tuple`, but recursive types are allowed.
- ///
- /// Returns `error.ExceededMaxDepth` if `depth` is exceeded.
- pub fn tupleMaxDepth(
- self: *Self,
- val: anytype,
- options: ValueOptions,
- depth: usize,
- ) (Writer.Error || error{ExceededMaxDepth})!void {
- try checkValueDepth(val, depth);
- try self.tupleArbitraryDepth(val, options);
- }
+ pub const CodePointError = Error || error{InvalidCodepoint};
- /// Like `tuple`, but recursive types are allowed.
- ///
- /// It is the caller's responsibility to ensure that `val` does not contain cycles.
- pub fn tupleArbitraryDepth(
- self: *Self,
- val: anytype,
- options: ValueOptions,
- ) Writer.Error!void {
- try self.tupleImpl(val, options);
- }
+ /// Serialize `val` as a Unicode codepoint.
+ ///
+ /// Returns `error.InvalidCodepoint` if `val` is not a valid Unicode codepoint.
+ pub fn codePoint(self: *Serializer, val: u21) CodePointError!void {
+ try self.writer.print("'{f}'", .{std.zig.fmtChar(val)});
+ }
- fn tupleImpl(self: *Self, val: anytype, options: ValueOptions) Writer.Error!void {
- comptime assert(canSerializeType(@TypeOf(val)));
- switch (@typeInfo(@TypeOf(val))) {
- .@"struct" => {
- var container = try self.beginTuple(.{ .whitespace_style = .{ .fields = val.len } });
- inline for (val) |item_val| {
- try container.fieldArbitraryDepth(item_val, options);
- }
- try container.end();
- },
- .pointer, .array => {
- var container = try self.beginTuple(.{ .whitespace_style = .{ .fields = val.len } });
- for (val) |item_val| {
- try container.fieldArbitraryDepth(item_val, options);
- }
- try container.end();
- },
- else => comptime unreachable,
- }
- }
+ /// Like `value`, but always serializes `val` as a tuple.
+ ///
+ /// Will fail at comptime if `val` is not a tuple, array, pointer to an array, or slice.
+ pub fn tuple(self: *Serializer, val: anytype, options: ValueOptions) Error!void {
+ comptime assert(!typeIsRecursive(@TypeOf(val)));
+ try self.tupleArbitraryDepth(val, options);
+ }
- /// Like `value`, but always serializes `val` as a string.
- pub fn string(self: *Self, val: []const u8) Writer.Error!void {
- try std.fmt.format(self.writer, "\"{f}\"", .{std.zig.fmtString(val)});
- }
+ /// Like `tuple`, but recursive types are allowed.
+ ///
+ /// Returns `error.ExceededMaxDepth` if `depth` is exceeded.
+ pub fn tupleMaxDepth(
+ self: *Serializer,
+ val: anytype,
+ options: ValueOptions,
+ depth: usize,
+ ) DepthError!void {
+ try checkValueDepth(val, depth);
+ try self.tupleArbitraryDepth(val, options);
+ }
- /// Options for formatting multiline strings.
- pub const MultilineStringOptions = struct {
- /// If top level is true, whitespace before and after the multiline string is elided.
- /// If it is true, a newline is printed, then the value, followed by a newline, and if
- /// whitespace is true any necessary indentation follows.
- top_level: bool = false,
- };
+ /// Like `tuple`, but recursive types are allowed.
+ ///
+ /// It is the caller's responsibility to ensure that `val` does not contain cycles.
+ pub fn tupleArbitraryDepth(
+ self: *Serializer,
+ val: anytype,
+ options: ValueOptions,
+ ) Error!void {
+ try self.tupleImpl(val, options);
+ }
- /// Like `value`, but always serializes to a multiline string literal.
- ///
- /// Returns `error.InnerCarriageReturn` if `val` contains a CR not followed by a newline,
- /// since multiline strings cannot represent CR without a following newline.
- pub fn multilineString(
- self: *Self,
- val: []const u8,
- options: MultilineStringOptions,
- ) (Writer.Error || error{InnerCarriageReturn})!void {
- // Make sure the string does not contain any carriage returns not followed by a newline
- var i: usize = 0;
- while (i < val.len) : (i += 1) {
- if (val[i] == '\r') {
- if (i + 1 < val.len) {
- if (val[i + 1] == '\n') {
- i += 1;
- continue;
- }
- }
- return error.InnerCarriageReturn;
+ fn tupleImpl(self: *Serializer, val: anytype, options: ValueOptions) Error!void {
+ comptime assert(canSerializeType(@TypeOf(val)));
+ switch (@typeInfo(@TypeOf(val))) {
+ .@"struct" => {
+ var container = try self.beginTuple(.{ .whitespace_style = .{ .fields = val.len } });
+ inline for (val) |item_val| {
+ try container.fieldArbitraryDepth(item_val, options);
}
- }
+ try container.end();
+ },
+ .pointer, .array => {
+ var container = try self.beginTuple(.{ .whitespace_style = .{ .fields = val.len } });
+ for (val) |item_val| {
+ try container.fieldArbitraryDepth(item_val, options);
+ }
+ try container.end();
+ },
+ else => comptime unreachable,
+ }
+ }
- if (!options.top_level) {
- try self.newline();
- try self.indent();
- }
+ /// Like `value`, but always serializes `val` as a string.
+ pub fn string(self: *Serializer, val: []const u8) Error!void {
+ try self.writer.print("\"{f}\"", .{std.zig.fmtString(val)});
+ }
+
+ /// Options for formatting multiline strings.
+ pub const MultilineStringOptions = struct {
+ /// If top level is true, whitespace before and after the multiline string is elided.
+ /// If it is true, a newline is printed, then the value, followed by a newline, and if
+ /// whitespace is true any necessary indentation follows.
+ top_level: bool = false,
+ };
- try self.writer.writeAll("\\\\");
- for (val) |c| {
- if (c != '\r') {
- try self.writer.writeByte(c); // We write newlines here even if whitespace off
- if (c == '\n') {
- try self.indent();
- try self.writer.writeAll("\\\\");
+ pub const MultilineStringError = Error || error{InnerCarriageReturn};
+
+ /// Like `value`, but always serializes to a multiline string literal.
+ ///
+ /// Returns `error.InnerCarriageReturn` if `val` contains a CR not followed by a newline,
+ /// since multiline strings cannot represent CR without a following newline.
+ pub fn multilineString(
+ self: *Serializer,
+ val: []const u8,
+ options: MultilineStringOptions,
+ ) MultilineStringError!void {
+ // Make sure the string does not contain any carriage returns not followed by a newline
+ var i: usize = 0;
+ while (i < val.len) : (i += 1) {
+ if (val[i] == '\r') {
+ if (i + 1 < val.len) {
+ if (val[i + 1] == '\n') {
+ i += 1;
+ continue;
}
}
+ return error.InnerCarriageReturn;
}
+ }
- if (!options.top_level) {
- try self.writer.writeByte('\n'); // Even if whitespace off
- try self.indent();
- }
+ if (!options.top_level) {
+ try self.newline();
+ try self.indent();
}
- /// Create a `Struct` for writing ZON structs field by field.
- pub fn beginStruct(
- self: *Self,
- options: SerializeContainerOptions,
- ) Writer.Error!Struct {
- return Struct.begin(self, options);
+ try self.writer.writeAll("\\\\");
+ for (val) |c| {
+ if (c != '\r') {
+ try self.writer.writeByte(c); // We write newlines here even if whitespace off
+ if (c == '\n') {
+ try self.indent();
+ try self.writer.writeAll("\\\\");
+ }
+ }
}
- /// Creates a `Tuple` for writing ZON tuples field by field.
- pub fn beginTuple(
- self: *Self,
- options: SerializeContainerOptions,
- ) Writer.Error!Tuple {
- return Tuple.begin(self, options);
+ if (!options.top_level) {
+ try self.writer.writeByte('\n'); // Even if whitespace off
+ try self.indent();
}
+ }
- fn indent(self: *Self) Writer.Error!void {
- if (self.options.whitespace) {
- try self.writer.writeByteNTimes(' ', 4 * self.indent_level);
- }
+ /// Create a `Struct` for writing ZON structs field by field.
+ pub fn beginStruct(
+ self: *Serializer,
+ options: SerializeContainerOptions,
+ ) Error!Struct {
+ return Struct.begin(self, options);
+ }
+
+ /// Creates a `Tuple` for writing ZON tuples field by field.
+ pub fn beginTuple(
+ self: *Serializer,
+ options: SerializeContainerOptions,
+ ) Error!Tuple {
+ return Tuple.begin(self, options);
+ }
+
+ fn indent(self: *Serializer) Error!void {
+ if (self.options.whitespace) {
+ try self.writer.splatByteAll(' ', 4 * self.indent_level);
}
+ }
- fn newline(self: *Self) Writer.Error!void {
- if (self.options.whitespace) {
- try self.writer.writeByte('\n');
- }
+ fn newline(self: *Serializer) Error!void {
+ if (self.options.whitespace) {
+ try self.writer.writeByte('\n');
}
+ }
- fn newlineOrSpace(self: *Self, len: usize) Writer.Error!void {
- if (self.containerShouldWrap(len)) {
- try self.newline();
- } else {
- try self.space();
- }
+ fn newlineOrSpace(self: *Serializer, len: usize) Error!void {
+ if (self.containerShouldWrap(len)) {
+ try self.newline();
+ } else {
+ try self.space();
}
+ }
- fn space(self: *Self) Writer.Error!void {
- if (self.options.whitespace) {
- try self.writer.writeByte(' ');
- }
+ fn space(self: *Serializer) Error!void {
+ if (self.options.whitespace) {
+ try self.writer.writeByte(' ');
}
+ }
- /// Writes ZON tuples field by field.
- pub const Tuple = struct {
- container: Container,
+ /// Writes ZON tuples field by field.
+ pub const Tuple = struct {
+ container: Container,
- fn begin(parent: *Self, options: SerializeContainerOptions) Writer.Error!Tuple {
- return .{
- .container = try Container.begin(parent, .anon, options),
- };
- }
+ fn begin(parent: *Serializer, options: SerializeContainerOptions) Error!Tuple {
+ return .{
+ .container = try Container.begin(parent, .anon, options),
+ };
+ }
- /// Finishes serializing the tuple.
- ///
- /// Prints a trailing comma as configured when appropriate, and the closing bracket.
- pub fn end(self: *Tuple) Writer.Error!void {
- try self.container.end();
- self.* = undefined;
- }
+ /// Finishes serializing the tuple.
+ ///
+ /// Prints a trailing comma as configured when appropriate, and the closing bracket.
+ pub fn end(self: *Tuple) Error!void {
+ try self.container.end();
+ self.* = undefined;
+ }
- /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `value`.
- pub fn field(
- self: *Tuple,
- val: anytype,
- options: ValueOptions,
- ) Writer.Error!void {
- try self.container.field(null, val, options);
- }
+ /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `value`.
+ pub fn field(
+ self: *Tuple,
+ val: anytype,
+ options: ValueOptions,
+ ) Error!void {
+ try self.container.field(null, val, options);
+ }
- /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `valueMaxDepth`.
- pub fn fieldMaxDepth(
- self: *Tuple,
- val: anytype,
- options: ValueOptions,
- depth: usize,
- ) (Writer.Error || error{ExceededMaxDepth})!void {
- try self.container.fieldMaxDepth(null, val, options, depth);
- }
+ /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `valueMaxDepth`.
+ /// Returns `error.ExceededMaxDepth` if `depth` is exceeded.
+ pub fn fieldMaxDepth(
+ self: *Tuple,
+ val: anytype,
+ options: ValueOptions,
+ depth: usize,
+ ) DepthError!void {
+ try self.container.fieldMaxDepth(null, val, options, depth);
+ }
- /// Serialize a field. Equivalent to calling `fieldPrefix` followed by
- /// `valueArbitraryDepth`.
- pub fn fieldArbitraryDepth(
- self: *Tuple,
- val: anytype,
- options: ValueOptions,
- ) Writer.Error!void {
- try self.container.fieldArbitraryDepth(null, val, options);
- }
+ /// Serialize a field. Equivalent to calling `fieldPrefix` followed by
+ /// `valueArbitraryDepth`.
+ pub fn fieldArbitraryDepth(
+ self: *Tuple,
+ val: anytype,
+ options: ValueOptions,
+ ) Error!void {
+ try self.container.fieldArbitraryDepth(null, val, options);
+ }
- /// Starts a field with a struct as a value. Returns the struct.
- pub fn beginStructField(
- self: *Tuple,
- options: SerializeContainerOptions,
- ) Writer.Error!Struct {
- try self.fieldPrefix();
- return self.container.serializer.beginStruct(options);
- }
+ /// Starts a field with a struct as a value. Returns the struct.
+ pub fn beginStructField(
+ self: *Tuple,
+ options: SerializeContainerOptions,
+ ) Error!Struct {
+ try self.fieldPrefix();
+ return self.container.serializer.beginStruct(options);
+ }
- /// Starts a field with a tuple as a value. Returns the tuple.
- pub fn beginTupleField(
- self: *Tuple,
- options: SerializeContainerOptions,
- ) Writer.Error!Tuple {
- try self.fieldPrefix();
- return self.container.serializer.beginTuple(options);
- }
+ /// Starts a field with a tuple as a value. Returns the tuple.
+ pub fn beginTupleField(
+ self: *Tuple,
+ options: SerializeContainerOptions,
+ ) Error!Tuple {
+ try self.fieldPrefix();
+ return self.container.serializer.beginTuple(options);
+ }
- /// Print a field prefix. This prints any necessary commas, and whitespace as
- /// configured. Useful if you want to serialize the field value yourself.
- pub fn fieldPrefix(self: *Tuple) Writer.Error!void {
- try self.container.fieldPrefix(null);
- }
- };
+ /// Print a field prefix. This prints any necessary commas, and whitespace as
+ /// configured. Useful if you want to serialize the field value yourself.
+ pub fn fieldPrefix(self: *Tuple) Error!void {
+ try self.container.fieldPrefix(null);
+ }
+ };
- /// Writes ZON structs field by field.
- pub const Struct = struct {
- container: Container,
+ /// Writes ZON structs field by field.
+ pub const Struct = struct {
+ container: Container,
- fn begin(parent: *Self, options: SerializeContainerOptions) Writer.Error!Struct {
- return .{
- .container = try Container.begin(parent, .named, options),
- };
- }
+ fn begin(parent: *Serializer, options: SerializeContainerOptions) Error!Struct {
+ return .{
+ .container = try Container.begin(parent, .named, options),
+ };
+ }
- /// Finishes serializing the struct.
- ///
- /// Prints a trailing comma as configured when appropriate, and the closing bracket.
- pub fn end(self: *Struct) Writer.Error!void {
- try self.container.end();
- self.* = undefined;
- }
+ /// Finishes serializing the struct.
+ ///
+ /// Prints a trailing comma as configured when appropriate, and the closing bracket.
+ pub fn end(self: *Struct) Error!void {
+ try self.container.end();
+ self.* = undefined;
+ }
- /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `value`.
- pub fn field(
- self: *Struct,
- name: []const u8,
- val: anytype,
- options: ValueOptions,
- ) Writer.Error!void {
- try self.container.field(name, val, options);
- }
+ /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `value`.
+ pub fn field(
+ self: *Struct,
+ name: []const u8,
+ val: anytype,
+ options: ValueOptions,
+ ) Error!void {
+ try self.container.field(name, val, options);
+ }
- /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `valueMaxDepth`.
- pub fn fieldMaxDepth(
- self: *Struct,
- name: []const u8,
- val: anytype,
- options: ValueOptions,
- depth: usize,
- ) (Writer.Error || error{ExceededMaxDepth})!void {
- try self.container.fieldMaxDepth(name, val, options, depth);
- }
+ /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `valueMaxDepth`.
+ /// Returns `error.ExceededMaxDepth` if `depth` is exceeded.
+ pub fn fieldMaxDepth(
+ self: *Struct,
+ name: []const u8,
+ val: anytype,
+ options: ValueOptions,
+ depth: usize,
+ ) DepthError!void {
+ try self.container.fieldMaxDepth(name, val, options, depth);
+ }
- /// Serialize a field. Equivalent to calling `fieldPrefix` followed by
- /// `valueArbitraryDepth`.
- pub fn fieldArbitraryDepth(
- self: *Struct,
- name: []const u8,
- val: anytype,
- options: ValueOptions,
- ) Writer.Error!void {
- try self.container.fieldArbitraryDepth(name, val, options);
- }
+ /// Serialize a field. Equivalent to calling `fieldPrefix` followed by
+ /// `valueArbitraryDepth`.
+ pub fn fieldArbitraryDepth(
+ self: *Struct,
+ name: []const u8,
+ val: anytype,
+ options: ValueOptions,
+ ) Error!void {
+ try self.container.fieldArbitraryDepth(name, val, options);
+ }
- /// Starts a field with a struct as a value. Returns the struct.
- pub fn beginStructField(
- self: *Struct,
- name: []const u8,
- options: SerializeContainerOptions,
- ) Writer.Error!Struct {
- try self.fieldPrefix(name);
- return self.container.serializer.beginStruct(options);
- }
+ /// Starts a field with a struct as a value. Returns the struct.
+ pub fn beginStructField(
+ self: *Struct,
+ name: []const u8,
+ options: SerializeContainerOptions,
+ ) Error!Struct {
+ try self.fieldPrefix(name);
+ return self.container.serializer.beginStruct(options);
+ }
- /// Starts a field with a tuple as a value. Returns the tuple.
- pub fn beginTupleField(
- self: *Struct,
- name: []const u8,
- options: SerializeContainerOptions,
- ) Writer.Error!Tuple {
- try self.fieldPrefix(name);
- return self.container.serializer.beginTuple(options);
- }
+ /// Starts a field with a tuple as a value. Returns the tuple.
+ pub fn beginTupleField(
+ self: *Struct,
+ name: []const u8,
+ options: SerializeContainerOptions,
+ ) Error!Tuple {
+ try self.fieldPrefix(name);
+ return self.container.serializer.beginTuple(options);
+ }
- /// Print a field prefix. This prints any necessary commas, the field name (escaped if
- /// necessary) and whitespace as configured. Useful if you want to serialize the field
- /// value yourself.
- pub fn fieldPrefix(self: *Struct, name: []const u8) Writer.Error!void {
- try self.container.fieldPrefix(name);
- }
- };
+ /// Print a field prefix. This prints any necessary commas, the field name (escaped if
+ /// necessary) and whitespace as configured. Useful if you want to serialize the field
+ /// value yourself.
+ pub fn fieldPrefix(self: *Struct, name: []const u8) Error!void {
+ try self.container.fieldPrefix(name);
+ }
+ };
- const Container = struct {
- const FieldStyle = enum { named, anon };
+ const Container = struct {
+ const FieldStyle = enum { named, anon };
- serializer: *Self,
+ serializer: *Serializer,
+ field_style: FieldStyle,
+ options: SerializeContainerOptions,
+ empty: bool,
+
+ fn begin(
+ sz: *Serializer,
field_style: FieldStyle,
options: SerializeContainerOptions,
- empty: bool,
-
- fn begin(
- sz: *Self,
- field_style: FieldStyle,
- options: SerializeContainerOptions,
- ) Writer.Error!Container {
- if (options.shouldWrap()) sz.indent_level +|= 1;
- try sz.writer.writeAll(".{");
- return .{
- .serializer = sz,
- .field_style = field_style,
- .options = options,
- .empty = true,
- };
- }
-
- fn end(self: *Container) Writer.Error!void {
- if (self.options.shouldWrap()) self.serializer.indent_level -|= 1;
- if (!self.empty) {
- if (self.options.shouldWrap()) {
- if (self.serializer.options.whitespace) {
- try self.serializer.writer.writeByte(',');
- }
- try self.serializer.newline();
- try self.serializer.indent();
- } else if (!self.shouldElideSpaces()) {
- try self.serializer.space();
- }
- }
- try self.serializer.writer.writeByte('}');
- self.* = undefined;
- }
+ ) Error!Container {
+ if (options.shouldWrap()) sz.indent_level +|= 1;
+ try sz.writer.writeAll(".{");
+ return .{
+ .serializer = sz,
+ .field_style = field_style,
+ .options = options,
+ .empty = true,
+ };
+ }
- fn fieldPrefix(self: *Container, name: ?[]const u8) Writer.Error!void {
- if (!self.empty) {
- try self.serializer.writer.writeByte(',');
- }
- self.empty = false;
+ fn end(self: *Container) Error!void {
+ if (self.options.shouldWrap()) self.serializer.indent_level -|= 1;
+ if (!self.empty) {
if (self.options.shouldWrap()) {
+ if (self.serializer.options.whitespace) {
+ try self.serializer.writer.writeByte(',');
+ }
try self.serializer.newline();
+ try self.serializer.indent();
} else if (!self.shouldElideSpaces()) {
try self.serializer.space();
}
- if (self.options.shouldWrap()) try self.serializer.indent();
- if (name) |n| {
- try self.serializer.ident(n);
- try self.serializer.space();
- try self.serializer.writer.writeByte('=');
- try self.serializer.space();
- }
}
+ try self.serializer.writer.writeByte('}');
+ self.* = undefined;
+ }
- fn field(
- self: *Container,
- name: ?[]const u8,
- val: anytype,
- options: ValueOptions,
- ) Writer.Error!void {
- comptime assert(!typeIsRecursive(@TypeOf(val)));
- try self.fieldArbitraryDepth(name, val, options);
+ fn fieldPrefix(self: *Container, name: ?[]const u8) Error!void {
+ if (!self.empty) {
+ try self.serializer.writer.writeByte(',');
}
-
- fn fieldMaxDepth(
- self: *Container,
- name: ?[]const u8,
- val: anytype,
- options: ValueOptions,
- depth: usize,
- ) (Writer.Error || error{ExceededMaxDepth})!void {
- try checkValueDepth(val, depth);
- try self.fieldArbitraryDepth(name, val, options);
+ self.empty = false;
+ if (self.options.shouldWrap()) {
+ try self.serializer.newline();
+ } else if (!self.shouldElideSpaces()) {
+ try self.serializer.space();
}
-
- fn fieldArbitraryDepth(
- self: *Container,
- name: ?[]const u8,
- val: anytype,
- options: ValueOptions,
- ) Writer.Error!void {
- try self.fieldPrefix(name);
- try self.serializer.valueArbitraryDepth(val, options);
+ if (self.options.shouldWrap()) try self.serializer.indent();
+ if (name) |n| {
+ try self.serializer.ident(n);
+ try self.serializer.space();
+ try self.serializer.writer.writeByte('=');
+ try self.serializer.space();
}
+ }
- fn shouldElideSpaces(self: *const Container) bool {
- return switch (self.options.whitespace_style) {
- .fields => |fields| self.field_style != .named and fields == 1,
- else => false,
- };
- }
- };
+ fn field(
+ self: *Container,
+ name: ?[]const u8,
+ val: anytype,
+ options: ValueOptions,
+ ) Error!void {
+ comptime assert(!typeIsRecursive(@TypeOf(val)));
+ try self.fieldArbitraryDepth(name, val, options);
+ }
+
+ /// Returns `error.ExceededMaxDepth` if `depth` is exceeded.
+ fn fieldMaxDepth(
+ self: *Container,
+ name: ?[]const u8,
+ val: anytype,
+ options: ValueOptions,
+ depth: usize,
+ ) DepthError!void {
+ try checkValueDepth(val, depth);
+ try self.fieldArbitraryDepth(name, val, options);
+ }
+
+ fn fieldArbitraryDepth(
+ self: *Container,
+ name: ?[]const u8,
+ val: anytype,
+ options: ValueOptions,
+ ) Error!void {
+ try self.fieldPrefix(name);
+ try self.serializer.valueArbitraryDepth(val, options);
+ }
+
+ fn shouldElideSpaces(self: *const Container) bool {
+ return switch (self.options.whitespace_style) {
+ .fields => |fields| self.field_style != .named and fields == 1,
+ else => false,
+ };
+ }
};
-}
+};
-/// Creates a new `Serializer` with the given writer and options.
-pub fn serializer(writer: anytype, options: SerializerOptions) Serializer(@TypeOf(writer)) {
- return .init(writer, options);
+test Serializer {
+ var discarding: Writer.Discarding = .init(&.{});
+ var s: Serializer = .{ .writer = &discarding.writer };
+ var vec2 = try s.beginStruct(.{});
+ try vec2.field("x", 1.5, .{});
+ try vec2.fieldPrefix("prefix");
+ try s.value(2.5, .{});
+ try vec2.end();
}
fn expectSerializeEqual(
@@ -1075,10 +1051,12 @@ fn expectSerializeEqual(
value: anytype,
options: SerializeOptions,
) !void {
- var buf = std.ArrayList(u8).init(std.testing.allocator);
- defer buf.deinit();
- try serialize(value, options, buf.writer());
- try std.testing.expectEqualStrings(expected, buf.items);
+ var aw: Writer.Allocating = .init(std.testing.allocator);
+ const bw = &aw.writer;
+ defer aw.deinit();
+
+ try serialize(value, options, bw);
+ try std.testing.expectEqualStrings(expected, aw.getWritten());
}
test "std.zon stringify whitespace, high level API" {
@@ -1175,59 +1153,59 @@ test "std.zon stringify whitespace, high level API" {
}
test "std.zon stringify whitespace, low level API" {
- var buf = std.ArrayList(u8).init(std.testing.allocator);
- defer buf.deinit();
- var sz = serializer(buf.writer(), .{});
+ var aw: Writer.Allocating = .init(std.testing.allocator);
+ var s: Serializer = .{ .writer = &aw.writer };
+ defer aw.deinit();
- inline for (.{ true, false }) |whitespace| {
- sz.options = .{ .whitespace = whitespace };
+ for ([2]bool{ true, false }) |whitespace| {
+ s.options = .{ .whitespace = whitespace };
// Empty containers
{
- var container = try sz.beginStruct(.{});
+ var container = try s.beginStruct(.{});
try container.end();
- try std.testing.expectEqualStrings(".{}", buf.items);
- buf.clearRetainingCapacity();
+ try std.testing.expectEqualStrings(".{}", aw.getWritten());
+ aw.clearRetainingCapacity();
}
{
- var container = try sz.beginTuple(.{});
+ var container = try s.beginTuple(.{});
try container.end();
- try std.testing.expectEqualStrings(".{}", buf.items);
- buf.clearRetainingCapacity();
+ try std.testing.expectEqualStrings(".{}", aw.getWritten());
+ aw.clearRetainingCapacity();
}
{
- var container = try sz.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
+ var container = try s.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
try container.end();
- try std.testing.expectEqualStrings(".{}", buf.items);
- buf.clearRetainingCapacity();
+ try std.testing.expectEqualStrings(".{}", aw.getWritten());
+ aw.clearRetainingCapacity();
}
{
- var container = try sz.beginTuple(.{ .whitespace_style = .{ .wrap = false } });
+ var container = try s.beginTuple(.{ .whitespace_style = .{ .wrap = false } });
try container.end();
- try std.testing.expectEqualStrings(".{}", buf.items);
- buf.clearRetainingCapacity();
+ try std.testing.expectEqualStrings(".{}", aw.getWritten());
+ aw.clearRetainingCapacity();
}
{
- var container = try sz.beginStruct(.{ .whitespace_style = .{ .fields = 0 } });
+ var container = try s.beginStruct(.{ .whitespace_style = .{ .fields = 0 } });
try container.end();
- try std.testing.expectEqualStrings(".{}", buf.items);
- buf.clearRetainingCapacity();
+ try std.testing.expectEqualStrings(".{}", aw.getWritten());
+ aw.clearRetainingCapacity();
}
{
- var container = try sz.beginTuple(.{ .whitespace_style = .{ .fields = 0 } });
+ var container = try s.beginTuple(.{ .whitespace_style = .{ .fields = 0 } });
try container.end();
- try std.testing.expectEqualStrings(".{}", buf.items);
- buf.clearRetainingCapacity();
+ try std.testing.expectEqualStrings(".{}", aw.getWritten());
+ aw.clearRetainingCapacity();
}
// Size 1
{
- var container = try sz.beginStruct(.{});
+ var container = try s.beginStruct(.{});
try container.field("a", 1, .{});
try container.end();
if (whitespace) {
@@ -1235,15 +1213,15 @@ test "std.zon stringify whitespace, low level API" {
\\.{
\\ .a = 1,
\\}
- , buf.items);
+ , aw.getWritten());
} else {
- try std.testing.expectEqualStrings(".{.a=1}", buf.items);
+ try std.testing.expectEqualStrings(".{.a=1}", aw.getWritten());
}
- buf.clearRetainingCapacity();
+ aw.clearRetainingCapacity();
}
{
- var container = try sz.beginTuple(.{});
+ var container = try s.beginTuple(.{});
try container.field(1, .{});
try container.end();
if (whitespace) {
@@ -1251,62 +1229,62 @@ test "std.zon stringify whitespace, low level API" {
\\.{
\\ 1,
\\}
- , buf.items);
+ , aw.getWritten());
} else {
- try std.testing.expectEqualStrings(".{1}", buf.items);
+ try std.testing.expectEqualStrings(".{1}", aw.getWritten());
}
- buf.clearRetainingCapacity();
+ aw.clearRetainingCapacity();
}
{
- var container = try sz.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
+ var container = try s.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
try container.field("a", 1, .{});
try container.end();
if (whitespace) {
- try std.testing.expectEqualStrings(".{ .a = 1 }", buf.items);
+ try std.testing.expectEqualStrings(".{ .a = 1 }", aw.getWritten());
} else {
- try std.testing.expectEqualStrings(".{.a=1}", buf.items);
+ try std.testing.expectEqualStrings(".{.a=1}", aw.getWritten());
}
- buf.clearRetainingCapacity();
+ aw.clearRetainingCapacity();
}
{
// We get extra spaces here, since we didn't know up front that there would only be one
// field.
- var container = try sz.beginTuple(.{ .whitespace_style = .{ .wrap = false } });
+ var container = try s.beginTuple(.{ .whitespace_style = .{ .wrap = false } });
try container.field(1, .{});
try container.end();
if (whitespace) {
- try std.testing.expectEqualStrings(".{ 1 }", buf.items);
+ try std.testing.expectEqualStrings(".{ 1 }", aw.getWritten());
} else {
- try std.testing.expectEqualStrings(".{1}", buf.items);
+ try std.testing.expectEqualStrings(".{1}", aw.getWritten());
}
- buf.clearRetainingCapacity();
+ aw.clearRetainingCapacity();
}
{
- var container = try sz.beginStruct(.{ .whitespace_style = .{ .fields = 1 } });
+ var container = try s.beginStruct(.{ .whitespace_style = .{ .fields = 1 } });
try container.field("a", 1, .{});
try container.end();
if (whitespace) {
- try std.testing.expectEqualStrings(".{ .a = 1 }", buf.items);
+ try std.testing.expectEqualStrings(".{ .a = 1 }", aw.getWritten());
} else {
- try std.testing.expectEqualStrings(".{.a=1}", buf.items);
+ try std.testing.expectEqualStrings(".{.a=1}", aw.getWritten());
}
- buf.clearRetainingCapacity();
+ aw.clearRetainingCapacity();
}
{
- var container = try sz.beginTuple(.{ .whitespace_style = .{ .fields = 1 } });
+ var container = try s.beginTuple(.{ .whitespace_style = .{ .fields = 1 } });
try container.field(1, .{});
try container.end();
- try std.testing.expectEqualStrings(".{1}", buf.items);
- buf.clearRetainingCapacity();
+ try std.testing.expectEqualStrings(".{1}", aw.getWritten());
+ aw.clearRetainingCapacity();
}
// Size 2
{
- var container = try sz.beginStruct(.{});
+ var container = try s.beginStruct(.{});
try container.field("a", 1, .{});
try container.field("b", 2, .{});
try container.end();
@@ -1316,15 +1294,15 @@ test "std.zon stringify whitespace, low level API" {
\\ .a = 1,
\\ .b = 2,
\\}
- , buf.items);
+ , aw.getWritten());
} else {
- try std.testing.expectEqualStrings(".{.a=1,.b=2}", buf.items);
+ try std.testing.expectEqualStrings(".{.a=1,.b=2}", aw.getWritten());
}
- buf.clearRetainingCapacity();
+ aw.clearRetainingCapacity();
}
{
- var container = try sz.beginTuple(.{});
+ var container = try s.beginTuple(.{});
try container.field(1, .{});
try container.field(2, .{});
try container.end();
@@ -1334,68 +1312,68 @@ test "std.zon stringify whitespace, low level API" {
\\ 1,
\\ 2,
\\}
- , buf.items);
+ , aw.getWritten());
} else {
- try std.testing.expectEqualStrings(".{1,2}", buf.items);
+ try std.testing.expectEqualStrings(".{1,2}", aw.getWritten());
}
- buf.clearRetainingCapacity();
+ aw.clearRetainingCapacity();
}
{
- var container = try sz.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
+ var container = try s.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
try container.field("a", 1, .{});
try container.field("b", 2, .{});
try container.end();
if (whitespace) {
- try std.testing.expectEqualStrings(".{ .a = 1, .b = 2 }", buf.items);
+ try std.testing.expectEqualStrings(".{ .a = 1, .b = 2 }", aw.getWritten());
} else {
- try std.testing.expectEqualStrings(".{.a=1,.b=2}", buf.items);
+ try std.testing.expectEqualStrings(".{.a=1,.b=2}", aw.getWritten());
}
- buf.clearRetainingCapacity();
+ aw.clearRetainingCapacity();
}
{
- var container = try sz.beginTuple(.{ .whitespace_style = .{ .wrap = false } });
+ var container = try s.beginTuple(.{ .whitespace_style = .{ .wrap = false } });
try container.field(1, .{});
try container.field(2, .{});
try container.end();
if (whitespace) {
- try std.testing.expectEqualStrings(".{ 1, 2 }", buf.items);
+ try std.testing.expectEqualStrings(".{ 1, 2 }", aw.getWritten());
} else {
- try std.testing.expectEqualStrings(".{1,2}", buf.items);
+ try std.testing.expectEqualStrings(".{1,2}", aw.getWritten());
}
- buf.clearRetainingCapacity();
+ aw.clearRetainingCapacity();
}
{
- var container = try sz.beginStruct(.{ .whitespace_style = .{ .fields = 2 } });
+ var container = try s.beginStruct(.{ .whitespace_style = .{ .fields = 2 } });
try container.field("a", 1, .{});
try container.field("b", 2, .{});
try container.end();
if (whitespace) {
- try std.testing.expectEqualStrings(".{ .a = 1, .b = 2 }", buf.items);
+ try std.testing.expectEqualStrings(".{ .a = 1, .b = 2 }", aw.getWritten());
} else {
- try std.testing.expectEqualStrings(".{.a=1,.b=2}", buf.items);
+ try std.testing.expectEqualStrings(".{.a=1,.b=2}", aw.getWritten());
}
- buf.clearRetainingCapacity();
+ aw.clearRetainingCapacity();
}
{
- var container = try sz.beginTuple(.{ .whitespace_style = .{ .fields = 2 } });
+ var container = try s.beginTuple(.{ .whitespace_style = .{ .fields = 2 } });
try container.field(1, .{});
try container.field(2, .{});
try container.end();
if (whitespace) {
- try std.testing.expectEqualStrings(".{ 1, 2 }", buf.items);
+ try std.testing.expectEqualStrings(".{ 1, 2 }", aw.getWritten());
} else {
- try std.testing.expectEqualStrings(".{1,2}", buf.items);
+ try std.testing.expectEqualStrings(".{1,2}", aw.getWritten());
}
- buf.clearRetainingCapacity();
+ aw.clearRetainingCapacity();
}
// Size 3
{
- var container = try sz.beginStruct(.{});
+ var container = try s.beginStruct(.{});
try container.field("a", 1, .{});
try container.field("b", 2, .{});
try container.field("c", 3, .{});
@@ -1407,15 +1385,15 @@ test "std.zon stringify whitespace, low level API" {
\\ .b = 2,
\\ .c = 3,
\\}
- , buf.items);
+ , aw.getWritten());
} else {
- try std.testing.expectEqualStrings(".{.a=1,.b=2,.c=3}", buf.items);
+ try std.testing.expectEqualStrings(".{.a=1,.b=2,.c=3}", aw.getWritten());
}
- buf.clearRetainingCapacity();
+ aw.clearRetainingCapacity();
}
{
- var container = try sz.beginTuple(.{});
+ var container = try s.beginTuple(.{});
try container.field(1, .{});
try container.field(2, .{});
try container.field(3, .{});
@@ -1427,43 +1405,43 @@ test "std.zon stringify whitespace, low level API" {
\\ 2,
\\ 3,
\\}
- , buf.items);
+ , aw.getWritten());
} else {
- try std.testing.expectEqualStrings(".{1,2,3}", buf.items);
+ try std.testing.expectEqualStrings(".{1,2,3}", aw.getWritten());
}
- buf.clearRetainingCapacity();
+ aw.clearRetainingCapacity();
}
{
- var container = try sz.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
+ var container = try s.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
try container.field("a", 1, .{});
try container.field("b", 2, .{});
try container.field("c", 3, .{});
try container.end();
if (whitespace) {
- try std.testing.expectEqualStrings(".{ .a = 1, .b = 2, .c = 3 }", buf.items);
+ try std.testing.expectEqualStrings(".{ .a = 1, .b = 2, .c = 3 }", aw.getWritten());
} else {
- try std.testing.expectEqualStrings(".{.a=1,.b=2,.c=3}", buf.items);
+ try std.testing.expectEqualStrings(".{.a=1,.b=2,.c=3}", aw.getWritten());
}
- buf.clearRetainingCapacity();
+ aw.clearRetainingCapacity();
}
{
- var container = try sz.beginTuple(.{ .whitespace_style = .{ .wrap = false } });
+ var container = try s.beginTuple(.{ .whitespace_style = .{ .wrap = false } });
try container.field(1, .{});
try container.field(2, .{});
try container.field(3, .{});
try container.end();
if (whitespace) {
- try std.testing.expectEqualStrings(".{ 1, 2, 3 }", buf.items);
+ try std.testing.expectEqualStrings(".{ 1, 2, 3 }", aw.getWritten());
} else {
- try std.testing.expectEqualStrings(".{1,2,3}", buf.items);
+ try std.testing.expectEqualStrings(".{1,2,3}", aw.getWritten());
}
- buf.clearRetainingCapacity();
+ aw.clearRetainingCapacity();
}
{
- var container = try sz.beginStruct(.{ .whitespace_style = .{ .fields = 3 } });
+ var container = try s.beginStruct(.{ .whitespace_style = .{ .fields = 3 } });
try container.field("a", 1, .{});
try container.field("b", 2, .{});
try container.field("c", 3, .{});
@@ -1475,15 +1453,15 @@ test "std.zon stringify whitespace, low level API" {
\\ .b = 2,
\\ .c = 3,
\\}
- , buf.items);
+ , aw.getWritten());
} else {
- try std.testing.expectEqualStrings(".{.a=1,.b=2,.c=3}", buf.items);
+ try std.testing.expectEqualStrings(".{.a=1,.b=2,.c=3}", aw.getWritten());
}
- buf.clearRetainingCapacity();
+ aw.clearRetainingCapacity();
}
{
- var container = try sz.beginTuple(.{ .whitespace_style = .{ .fields = 3 } });
+ var container = try s.beginTuple(.{ .whitespace_style = .{ .fields = 3 } });
try container.field(1, .{});
try container.field(2, .{});
try container.field(3, .{});
@@ -1495,16 +1473,16 @@ test "std.zon stringify whitespace, low level API" {
\\ 2,
\\ 3,
\\}
- , buf.items);
+ , aw.getWritten());
} else {
- try std.testing.expectEqualStrings(".{1,2,3}", buf.items);
+ try std.testing.expectEqualStrings(".{1,2,3}", aw.getWritten());
}
- buf.clearRetainingCapacity();
+ aw.clearRetainingCapacity();
}
// Nested objects where the outer container doesn't wrap but the inner containers do
{
- var container = try sz.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
+ var container = try s.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
try container.field("first", .{ 1, 2, 3 }, .{});
try container.field("second", .{ 4, 5, 6 }, .{});
try container.end();
@@ -1519,139 +1497,141 @@ test "std.zon stringify whitespace, low level API" {
\\ 5,
\\ 6,
\\} }
- , buf.items);
+ , aw.getWritten());
} else {
try std.testing.expectEqualStrings(
".{.first=.{1,2,3},.second=.{4,5,6}}",
- buf.items,
+ aw.getWritten(),
);
}
- buf.clearRetainingCapacity();
+ aw.clearRetainingCapacity();
}
}
}
test "std.zon stringify utf8 codepoints" {
- var buf = std.ArrayList(u8).init(std.testing.allocator);
- defer buf.deinit();
- var sz = serializer(buf.writer(), .{});
+ var aw: Writer.Allocating = .init(std.testing.allocator);
+ var s: Serializer = .{ .writer = &aw.writer };
+ defer aw.deinit();
// Printable ASCII
- try sz.int('a');
- try std.testing.expectEqualStrings("97", buf.items);
- buf.clearRetainingCapacity();
+ try s.int('a');
+ try std.testing.expectEqualStrings("97", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.codePoint('a');
- try std.testing.expectEqualStrings("'a'", buf.items);
- buf.clearRetainingCapacity();
+ try s.codePoint('a');
+ try std.testing.expectEqualStrings("'a'", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.value('a', .{ .emit_codepoint_literals = .always });
- try std.testing.expectEqualStrings("'a'", buf.items);
- buf.clearRetainingCapacity();
+ try s.value('a', .{ .emit_codepoint_literals = .always });
+ try std.testing.expectEqualStrings("'a'", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.value('a', .{ .emit_codepoint_literals = .printable_ascii });
- try std.testing.expectEqualStrings("'a'", buf.items);
- buf.clearRetainingCapacity();
+ try s.value('a', .{ .emit_codepoint_literals = .printable_ascii });
+ try std.testing.expectEqualStrings("'a'", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.value('a', .{ .emit_codepoint_literals = .never });
- try std.testing.expectEqualStrings("97", buf.items);
- buf.clearRetainingCapacity();
+ try s.value('a', .{ .emit_codepoint_literals = .never });
+ try std.testing.expectEqualStrings("97", aw.getWritten());
+ aw.clearRetainingCapacity();
// Short escaped codepoint
- try sz.int('\n');
- try std.testing.expectEqualStrings("10", buf.items);
- buf.clearRetainingCapacity();
+ try s.int('\n');
+ try std.testing.expectEqualStrings("10", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.codePoint('\n');
- try std.testing.expectEqualStrings("'\\n'", buf.items);
- buf.clearRetainingCapacity();
+ try s.codePoint('\n');
+ try std.testing.expectEqualStrings("'\\n'", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.value('\n', .{ .emit_codepoint_literals = .always });
- try std.testing.expectEqualStrings("'\\n'", buf.items);
- buf.clearRetainingCapacity();
+ try s.value('\n', .{ .emit_codepoint_literals = .always });
+ try std.testing.expectEqualStrings("'\\n'", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.value('\n', .{ .emit_codepoint_literals = .printable_ascii });
- try std.testing.expectEqualStrings("10", buf.items);
- buf.clearRetainingCapacity();
+ try s.value('\n', .{ .emit_codepoint_literals = .printable_ascii });
+ try std.testing.expectEqualStrings("10", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.value('\n', .{ .emit_codepoint_literals = .never });
- try std.testing.expectEqualStrings("10", buf.items);
- buf.clearRetainingCapacity();
+ try s.value('\n', .{ .emit_codepoint_literals = .never });
+ try std.testing.expectEqualStrings("10", aw.getWritten());
+ aw.clearRetainingCapacity();
// Large codepoint
- try sz.int('⚡');
- try std.testing.expectEqualStrings("9889", buf.items);
- buf.clearRetainingCapacity();
+ try s.int('⚡');
+ try std.testing.expectEqualStrings("9889", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.codePoint('⚡');
- try std.testing.expectEqualStrings("'\\xe2\\x9a\\xa1'", buf.items);
- buf.clearRetainingCapacity();
+ try s.codePoint('⚡');
+ try std.testing.expectEqualStrings("'\\u{26a1}'", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.value('⚡', .{ .emit_codepoint_literals = .always });
- try std.testing.expectEqualStrings("'\\xe2\\x9a\\xa1'", buf.items);
- buf.clearRetainingCapacity();
+ try s.value('⚡', .{ .emit_codepoint_literals = .always });
+ try std.testing.expectEqualStrings("'\\u{26a1}'", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.value('⚡', .{ .emit_codepoint_literals = .printable_ascii });
- try std.testing.expectEqualStrings("9889", buf.items);
- buf.clearRetainingCapacity();
+ try s.value('⚡', .{ .emit_codepoint_literals = .printable_ascii });
+ try std.testing.expectEqualStrings("9889", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.value('⚡', .{ .emit_codepoint_literals = .never });
- try std.testing.expectEqualStrings("9889", buf.items);
- buf.clearRetainingCapacity();
+ try s.value('⚡', .{ .emit_codepoint_literals = .never });
+ try std.testing.expectEqualStrings("9889", aw.getWritten());
+ aw.clearRetainingCapacity();
// Invalid codepoint
- try std.testing.expectError(error.InvalidCodepoint, sz.codePoint(0x110000 + 1));
+ try s.codePoint(0x110000 + 1);
+ try std.testing.expectEqualStrings("'\\u{110001}'", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.int(0x110000 + 1);
- try std.testing.expectEqualStrings("1114113", buf.items);
- buf.clearRetainingCapacity();
+ try s.int(0x110000 + 1);
+ try std.testing.expectEqualStrings("1114113", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.value(0x110000 + 1, .{ .emit_codepoint_literals = .always });
- try std.testing.expectEqualStrings("1114113", buf.items);
- buf.clearRetainingCapacity();
+ try s.value(0x110000 + 1, .{ .emit_codepoint_literals = .always });
+ try std.testing.expectEqualStrings("1114113", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.value(0x110000 + 1, .{ .emit_codepoint_literals = .printable_ascii });
- try std.testing.expectEqualStrings("1114113", buf.items);
- buf.clearRetainingCapacity();
+ try s.value(0x110000 + 1, .{ .emit_codepoint_literals = .printable_ascii });
+ try std.testing.expectEqualStrings("1114113", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.value(0x110000 + 1, .{ .emit_codepoint_literals = .never });
- try std.testing.expectEqualStrings("1114113", buf.items);
- buf.clearRetainingCapacity();
+ try s.value(0x110000 + 1, .{ .emit_codepoint_literals = .never });
+ try std.testing.expectEqualStrings("1114113", aw.getWritten());
+ aw.clearRetainingCapacity();
// Valid codepoint, not a codepoint type
- try sz.value(@as(u22, 'a'), .{ .emit_codepoint_literals = .always });
- try std.testing.expectEqualStrings("97", buf.items);
- buf.clearRetainingCapacity();
+ try s.value(@as(u22, 'a'), .{ .emit_codepoint_literals = .always });
+ try std.testing.expectEqualStrings("97", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.value(@as(u22, 'a'), .{ .emit_codepoint_literals = .printable_ascii });
- try std.testing.expectEqualStrings("97", buf.items);
- buf.clearRetainingCapacity();
+ try s.value(@as(u22, 'a'), .{ .emit_codepoint_literals = .printable_ascii });
+ try std.testing.expectEqualStrings("97", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.value(@as(i32, 'a'), .{ .emit_codepoint_literals = .never });
- try std.testing.expectEqualStrings("97", buf.items);
- buf.clearRetainingCapacity();
+ try s.value(@as(i32, 'a'), .{ .emit_codepoint_literals = .never });
+ try std.testing.expectEqualStrings("97", aw.getWritten());
+ aw.clearRetainingCapacity();
// Make sure value options are passed to children
- try sz.value(.{ .c = '⚡' }, .{ .emit_codepoint_literals = .always });
- try std.testing.expectEqualStrings(".{ .c = '\\xe2\\x9a\\xa1' }", buf.items);
- buf.clearRetainingCapacity();
+ try s.value(.{ .c = '⚡' }, .{ .emit_codepoint_literals = .always });
+ try std.testing.expectEqualStrings(".{ .c = '\\u{26a1}' }", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.value(.{ .c = '⚡' }, .{ .emit_codepoint_literals = .never });
- try std.testing.expectEqualStrings(".{ .c = 9889 }", buf.items);
- buf.clearRetainingCapacity();
+ try s.value(.{ .c = '⚡' }, .{ .emit_codepoint_literals = .never });
+ try std.testing.expectEqualStrings(".{ .c = 9889 }", aw.getWritten());
+ aw.clearRetainingCapacity();
}
test "std.zon stringify strings" {
- var buf = std.ArrayList(u8).init(std.testing.allocator);
- defer buf.deinit();
- var sz = serializer(buf.writer(), .{});
+ var aw: Writer.Allocating = .init(std.testing.allocator);
+ var s: Serializer = .{ .writer = &aw.writer };
+ defer aw.deinit();
// Minimal case
- try sz.string("abc⚡\n");
- try std.testing.expectEqualStrings("\"abc\\xe2\\x9a\\xa1\\n\"", buf.items);
- buf.clearRetainingCapacity();
+ try s.string("abc⚡\n");
+ try std.testing.expectEqualStrings("\"abc\\xe2\\x9a\\xa1\\n\"", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.tuple("abc⚡\n", .{});
+ try s.tuple("abc⚡\n", .{});
try std.testing.expectEqualStrings(
\\.{
\\ 97,
@@ -1662,14 +1642,14 @@ test "std.zon stringify strings" {
\\ 161,
\\ 10,
\\}
- , buf.items);
- buf.clearRetainingCapacity();
+ , aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.value("abc⚡\n", .{});
- try std.testing.expectEqualStrings("\"abc\\xe2\\x9a\\xa1\\n\"", buf.items);
- buf.clearRetainingCapacity();
+ try s.value("abc⚡\n", .{});
+ try std.testing.expectEqualStrings("\"abc\\xe2\\x9a\\xa1\\n\"", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.value("abc⚡\n", .{ .emit_strings_as_containers = true });
+ try s.value("abc⚡\n", .{ .emit_strings_as_containers = true });
try std.testing.expectEqualStrings(
\\.{
\\ 97,
@@ -1680,113 +1660,113 @@ test "std.zon stringify strings" {
\\ 161,
\\ 10,
\\}
- , buf.items);
- buf.clearRetainingCapacity();
+ , aw.getWritten());
+ aw.clearRetainingCapacity();
// Value options are inherited by children
- try sz.value(.{ .str = "abc" }, .{});
- try std.testing.expectEqualStrings(".{ .str = \"abc\" }", buf.items);
- buf.clearRetainingCapacity();
+ try s.value(.{ .str = "abc" }, .{});
+ try std.testing.expectEqualStrings(".{ .str = \"abc\" }", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.value(.{ .str = "abc" }, .{ .emit_strings_as_containers = true });
+ try s.value(.{ .str = "abc" }, .{ .emit_strings_as_containers = true });
try std.testing.expectEqualStrings(
\\.{ .str = .{
\\ 97,
\\ 98,
\\ 99,
\\} }
- , buf.items);
- buf.clearRetainingCapacity();
+ , aw.getWritten());
+ aw.clearRetainingCapacity();
// Arrays (rather than pointers to arrays) of u8s are not considered strings, so that data can
// round trip correctly.
- try sz.value("abc".*, .{});
+ try s.value("abc".*, .{});
try std.testing.expectEqualStrings(
\\.{
\\ 97,
\\ 98,
\\ 99,
\\}
- , buf.items);
- buf.clearRetainingCapacity();
+ , aw.getWritten());
+ aw.clearRetainingCapacity();
}
test "std.zon stringify multiline strings" {
- var buf = std.ArrayList(u8).init(std.testing.allocator);
- defer buf.deinit();
- var sz = serializer(buf.writer(), .{});
+ var aw: Writer.Allocating = .init(std.testing.allocator);
+ var s: Serializer = .{ .writer = &aw.writer };
+ defer aw.deinit();
inline for (.{ true, false }) |whitespace| {
- sz.options.whitespace = whitespace;
+ s.options.whitespace = whitespace;
{
- try sz.multilineString("", .{ .top_level = true });
- try std.testing.expectEqualStrings("\\\\", buf.items);
- buf.clearRetainingCapacity();
+ try s.multilineString("", .{ .top_level = true });
+ try std.testing.expectEqualStrings("\\\\", aw.getWritten());
+ aw.clearRetainingCapacity();
}
{
- try sz.multilineString("abc⚡", .{ .top_level = true });
- try std.testing.expectEqualStrings("\\\\abc⚡", buf.items);
- buf.clearRetainingCapacity();
+ try s.multilineString("abc⚡", .{ .top_level = true });
+ try std.testing.expectEqualStrings("\\\\abc⚡", aw.getWritten());
+ aw.clearRetainingCapacity();
}
{
- try sz.multilineString("abc⚡\ndef", .{ .top_level = true });
- try std.testing.expectEqualStrings("\\\\abc⚡\n\\\\def", buf.items);
- buf.clearRetainingCapacity();
+ try s.multilineString("abc⚡\ndef", .{ .top_level = true });
+ try std.testing.expectEqualStrings("\\\\abc⚡\n\\\\def", aw.getWritten());
+ aw.clearRetainingCapacity();
}
{
- try sz.multilineString("abc⚡\r\ndef", .{ .top_level = true });
- try std.testing.expectEqualStrings("\\\\abc⚡\n\\\\def", buf.items);
- buf.clearRetainingCapacity();
+ try s.multilineString("abc⚡\r\ndef", .{ .top_level = true });
+ try std.testing.expectEqualStrings("\\\\abc⚡\n\\\\def", aw.getWritten());
+ aw.clearRetainingCapacity();
}
{
- try sz.multilineString("\nabc⚡", .{ .top_level = true });
- try std.testing.expectEqualStrings("\\\\\n\\\\abc⚡", buf.items);
- buf.clearRetainingCapacity();
+ try s.multilineString("\nabc⚡", .{ .top_level = true });
+ try std.testing.expectEqualStrings("\\\\\n\\\\abc⚡", aw.getWritten());
+ aw.clearRetainingCapacity();
}
{
- try sz.multilineString("\r\nabc⚡", .{ .top_level = true });
- try std.testing.expectEqualStrings("\\\\\n\\\\abc⚡", buf.items);
- buf.clearRetainingCapacity();
+ try s.multilineString("\r\nabc⚡", .{ .top_level = true });
+ try std.testing.expectEqualStrings("\\\\\n\\\\abc⚡", aw.getWritten());
+ aw.clearRetainingCapacity();
}
{
- try sz.multilineString("abc\ndef", .{});
+ try s.multilineString("abc\ndef", .{});
if (whitespace) {
- try std.testing.expectEqualStrings("\n\\\\abc\n\\\\def\n", buf.items);
+ try std.testing.expectEqualStrings("\n\\\\abc\n\\\\def\n", aw.getWritten());
} else {
- try std.testing.expectEqualStrings("\\\\abc\n\\\\def\n", buf.items);
+ try std.testing.expectEqualStrings("\\\\abc\n\\\\def\n", aw.getWritten());
}
- buf.clearRetainingCapacity();
+ aw.clearRetainingCapacity();
}
{
const str: []const u8 = &.{ 'a', '\r', 'c' };
- try sz.string(str);
- try std.testing.expectEqualStrings("\"a\\rc\"", buf.items);
- buf.clearRetainingCapacity();
+ try s.string(str);
+ try std.testing.expectEqualStrings("\"a\\rc\"", aw.getWritten());
+ aw.clearRetainingCapacity();
}
{
try std.testing.expectError(
error.InnerCarriageReturn,
- sz.multilineString(@as([]const u8, &.{ 'a', '\r', 'c' }), .{}),
+ s.multilineString(@as([]const u8, &.{ 'a', '\r', 'c' }), .{}),
);
try std.testing.expectError(
error.InnerCarriageReturn,
- sz.multilineString(@as([]const u8, &.{ 'a', '\r', 'c', '\n' }), .{}),
+ s.multilineString(@as([]const u8, &.{ 'a', '\r', 'c', '\n' }), .{}),
);
try std.testing.expectError(
error.InnerCarriageReturn,
- sz.multilineString(@as([]const u8, &.{ 'a', '\r', 'c', '\r', '\n' }), .{}),
+ s.multilineString(@as([]const u8, &.{ 'a', '\r', 'c', '\r', '\n' }), .{}),
);
- try std.testing.expectEqualStrings("", buf.items);
- buf.clearRetainingCapacity();
+ try std.testing.expectEqualStrings("", aw.getWritten());
+ aw.clearRetainingCapacity();
}
}
}
@@ -1932,42 +1912,43 @@ test "std.zon stringify skip default fields" {
}
test "std.zon depth limits" {
- var buf = std.ArrayList(u8).init(std.testing.allocator);
- defer buf.deinit();
+ var aw: Writer.Allocating = .init(std.testing.allocator);
+ const bw = &aw.writer;
+ defer aw.deinit();
const Recurse = struct { r: []const @This() };
// Normal operation
- try serializeMaxDepth(.{ 1, .{ 2, 3 } }, .{}, buf.writer(), 16);
- try std.testing.expectEqualStrings(".{ 1, .{ 2, 3 } }", buf.items);
- buf.clearRetainingCapacity();
+ try serializeMaxDepth(.{ 1, .{ 2, 3 } }, .{}, bw, 16);
+ try std.testing.expectEqualStrings(".{ 1, .{ 2, 3 } }", aw.getWritten());
+ aw.clearRetainingCapacity();
- try serializeArbitraryDepth(.{ 1, .{ 2, 3 } }, .{}, buf.writer());
- try std.testing.expectEqualStrings(".{ 1, .{ 2, 3 } }", buf.items);
- buf.clearRetainingCapacity();
+ try serializeArbitraryDepth(.{ 1, .{ 2, 3 } }, .{}, bw);
+ try std.testing.expectEqualStrings(".{ 1, .{ 2, 3 } }", aw.getWritten());
+ aw.clearRetainingCapacity();
// Max depth failing on non recursive type
try std.testing.expectError(
error.ExceededMaxDepth,
- serializeMaxDepth(.{ 1, .{ 2, .{ 3, 4 } } }, .{}, buf.writer(), 3),
+ serializeMaxDepth(.{ 1, .{ 2, .{ 3, 4 } } }, .{}, bw, 3),
);
- try std.testing.expectEqualStrings("", buf.items);
- buf.clearRetainingCapacity();
+ try std.testing.expectEqualStrings("", aw.getWritten());
+ aw.clearRetainingCapacity();
// Max depth passing on recursive type
{
const maybe_recurse = Recurse{ .r = &.{} };
- try serializeMaxDepth(maybe_recurse, .{}, buf.writer(), 2);
- try std.testing.expectEqualStrings(".{ .r = .{} }", buf.items);
- buf.clearRetainingCapacity();
+ try serializeMaxDepth(maybe_recurse, .{}, bw, 2);
+ try std.testing.expectEqualStrings(".{ .r = .{} }", aw.getWritten());
+ aw.clearRetainingCapacity();
}
// Unchecked passing on recursive type
{
const maybe_recurse = Recurse{ .r = &.{} };
- try serializeArbitraryDepth(maybe_recurse, .{}, buf.writer());
- try std.testing.expectEqualStrings(".{ .r = .{} }", buf.items);
- buf.clearRetainingCapacity();
+ try serializeArbitraryDepth(maybe_recurse, .{}, bw);
+ try std.testing.expectEqualStrings(".{ .r = .{} }", aw.getWritten());
+ aw.clearRetainingCapacity();
}
// Max depth failing on recursive type due to depth
@@ -1976,10 +1957,10 @@ test "std.zon depth limits" {
maybe_recurse.r = &.{.{ .r = &.{} }};
try std.testing.expectError(
error.ExceededMaxDepth,
- serializeMaxDepth(maybe_recurse, .{}, buf.writer(), 2),
+ serializeMaxDepth(maybe_recurse, .{}, bw, 2),
);
- try std.testing.expectEqualStrings("", buf.items);
- buf.clearRetainingCapacity();
+ try std.testing.expectEqualStrings("", aw.getWritten());
+ aw.clearRetainingCapacity();
}
// Same but for a slice
@@ -1989,23 +1970,23 @@ test "std.zon depth limits" {
try std.testing.expectError(
error.ExceededMaxDepth,
- serializeMaxDepth(maybe_recurse, .{}, buf.writer(), 2),
+ serializeMaxDepth(maybe_recurse, .{}, bw, 2),
);
- try std.testing.expectEqualStrings("", buf.items);
- buf.clearRetainingCapacity();
+ try std.testing.expectEqualStrings("", aw.getWritten());
+ aw.clearRetainingCapacity();
- var sz = serializer(buf.writer(), .{});
+ var s: Serializer = .{ .writer = bw };
try std.testing.expectError(
error.ExceededMaxDepth,
- sz.tupleMaxDepth(maybe_recurse, .{}, 2),
+ s.tupleMaxDepth(maybe_recurse, .{}, 2),
);
- try std.testing.expectEqualStrings("", buf.items);
- buf.clearRetainingCapacity();
+ try std.testing.expectEqualStrings("", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.tupleArbitraryDepth(maybe_recurse, .{});
- try std.testing.expectEqualStrings(".{.{ .r = .{} }}", buf.items);
- buf.clearRetainingCapacity();
+ try s.tupleArbitraryDepth(maybe_recurse, .{});
+ try std.testing.expectEqualStrings(".{.{ .r = .{} }}", aw.getWritten());
+ aw.clearRetainingCapacity();
}
// A slice succeeding
@@ -2013,19 +1994,19 @@ test "std.zon depth limits" {
var temp: [1]Recurse = .{.{ .r = &.{} }};
const maybe_recurse: []const Recurse = &temp;
- try serializeMaxDepth(maybe_recurse, .{}, buf.writer(), 3);
- try std.testing.expectEqualStrings(".{.{ .r = .{} }}", buf.items);
- buf.clearRetainingCapacity();
+ try serializeMaxDepth(maybe_recurse, .{}, bw, 3);
+ try std.testing.expectEqualStrings(".{.{ .r = .{} }}", aw.getWritten());
+ aw.clearRetainingCapacity();
- var sz = serializer(buf.writer(), .{});
+ var s: Serializer = .{ .writer = bw };
- try sz.tupleMaxDepth(maybe_recurse, .{}, 3);
- try std.testing.expectEqualStrings(".{.{ .r = .{} }}", buf.items);
- buf.clearRetainingCapacity();
+ try s.tupleMaxDepth(maybe_recurse, .{}, 3);
+ try std.testing.expectEqualStrings(".{.{ .r = .{} }}", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.tupleArbitraryDepth(maybe_recurse, .{});
- try std.testing.expectEqualStrings(".{.{ .r = .{} }}", buf.items);
- buf.clearRetainingCapacity();
+ try s.tupleArbitraryDepth(maybe_recurse, .{});
+ try std.testing.expectEqualStrings(".{.{ .r = .{} }}", aw.getWritten());
+ aw.clearRetainingCapacity();
}
// Max depth failing on recursive type due to recursion
@@ -2036,46 +2017,46 @@ test "std.zon depth limits" {
try std.testing.expectError(
error.ExceededMaxDepth,
- serializeMaxDepth(maybe_recurse, .{}, buf.writer(), 128),
+ serializeMaxDepth(maybe_recurse, .{}, bw, 128),
);
- try std.testing.expectEqualStrings("", buf.items);
- buf.clearRetainingCapacity();
+ try std.testing.expectEqualStrings("", aw.getWritten());
+ aw.clearRetainingCapacity();
- var sz = serializer(buf.writer(), .{});
+ var s: Serializer = .{ .writer = bw };
try std.testing.expectError(
error.ExceededMaxDepth,
- sz.tupleMaxDepth(maybe_recurse, .{}, 128),
+ s.tupleMaxDepth(maybe_recurse, .{}, 128),
);
- try std.testing.expectEqualStrings("", buf.items);
- buf.clearRetainingCapacity();
+ try std.testing.expectEqualStrings("", aw.getWritten());
+ aw.clearRetainingCapacity();
}
// Max depth on other parts of the lower level API
{
- var sz = serializer(buf.writer(), .{});
+ var s: Serializer = .{ .writer = bw };
const maybe_recurse: []const Recurse = &.{};
- try std.testing.expectError(error.ExceededMaxDepth, sz.valueMaxDepth(1, .{}, 0));
- try sz.valueMaxDepth(2, .{}, 1);
- try sz.value(3, .{});
- try sz.valueArbitraryDepth(maybe_recurse, .{});
+ try std.testing.expectError(error.ExceededMaxDepth, s.valueMaxDepth(1, .{}, 0));
+ try s.valueMaxDepth(2, .{}, 1);
+ try s.value(3, .{});
+ try s.valueArbitraryDepth(maybe_recurse, .{});
- var s = try sz.beginStruct(.{});
- try std.testing.expectError(error.ExceededMaxDepth, s.fieldMaxDepth("a", 1, .{}, 0));
- try s.fieldMaxDepth("b", 4, .{}, 1);
- try s.field("c", 5, .{});
- try s.fieldArbitraryDepth("d", maybe_recurse, .{});
- try s.end();
+ var wip_struct = try s.beginStruct(.{});
+ try std.testing.expectError(error.ExceededMaxDepth, wip_struct.fieldMaxDepth("a", 1, .{}, 0));
+ try wip_struct.fieldMaxDepth("b", 4, .{}, 1);
+ try wip_struct.field("c", 5, .{});
+ try wip_struct.fieldArbitraryDepth("d", maybe_recurse, .{});
+ try wip_struct.end();
- var t = try sz.beginTuple(.{});
+ var t = try s.beginTuple(.{});
try std.testing.expectError(error.ExceededMaxDepth, t.fieldMaxDepth(1, .{}, 0));
try t.fieldMaxDepth(6, .{}, 1);
try t.field(7, .{});
try t.fieldArbitraryDepth(maybe_recurse, .{});
try t.end();
- var a = try sz.beginTuple(.{});
+ var a = try s.beginTuple(.{});
try std.testing.expectError(error.ExceededMaxDepth, a.fieldMaxDepth(1, .{}, 0));
try a.fieldMaxDepth(8, .{}, 1);
try a.field(9, .{});
@@ -2096,7 +2077,7 @@ test "std.zon depth limits" {
\\ 9,
\\ .{},
\\}
- , buf.items);
+ , aw.getWritten());
}
}
@@ -2192,42 +2173,42 @@ test "std.zon stringify primitives" {
}
test "std.zon stringify ident" {
- var buf = std.ArrayList(u8).init(std.testing.allocator);
- defer buf.deinit();
- var sz = serializer(buf.writer(), .{});
+ var aw: Writer.Allocating = .init(std.testing.allocator);
+ var s: Serializer = .{ .writer = &aw.writer };
+ defer aw.deinit();
try expectSerializeEqual(".{ .a = 0 }", .{ .a = 0 }, .{});
- try sz.ident("a");
- try std.testing.expectEqualStrings(".a", buf.items);
- buf.clearRetainingCapacity();
+ try s.ident("a");
+ try std.testing.expectEqualStrings(".a", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.ident("foo_1");
- try std.testing.expectEqualStrings(".foo_1", buf.items);
- buf.clearRetainingCapacity();
+ try s.ident("foo_1");
+ try std.testing.expectEqualStrings(".foo_1", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.ident("_foo_1");
- try std.testing.expectEqualStrings("._foo_1", buf.items);
- buf.clearRetainingCapacity();
+ try s.ident("_foo_1");
+ try std.testing.expectEqualStrings("._foo_1", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.ident("foo bar");
- try std.testing.expectEqualStrings(".@\"foo bar\"", buf.items);
- buf.clearRetainingCapacity();
+ try s.ident("foo bar");
+ try std.testing.expectEqualStrings(".@\"foo bar\"", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.ident("1foo");
- try std.testing.expectEqualStrings(".@\"1foo\"", buf.items);
- buf.clearRetainingCapacity();
+ try s.ident("1foo");
+ try std.testing.expectEqualStrings(".@\"1foo\"", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.ident("var");
- try std.testing.expectEqualStrings(".@\"var\"", buf.items);
- buf.clearRetainingCapacity();
+ try s.ident("var");
+ try std.testing.expectEqualStrings(".@\"var\"", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.ident("true");
- try std.testing.expectEqualStrings(".true", buf.items);
- buf.clearRetainingCapacity();
+ try s.ident("true");
+ try std.testing.expectEqualStrings(".true", aw.getWritten());
+ aw.clearRetainingCapacity();
- try sz.ident("_");
- try std.testing.expectEqualStrings("._", buf.items);
- buf.clearRetainingCapacity();
+ try s.ident("_");
+ try std.testing.expectEqualStrings("._", aw.getWritten());
+ aw.clearRetainingCapacity();
const Enum = enum {
@"foo bar",
@@ -2239,40 +2220,40 @@ test "std.zon stringify ident" {
}
test "std.zon stringify as tuple" {
- var buf = std.ArrayList(u8).init(std.testing.allocator);
- defer buf.deinit();
- var sz = serializer(buf.writer(), .{});
+ var aw: Writer.Allocating = .init(std.testing.allocator);
+ var s: Serializer = .{ .writer = &aw.writer };
+ defer aw.deinit();
// Tuples
- try sz.tuple(.{ 1, 2 }, .{});
- try std.testing.expectEqualStrings(".{ 1, 2 }", buf.items);
- buf.clearRetainingCapacity();
+ try s.tuple(.{ 1, 2 }, .{});
+ try std.testing.expectEqualStrings(".{ 1, 2 }", aw.getWritten());
+ aw.clearRetainingCapacity();
// Slice
- try sz.tuple(@as([]const u8, &.{ 1, 2 }), .{});
- try std.testing.expectEqualStrings(".{ 1, 2 }", buf.items);
- buf.clearRetainingCapacity();
+ try s.tuple(@as([]const u8, &.{ 1, 2 }), .{});
+ try std.testing.expectEqualStrings(".{ 1, 2 }", aw.getWritten());
+ aw.clearRetainingCapacity();
// Array
- try sz.tuple([2]u8{ 1, 2 }, .{});
- try std.testing.expectEqualStrings(".{ 1, 2 }", buf.items);
- buf.clearRetainingCapacity();
+ try s.tuple([2]u8{ 1, 2 }, .{});
+ try std.testing.expectEqualStrings(".{ 1, 2 }", aw.getWritten());
+ aw.clearRetainingCapacity();
}
test "std.zon stringify as float" {
- var buf = std.ArrayList(u8).init(std.testing.allocator);
- defer buf.deinit();
- var sz = serializer(buf.writer(), .{});
+ var aw: Writer.Allocating = .init(std.testing.allocator);
+ var s: Serializer = .{ .writer = &aw.writer };
+ defer aw.deinit();
// Comptime float
- try sz.float(2.5);
- try std.testing.expectEqualStrings("2.5", buf.items);
- buf.clearRetainingCapacity();
+ try s.float(2.5);
+ try std.testing.expectEqualStrings("2.5", aw.getWritten());
+ aw.clearRetainingCapacity();
// Sized float
- try sz.float(@as(f32, 2.5));
- try std.testing.expectEqualStrings("2.5", buf.items);
- buf.clearRetainingCapacity();
+ try s.float(@as(f32, 2.5));
+ try std.testing.expectEqualStrings("2.5", aw.getWritten());
+ aw.clearRetainingCapacity();
}
test "std.zon stringify vector" {
@@ -2364,13 +2345,13 @@ test "std.zon pointers" {
}
test "std.zon tuple/struct field" {
- var buf = std.ArrayList(u8).init(std.testing.allocator);
- defer buf.deinit();
- var sz = serializer(buf.writer(), .{});
+ var aw: Writer.Allocating = .init(std.testing.allocator);
+ var s: Serializer = .{ .writer = &aw.writer };
+ defer aw.deinit();
// Test on structs
{
- var root = try sz.beginStruct(.{});
+ var root = try s.beginStruct(.{});
{
var tuple = try root.beginTupleField("foo", .{});
try tuple.field(0, .{});
@@ -2396,13 +2377,13 @@ test "std.zon tuple/struct field" {
\\ .b = 1,
\\ },
\\}
- , buf.items);
- buf.clearRetainingCapacity();
+ , aw.getWritten());
+ aw.clearRetainingCapacity();
}
// Test on tuples
{
- var root = try sz.beginTuple(.{});
+ var root = try s.beginTuple(.{});
{
var tuple = try root.beginTupleField(.{});
try tuple.field(0, .{});
@@ -2428,7 +2409,7 @@ test "std.zon tuple/struct field" {
\\ .b = 1,
\\ },
\\}
- , buf.items);
- buf.clearRetainingCapacity();
+ , aw.getWritten());
+ aw.clearRetainingCapacity();
}
}
lib/std/zig.zig
@@ -446,8 +446,8 @@ pub fn fmtString(bytes: []const u8) std.fmt.Formatter([]const u8, stringEscape)
}
/// Return a formatter for escaping a single quoted Zig string.
-pub fn fmtChar(bytes: []const u8) std.fmt.Formatter([]const u8, charEscape) {
- return .{ .data = bytes };
+pub fn fmtChar(c: u21) std.fmt.Formatter(u21, charEscape) {
+ return .{ .data = c };
}
test fmtString {
@@ -458,9 +458,7 @@ test fmtString {
}
test fmtChar {
- try std.testing.expectFmt(
- \\" \\ hi \x07 \x11 " derp \'"
- , "\"{f}\"", .{fmtChar(" \\ hi \x07 \x11 \" derp '")});
+ try std.testing.expectFmt("c \\u{26a1}", "{f} {f}", .{ fmtChar('c'), fmtChar('⚡') });
}
/// Print the string as escaped contents of a double quoted string.
@@ -480,21 +478,26 @@ pub fn stringEscape(bytes: []const u8, w: *Writer) Writer.Error!void {
};
}
-/// Print the string as escaped contents of a single-quoted string.
-pub fn charEscape(bytes: []const u8, w: *Writer) Writer.Error!void {
- for (bytes) |byte| switch (byte) {
+/// Print as escaped contents of a single-quoted string.
+pub fn charEscape(codepoint: u21, w: *Writer) Writer.Error!void {
+ switch (codepoint) {
'\n' => try w.writeAll("\\n"),
'\r' => try w.writeAll("\\r"),
'\t' => try w.writeAll("\\t"),
'\\' => try w.writeAll("\\\\"),
- '"' => try w.writeByte('"'),
'\'' => try w.writeAll("\\'"),
- ' ', '!', '#'...'&', '('...'[', ']'...'~' => try w.writeByte(byte),
+ '"', ' ', '!', '#'...'&', '('...'[', ']'...'~' => try w.writeByte(@intCast(codepoint)),
else => {
- try w.writeAll("\\x");
- try w.printInt(byte, 16, .lower, .{ .width = 2, .fill = '0' });
+ if (std.math.cast(u8, codepoint)) |byte| {
+ try w.writeAll("\\x");
+ try w.printInt(byte, 16, .lower, .{ .width = 2, .fill = '0' });
+ } else {
+ try w.writeAll("\\u{");
+ try w.printInt(codepoint, 16, .lower, .{});
+ try w.writeByte('}');
+ }
},
- };
+ }
}
pub fn isValidId(bytes: []const u8) bool {