authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-19 16:59:16-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-19 18:27:09-07:00
logc3da98cf5a8b8a3164db78998bda848100871918
tree63f6d15eedc64b24ed00266a204fd8b391278709
parentb956b021878cd7b67f01c30a30fcb085887f24dc

std.zon: update to new I/O API


5 files changed, 959 insertions(+), 973 deletions(-)

lib/std/Build/Cache/Path.zig+5-3
...@@ -161,17 +161,19 @@ pub fn formatEscapeString(path: Path, writer: *std.io.Writer) std.io.Writer.Erro...@@ -161,17 +161,19 @@ pub fn formatEscapeString(path: Path, writer: *std.io.Writer) std.io.Writer.Erro
161 }161 }
162}162}
163163
164/// Deprecated, use double quoted escape to print paths.
164pub fn fmtEscapeChar(path: Path) std.fmt.Formatter(Path, formatEscapeChar) {165pub fn fmtEscapeChar(path: Path) std.fmt.Formatter(Path, formatEscapeChar) {
165 return .{ .data = path };166 return .{ .data = path };
166}167}
167168
169/// Deprecated, use double quoted escape to print paths.
168pub fn formatEscapeChar(path: Path, writer: *std.io.Writer) std.io.Writer.Error!void {170pub fn formatEscapeChar(path: Path, writer: *std.io.Writer) std.io.Writer.Error!void {
169 if (path.root_dir.path) |p| {171 if (path.root_dir.path) |p| {
170 try std.zig.charEscape(p, writer);172 for (p) |byte| try std.zig.charEscape(byte, writer);
171 if (path.sub_path.len > 0) try std.zig.charEscape(fs.path.sep_str, writer);173 if (path.sub_path.len > 0) try writer.writeByte(fs.path.sep);
172 }174 }
173 if (path.sub_path.len > 0) {175 if (path.sub_path.len > 0) {
174 try std.zig.charEscape(path.sub_path, writer);176 for (path.sub_path) |byte| try std.zig.charEscape(byte, writer);
175 }177 }
176}178}
177179
lib/std/zig.zig+16-13
...@@ -446,8 +446,8 @@ pub fn fmtString(bytes: []const u8) std.fmt.Formatter([]const u8, stringEscape)...@@ -446,8 +446,8 @@ pub fn fmtString(bytes: []const u8) std.fmt.Formatter([]const u8, stringEscape)
446}446}
447447
448/// Return a formatter for escaping a single quoted Zig string.448/// Return a formatter for escaping a single quoted Zig string.
449pub fn fmtChar(bytes: []const u8) std.fmt.Formatter([]const u8, charEscape) {449pub fn fmtChar(c: u21) std.fmt.Formatter(u21, charEscape) {
450 return .{ .data = bytes };450 return .{ .data = c };
451}451}
452452
453test fmtString {453test fmtString {
...@@ -458,9 +458,7 @@ test fmtString {...@@ -458,9 +458,7 @@ test fmtString {
458}458}
459459
460test fmtChar {460test fmtChar {
461 try std.testing.expectFmt(461 try std.testing.expectFmt("c \\u{26a1}", "{f} {f}", .{ fmtChar('c'), fmtChar('⚡') });
462 \\" \\ hi \x07 \x11 " derp \'"
463 , "\"{f}\"", .{fmtChar(" \\ hi \x07 \x11 \" derp '")});
464}462}
465463
466/// Print the string as escaped contents of a double quoted string.464/// 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 {...@@ -480,21 +478,26 @@ pub fn stringEscape(bytes: []const u8, w: *Writer) Writer.Error!void {
480 };478 };
481}479}
482480
483/// Print the string as escaped contents of a single-quoted string.481/// Print as escaped contents of a single-quoted string.
484pub fn charEscape(bytes: []const u8, w: *Writer) Writer.Error!void {482pub fn charEscape(codepoint: u21, w: *Writer) Writer.Error!void {
485 for (bytes) |byte| switch (byte) {483 switch (codepoint) {
486 '\n' => try w.writeAll("\\n"),484 '\n' => try w.writeAll("\\n"),
487 '\r' => try w.writeAll("\\r"),485 '\r' => try w.writeAll("\\r"),
488 '\t' => try w.writeAll("\\t"),486 '\t' => try w.writeAll("\\t"),
489 '\\' => try w.writeAll("\\\\"),487 '\\' => try w.writeAll("\\\\"),
490 '"' => try w.writeByte('"'),
491 '\'' => try w.writeAll("\\'"),488 '\'' => try w.writeAll("\\'"),
492 ' ', '!', '#'...'&', '('...'[', ']'...'~' => try w.writeByte(byte),489 '"', ' ', '!', '#'...'&', '('...'[', ']'...'~' => try w.writeByte(@intCast(codepoint)),
493 else => {490 else => {
494 try w.writeAll("\\x");491 if (std.math.cast(u8, codepoint)) |byte| {
495 try w.printInt(byte, 16, .lower, .{ .width = 2, .fill = '0' });492 try w.writeAll("\\x");
493 try w.printInt(byte, 16, .lower, .{ .width = 2, .fill = '0' });
494 } else {
495 try w.writeAll("\\u{");
496 try w.printInt(codepoint, 16, .lower, .{});
497 try w.writeByte('}');
498 }
496 },499 },
497 };500 }
498}501}
499502
500pub fn isValidId(bytes: []const u8) bool {503pub fn isValidId(bytes: []const u8) bool {
lib/std/zig/Ast.zig+1-1
...@@ -574,7 +574,7 @@ pub fn renderError(tree: Ast, parse_error: Error, w: *Writer) Writer.Error!void...@@ -574,7 +574,7 @@ pub fn renderError(tree: Ast, parse_error: Error, w: *Writer) Writer.Error!void
574 '/' => "comment",574 '/' => "comment",
575 else => unreachable,575 else => unreachable,
576 },576 },
577 std.zig.fmtChar(tok_slice[parse_error.extra.offset..][0..1]),577 std.zig.fmtChar(tok_slice[parse_error.extra.offset]),
578 });578 });
579 },579 },
580580
lib/std/zon/parse.zig+13-13
...@@ -64,14 +64,14 @@ pub const Error = union(enum) {...@@ -64,14 +64,14 @@ pub const Error = union(enum) {
64 }64 }
65 };65 };
6666
67 fn formatMessage(self: []const u8, w: *std.io.Writer) std.io.Writer.Error!void {67 fn formatMessage(self: []const u8, w: *std.Io.Writer) std.Io.Writer.Error!void {
68 // Just writes the string for now, but we're keeping this behind a formatter so we have68 // Just writes the string for now, but we're keeping this behind a formatter so we have
69 // the option to extend it in the future to print more advanced messages (like `Error`69 // the option to extend it in the future to print more advanced messages (like `Error`
70 // does) without breaking the API.70 // does) without breaking the API.
71 try w.writeAll(self);71 try w.writeAll(self);
72 }72 }
7373
74 pub fn fmtMessage(self: Note, diag: *const Diagnostics) std.fmt.Formatter([]const u8, Note.formatMessage) {74 pub fn fmtMessage(self: Note, diag: *const Diagnostics) std.fmt.Alt([]const u8, Note.formatMessage) {
75 return .{ .data = switch (self) {75 return .{ .data = switch (self) {
76 .zoir => |note| note.msg.get(diag.zoir),76 .zoir => |note| note.msg.get(diag.zoir),
77 .type_check => |note| note.msg,77 .type_check => |note| note.msg,
...@@ -147,14 +147,14 @@ pub const Error = union(enum) {...@@ -147,14 +147,14 @@ pub const Error = union(enum) {
147 diag: *const Diagnostics,147 diag: *const Diagnostics,
148 };148 };
149149
150 fn formatMessage(self: FormatMessage, w: *std.io.Writer) std.io.Writer.Error!void {150 fn formatMessage(self: FormatMessage, w: *std.Io.Writer) std.Io.Writer.Error!void {
151 switch (self.err) {151 switch (self.err) {
152 .zoir => |err| try w.writeAll(err.msg.get(self.diag.zoir)),152 .zoir => |err| try w.writeAll(err.msg.get(self.diag.zoir)),
153 .type_check => |tc| try w.writeAll(tc.message),153 .type_check => |tc| try w.writeAll(tc.message),
154 }154 }
155 }155 }
156156
157 pub fn fmtMessage(self: @This(), diag: *const Diagnostics) std.fmt.Formatter(FormatMessage, formatMessage) {157 pub fn fmtMessage(self: @This(), diag: *const Diagnostics) std.fmt.Alt(FormatMessage, formatMessage) {
158 return .{ .data = .{158 return .{ .data = .{
159 .err = self,159 .err = self,
160 .diag = diag,160 .diag = diag,
...@@ -226,7 +226,7 @@ pub const Diagnostics = struct {...@@ -226,7 +226,7 @@ pub const Diagnostics = struct {
226 return .{ .diag = self };226 return .{ .diag = self };
227 }227 }
228228
229 pub fn format(self: *const @This(), w: *std.io.Writer) std.io.Writer.Error!void {229 pub fn format(self: *const @This(), w: *std.Io.Writer) std.Io.Writer.Error!void {
230 var errors = self.iterateErrors();230 var errors = self.iterateErrors();
231 while (errors.next()) |err| {231 while (errors.next()) |err| {
232 const loc = err.getLocation(self);232 const loc = err.getLocation(self);
...@@ -606,7 +606,7 @@ const Parser = struct {...@@ -606,7 +606,7 @@ const Parser = struct {
606 }606 }
607 }607 }
608608
609 fn parseSlicePointer(self: *@This(), T: type, node: Zoir.Node.Index) !T {609 fn parseSlicePointer(self: *@This(), T: type, node: Zoir.Node.Index) ParseExprInnerError!T {
610 switch (node.get(self.zoir)) {610 switch (node.get(self.zoir)) {
611 .string_literal => return self.parseString(T, node),611 .string_literal => return self.parseString(T, node),
612 .array_literal => |nodes| return self.parseSlice(T, nodes),612 .array_literal => |nodes| return self.parseSlice(T, nodes),
...@@ -1048,6 +1048,7 @@ const Parser = struct {...@@ -1048,6 +1048,7 @@ const Parser = struct {
1048 name: []const u8,1048 name: []const u8,
1049 ) error{ OutOfMemory, ParseZon } {1049 ) error{ OutOfMemory, ParseZon } {
1050 @branchHint(.cold);1050 @branchHint(.cold);
1051 const gpa = self.gpa;
1051 const token = if (field) |f| b: {1052 const token = if (field) |f| b: {
1052 var buf: [2]Ast.Node.Index = undefined;1053 var buf: [2]Ast.Node.Index = undefined;
1053 const struct_init = self.ast.fullStructInit(&buf, node.getAstNode(self.zoir)).?;1054 const struct_init = self.ast.fullStructInit(&buf, node.getAstNode(self.zoir)).?;
...@@ -1065,13 +1066,12 @@ const Parser = struct {...@@ -1065,13 +1066,12 @@ const Parser = struct {
1065 };1066 };
1066 } else b: {1067 } else b: {
1067 const msg = "supported: ";1068 const msg = "supported: ";
1068 var buf: std.ArrayListUnmanaged(u8) = try .initCapacity(self.gpa, 64);1069 var buf: std.ArrayListUnmanaged(u8) = try .initCapacity(gpa, 64);
1069 defer buf.deinit(self.gpa);1070 defer buf.deinit(gpa);
1070 const writer = buf.writer(self.gpa);1071 try buf.appendSlice(gpa, msg);
1071 try writer.writeAll(msg);
1072 inline for (info.fields, 0..) |field_info, i| {1072 inline for (info.fields, 0..) |field_info, i| {
1073 if (i != 0) try writer.writeAll(", ");1073 if (i != 0) try buf.appendSlice(gpa, ", ");
1074 try writer.print("'{f}'", .{std.zig.fmtIdFlags(field_info.name, .{1074 try buf.print(gpa, "'{f}'", .{std.zig.fmtIdFlags(field_info.name, .{
1075 .allow_primitive = true,1075 .allow_primitive = true,
1076 .allow_underscore = true,1076 .allow_underscore = true,
1077 })});1077 })});
...@@ -1079,7 +1079,7 @@ const Parser = struct {...@@ -1079,7 +1079,7 @@ const Parser = struct {
1079 break :b .{1079 break :b .{
1080 .token = token,1080 .token = token,
1081 .offset = 0,1081 .offset = 0,
1082 .msg = try buf.toOwnedSlice(self.gpa),1082 .msg = try buf.toOwnedSlice(gpa),
1083 .owned = true,1083 .owned = true,
1084 };1084 };
1085 };1085 };
lib/std/zon/stringify.zig+924-943
...@@ -22,6 +22,7 @@...@@ -22,6 +22,7 @@
2222
23const std = @import("std");23const std = @import("std");
24const assert = std.debug.assert;24const assert = std.debug.assert;
25const Writer = std.Io.Writer;
2526
26/// Options for `serialize`.27/// Options for `serialize`.
27pub const SerializeOptions = struct {28pub const SerializeOptions = struct {
...@@ -40,15 +41,12 @@ pub const SerializeOptions = struct {...@@ -40,15 +41,12 @@ pub const SerializeOptions = struct {
40/// Serialize the given value as ZON.41/// Serialize the given value as ZON.
41///42///
42/// It is asserted at comptime that `@TypeOf(val)` is not a recursive type.43/// It is asserted at comptime that `@TypeOf(val)` is not a recursive type.
43pub fn serialize(44pub fn serialize(val: anytype, options: SerializeOptions, writer: *Writer) Writer.Error!void {
44 val: anytype,45 var s: Serializer = .{
45 options: SerializeOptions,46 .writer = writer,
46 writer: anytype,47 .options = .{ .whitespace = options.whitespace },
47) @TypeOf(writer).Error!void {48 };
48 var sz = serializer(writer, .{49 try s.value(val, .{
49 .whitespace = options.whitespace,
50 });
51 try sz.value(val, .{
52 .emit_codepoint_literals = options.emit_codepoint_literals,50 .emit_codepoint_literals = options.emit_codepoint_literals,
53 .emit_strings_as_containers = options.emit_strings_as_containers,51 .emit_strings_as_containers = options.emit_strings_as_containers,
54 .emit_default_optional_fields = options.emit_default_optional_fields,52 .emit_default_optional_fields = options.emit_default_optional_fields,
...@@ -62,13 +60,14 @@ pub fn serialize(...@@ -62,13 +60,14 @@ pub fn serialize(
62pub fn serializeMaxDepth(60pub fn serializeMaxDepth(
63 val: anytype,61 val: anytype,
64 options: SerializeOptions,62 options: SerializeOptions,
65 writer: anytype,63 writer: *Writer,
66 depth: usize,64 depth: usize,
67) (@TypeOf(writer).Error || error{ExceededMaxDepth})!void {65) Serializer.DepthError!void {
68 var sz = serializer(writer, .{66 var s: Serializer = .{
69 .whitespace = options.whitespace,67 .writer = writer,
70 });68 .options = .{ .whitespace = options.whitespace },
71 try sz.valueMaxDepth(val, .{69 };
70 try s.valueMaxDepth(val, .{
72 .emit_codepoint_literals = options.emit_codepoint_literals,71 .emit_codepoint_literals = options.emit_codepoint_literals,
73 .emit_strings_as_containers = options.emit_strings_as_containers,72 .emit_strings_as_containers = options.emit_strings_as_containers,
74 .emit_default_optional_fields = options.emit_default_optional_fields,73 .emit_default_optional_fields = options.emit_default_optional_fields,
...@@ -81,44 +80,45 @@ pub fn serializeMaxDepth(...@@ -81,44 +80,45 @@ pub fn serializeMaxDepth(
81pub fn serializeArbitraryDepth(80pub fn serializeArbitraryDepth(
82 val: anytype,81 val: anytype,
83 options: SerializeOptions,82 options: SerializeOptions,
84 writer: anytype,83 writer: *Writer,
85) @TypeOf(writer).Error!void {84) Serializer.Error!void {
86 var sz = serializer(writer, .{85 var s: Serializer = .{
87 .whitespace = options.whitespace,86 .writer = writer,
88 });87 .options = .{ .whitespace = options.whitespace },
89 try sz.valueArbitraryDepth(val, .{88 };
89 try s.valueArbitraryDepth(val, .{
90 .emit_codepoint_literals = options.emit_codepoint_literals,90 .emit_codepoint_literals = options.emit_codepoint_literals,
91 .emit_strings_as_containers = options.emit_strings_as_containers,91 .emit_strings_as_containers = options.emit_strings_as_containers,
92 .emit_default_optional_fields = options.emit_default_optional_fields,92 .emit_default_optional_fields = options.emit_default_optional_fields,
93 });93 });
94}94}
9595
96fn typeIsRecursive(comptime T: type) bool {96inline fn typeIsRecursive(comptime T: type) bool {
97 return comptime typeIsRecursiveImpl(T, &.{});97 return comptime typeIsRecursiveInner(T, &.{});
98}98}
9999
100fn typeIsRecursiveImpl(comptime T: type, comptime prev_visited: []const type) bool {100fn typeIsRecursiveInner(comptime T: type, comptime prev_visited: []const type) bool {
101 for (prev_visited) |V| {101 for (prev_visited) |V| {
102 if (V == T) return true;102 if (V == T) return true;
103 }103 }
104 const visited = prev_visited ++ .{T};104 const visited = prev_visited ++ .{T};
105105
106 return switch (@typeInfo(T)) {106 return switch (@typeInfo(T)) {
107 .pointer => |pointer| typeIsRecursiveImpl(pointer.child, visited),107 .pointer => |pointer| typeIsRecursiveInner(pointer.child, visited),
108 .optional => |optional| typeIsRecursiveImpl(optional.child, visited),108 .optional => |optional| typeIsRecursiveInner(optional.child, visited),
109 .array => |array| typeIsRecursiveImpl(array.child, visited),109 .array => |array| typeIsRecursiveInner(array.child, visited),
110 .vector => |vector| typeIsRecursiveImpl(vector.child, visited),110 .vector => |vector| typeIsRecursiveInner(vector.child, visited),
111 .@"struct" => |@"struct"| for (@"struct".fields) |field| {111 .@"struct" => |@"struct"| for (@"struct".fields) |field| {
112 if (typeIsRecursiveImpl(field.type, visited)) break true;112 if (typeIsRecursiveInner(field.type, visited)) break true;
113 } else false,113 } else false,
114 .@"union" => |@"union"| inline for (@"union".fields) |field| {114 .@"union" => |@"union"| inline for (@"union".fields) |field| {
115 if (typeIsRecursiveImpl(field.type, visited)) break true;115 if (typeIsRecursiveInner(field.type, visited)) break true;
116 } else false,116 } else false,
117 else => false,117 else => false,
118 };118 };
119}119}
120120
121fn canSerializeType(T: type) bool {121inline fn canSerializeType(T: type) bool {
122 comptime return canSerializeTypeInner(T, &.{}, false);122 comptime return canSerializeTypeInner(T, &.{}, false);
123}123}
124124
...@@ -343,12 +343,6 @@ test "std.zon checkValueDepth" {...@@ -343,12 +343,6 @@ test "std.zon checkValueDepth" {
343 try expectValueDepthEquals(3, @as([]const []const u8, &.{&.{ 1, 2, 3 }}));343 try expectValueDepthEquals(3, @as([]const []const u8, &.{&.{ 1, 2, 3 }}));
344}344}
345345
346/// Options for `Serializer`.
347pub const SerializerOptions = struct {
348 /// If false, only syntactically necessary whitespace is emitted.
349 whitespace: bool = true,
350};
351
352/// Determines when to emit Unicode code point literals as opposed to integer literals.346/// Determines when to emit Unicode code point literals as opposed to integer literals.
353pub const EmitCodepointLiterals = enum {347pub const EmitCodepointLiterals = enum {
354 /// Never emit Unicode code point literals.348 /// Never emit Unicode code point literals.
...@@ -440,634 +434,616 @@ pub const SerializeContainerOptions = struct {...@@ -440,634 +434,616 @@ pub const SerializeContainerOptions = struct {
440/// For manual serialization of containers, see:434/// For manual serialization of containers, see:
441/// * `beginStruct`435/// * `beginStruct`
442/// * `beginTuple`436/// * `beginTuple`
443///437pub const Serializer = struct {
444/// # Example438 options: Options = .{},
445/// ```zig439 indent_level: u8 = 0,
446/// var sz = serializer(writer, .{});440 writer: *Writer,
447/// var vec2 = try sz.beginStruct(.{});
448/// try vec2.field("x", 1.5, .{});
449/// try vec2.fieldPrefix();
450/// try sz.value(2.5);
451/// try vec2.end();
452/// ```
453pub fn Serializer(Writer: type) type {
454 return struct {
455 const Self = @This();
456
457 options: SerializerOptions,
458 indent_level: u8,
459 writer: Writer,
460
461 /// Initialize a serializer.
462 fn init(writer: Writer, options: SerializerOptions) Self {
463 return .{
464 .options = options,
465 .writer = writer,
466 .indent_level = 0,
467 };
468 }
469441
470 /// Serialize a value, similar to `serialize`.442 pub const Error = Writer.Error;
471 pub fn value(self: *Self, val: anytype, options: ValueOptions) Writer.Error!void {443 pub const DepthError = Error || error{ExceededMaxDepth};
472 comptime assert(!typeIsRecursive(@TypeOf(val)));
473 return self.valueArbitraryDepth(val, options);
474 }
475444
476 /// Serialize a value, similar to `serializeMaxDepth`.445 pub const Options = struct {
477 pub fn valueMaxDepth(446 /// If false, only syntactically necessary whitespace is emitted.
478 self: *Self,447 whitespace: bool = true,
479 val: anytype,448 };
480 options: ValueOptions,
481 depth: usize,
482 ) (Writer.Error || error{ExceededMaxDepth})!void {
483 try checkValueDepth(val, depth);
484 return self.valueArbitraryDepth(val, options);
485 }
486449
487 /// Serialize a value, similar to `serializeArbitraryDepth`.450 /// Serialize a value, similar to `serialize`.
488 pub fn valueArbitraryDepth(451 pub fn value(self: *Serializer, val: anytype, options: ValueOptions) Error!void {
489 self: *Self,452 comptime assert(!typeIsRecursive(@TypeOf(val)));
490 val: anytype,453 return self.valueArbitraryDepth(val, options);
491 options: ValueOptions,454 }
492 ) Writer.Error!void {
493 comptime assert(canSerializeType(@TypeOf(val)));
494 switch (@typeInfo(@TypeOf(val))) {
495 .int, .comptime_int => if (options.emit_codepoint_literals.emitAsCodepoint(val)) |c| {
496 self.codePoint(c) catch |err| switch (err) {
497 error.InvalidCodepoint => unreachable, // Already validated
498 else => |e| return e,
499 };
500 } else {
501 try self.int(val);
502 },
503 .float, .comptime_float => try self.float(val),
504 .bool, .null => try std.fmt.format(self.writer, "{}", .{val}),
505 .enum_literal => try self.ident(@tagName(val)),
506 .@"enum" => try self.ident(@tagName(val)),
507 .pointer => |pointer| {
508 // Try to serialize as a string
509 const item: ?type = switch (@typeInfo(pointer.child)) {
510 .array => |array| array.child,
511 else => if (pointer.size == .slice) pointer.child else null,
512 };
513 if (item == u8 and
514 (pointer.sentinel() == null or pointer.sentinel() == 0) and
515 !options.emit_strings_as_containers)
516 {
517 return try self.string(val);
518 }
519455
520 // Serialize as either a tuple or as the child type456 /// Serialize a value, similar to `serializeMaxDepth`.
521 switch (pointer.size) {457 /// Can return `error.ExceededMaxDepth`.
522 .slice => try self.tupleImpl(val, options),458 pub fn valueMaxDepth(self: *Serializer, val: anytype, options: ValueOptions, depth: usize) DepthError!void {
523 .one => try self.valueArbitraryDepth(val.*, options),459 try checkValueDepth(val, depth);
524 else => comptime unreachable,460 return self.valueArbitraryDepth(val, options);
525 }461 }
526 },462
527 .array => {463 /// Serialize a value, similar to `serializeArbitraryDepth`.
528 var container = try self.beginTuple(464 pub fn valueArbitraryDepth(self: *Serializer, val: anytype, options: ValueOptions) Error!void {
529 .{ .whitespace_style = .{ .fields = val.len } },465 comptime assert(canSerializeType(@TypeOf(val)));
530 );466 switch (@typeInfo(@TypeOf(val))) {
531 for (val) |item_val| {467 .int, .comptime_int => if (options.emit_codepoint_literals.emitAsCodepoint(val)) |c| {
532 try container.fieldArbitraryDepth(item_val, options);468 self.codePoint(c) catch |err| switch (err) {
533 }469 error.InvalidCodepoint => unreachable, // Already validated
534 try container.end();470 else => |e| return e,
535 },471 };
536 .@"struct" => |@"struct"| if (@"struct".is_tuple) {472 } else {
537 var container = try self.beginTuple(473 try self.int(val);
538 .{ .whitespace_style = .{ .fields = @"struct".fields.len } },474 },
539 );475 .float, .comptime_float => try self.float(val),
540 inline for (val) |field_value| {476 .bool, .null => try self.writer.print("{}", .{val}),
541 try container.fieldArbitraryDepth(field_value, options);477 .enum_literal => try self.ident(@tagName(val)),
542 }478 .@"enum" => try self.ident(@tagName(val)),
543 try container.end();479 .pointer => |pointer| {
544 } else {480 // Try to serialize as a string
545 // Decide which fields to emit481 const item: ?type = switch (@typeInfo(pointer.child)) {
546 const fields, const skipped: [@"struct".fields.len]bool = if (options.emit_default_optional_fields) b: {482 .array => |array| array.child,
547 break :b .{ @"struct".fields.len, @splat(false) };483 else => if (pointer.size == .slice) pointer.child else null,
548 } else b: {484 };
549 var fields = @"struct".fields.len;485 if (item == u8 and
550 var skipped: [@"struct".fields.len]bool = @splat(false);486 (pointer.sentinel() == null or pointer.sentinel() == 0) and
551 inline for (@"struct".fields, &skipped) |field_info, *skip| {487 !options.emit_strings_as_containers)
552 if (field_info.default_value_ptr) |ptr| {488 {
553 const default: *const field_info.type = @ptrCast(@alignCast(ptr));489 return try self.string(val);
554 const field_value = @field(val, field_info.name);490 }
555 if (std.meta.eql(field_value, default.*)) {491
556 skip.* = true;492 // Serialize as either a tuple or as the child type
557 fields -= 1;493 switch (pointer.size) {
558 }494 .slice => try self.tupleImpl(val, options),
495 .one => try self.valueArbitraryDepth(val.*, options),
496 else => comptime unreachable,
497 }
498 },
499 .array => {
500 var container = try self.beginTuple(
501 .{ .whitespace_style = .{ .fields = val.len } },
502 );
503 for (val) |item_val| {
504 try container.fieldArbitraryDepth(item_val, options);
505 }
506 try container.end();
507 },
508 .@"struct" => |@"struct"| if (@"struct".is_tuple) {
509 var container = try self.beginTuple(
510 .{ .whitespace_style = .{ .fields = @"struct".fields.len } },
511 );
512 inline for (val) |field_value| {
513 try container.fieldArbitraryDepth(field_value, options);
514 }
515 try container.end();
516 } else {
517 // Decide which fields to emit
518 const fields, const skipped: [@"struct".fields.len]bool = if (options.emit_default_optional_fields) b: {
519 break :b .{ @"struct".fields.len, @splat(false) };
520 } else b: {
521 var fields = @"struct".fields.len;
522 var skipped: [@"struct".fields.len]bool = @splat(false);
523 inline for (@"struct".fields, &skipped) |field_info, *skip| {
524 if (field_info.default_value_ptr) |ptr| {
525 const default: *const field_info.type = @ptrCast(@alignCast(ptr));
526 const field_value = @field(val, field_info.name);
527 if (std.meta.eql(field_value, default.*)) {
528 skip.* = true;
529 fields -= 1;
559 }530 }
560 }531 }
561 break :b .{ fields, skipped };
562 };
563
564 // Emit those fields
565 var container = try self.beginStruct(
566 .{ .whitespace_style = .{ .fields = fields } },
567 );
568 inline for (@"struct".fields, skipped) |field_info, skip| {
569 if (!skip) {
570 try container.fieldArbitraryDepth(
571 field_info.name,
572 @field(val, field_info.name),
573 options,
574 );
575 }
576 }
577 try container.end();
578 },
579 .@"union" => |@"union"| {
580 comptime assert(@"union".tag_type != null);
581 switch (val) {
582 inline else => |pl, tag| if (@TypeOf(pl) == void)
583 try self.writer.print(".{s}", .{@tagName(tag)})
584 else {
585 var container = try self.beginStruct(.{ .whitespace_style = .{ .fields = 1 } });
586
587 try container.fieldArbitraryDepth(
588 @tagName(tag),
589 pl,
590 options,
591 );
592
593 try container.end();
594 },
595 }532 }
596 },533 break :b .{ fields, skipped };
597 .optional => if (val) |inner| {534 };
598 try self.valueArbitraryDepth(inner, options);535
599 } else {536 // Emit those fields
600 try self.writer.writeAll("null");537 var container = try self.beginStruct(
601 },538 .{ .whitespace_style = .{ .fields = fields } },
602 .vector => |vector| {539 );
603 var container = try self.beginTuple(540 inline for (@"struct".fields, skipped) |field_info, skip| {
604 .{ .whitespace_style = .{ .fields = vector.len } },541 if (!skip) {
605 );542 try container.fieldArbitraryDepth(
606 for (0..vector.len) |i| {543 field_info.name,
607 try container.fieldArbitraryDepth(val[i], options);544 @field(val, field_info.name),
545 options,
546 );
608 }547 }
609 try container.end();548 }
610 },549 try container.end();
550 },
551 .@"union" => |@"union"| {
552 comptime assert(@"union".tag_type != null);
553 switch (val) {
554 inline else => |pl, tag| if (@TypeOf(pl) == void)
555 try self.writer.print(".{s}", .{@tagName(tag)})
556 else {
557 var container = try self.beginStruct(.{ .whitespace_style = .{ .fields = 1 } });
558
559 try container.fieldArbitraryDepth(
560 @tagName(tag),
561 pl,
562 options,
563 );
564
565 try container.end();
566 },
567 }
568 },
569 .optional => if (val) |inner| {
570 try self.valueArbitraryDepth(inner, options);
571 } else {
572 try self.writer.writeAll("null");
573 },
574 .vector => |vector| {
575 var container = try self.beginTuple(
576 .{ .whitespace_style = .{ .fields = vector.len } },
577 );
578 for (0..vector.len) |i| {
579 try container.fieldArbitraryDepth(val[i], options);
580 }
581 try container.end();
582 },
611583
612 else => comptime unreachable,584 else => comptime unreachable,
613 }
614 }585 }
586 }
615587
616 /// Serialize an integer.588 /// Serialize an integer.
617 pub fn int(self: *Self, val: anytype) Writer.Error!void {589 pub fn int(self: *Serializer, val: anytype) Error!void {
618 //try self.writer.printInt(val, 10, .lower, .{});590 try self.writer.printInt(val, 10, .lower, .{});
619 try std.fmt.format(self.writer, "{d}", .{val});591 }
620 }
621
622 /// Serialize a float.
623 pub fn float(self: *Self, val: anytype) Writer.Error!void {
624 switch (@typeInfo(@TypeOf(val))) {
625 .float => if (std.math.isNan(val)) {
626 return self.writer.writeAll("nan");
627 } else if (std.math.isPositiveInf(val)) {
628 return self.writer.writeAll("inf");
629 } else if (std.math.isNegativeInf(val)) {
630 return self.writer.writeAll("-inf");
631 } else if (std.math.isNegativeZero(val)) {
632 return self.writer.writeAll("-0.0");
633 } else {
634 try std.fmt.format(self.writer, "{d}", .{val});
635 },
636 .comptime_float => if (val == 0) {
637 return self.writer.writeAll("0");
638 } else {
639 try std.fmt.format(self.writer, "{d}", .{val});
640 },
641 else => comptime unreachable,
642 }
643 }
644592
645 /// Serialize `name` as an identifier prefixed with `.`.593 /// Serialize a float.
646 ///594 pub fn float(self: *Serializer, val: anytype) Error!void {
647 /// Escapes the identifier if necessary.595 switch (@typeInfo(@TypeOf(val))) {
648 pub fn ident(self: *Self, name: []const u8) Writer.Error!void {596 .float => if (std.math.isNan(val)) {
649 try self.writer.print(".{f}", .{std.zig.fmtIdPU(name)});597 return self.writer.writeAll("nan");
598 } else if (std.math.isPositiveInf(val)) {
599 return self.writer.writeAll("inf");
600 } else if (std.math.isNegativeInf(val)) {
601 return self.writer.writeAll("-inf");
602 } else if (std.math.isNegativeZero(val)) {
603 return self.writer.writeAll("-0.0");
604 } else {
605 try self.writer.print("{d}", .{val});
606 },
607 .comptime_float => if (val == 0) {
608 return self.writer.writeAll("0");
609 } else {
610 try self.writer.print("{d}", .{val});
611 },
612 else => comptime unreachable,
650 }613 }
614 }
651615
652 /// Serialize `val` as a Unicode codepoint.616 /// Serialize `name` as an identifier prefixed with `.`.
653 ///617 ///
654 /// Returns `error.InvalidCodepoint` if `val` is not a valid Unicode codepoint.618 /// Escapes the identifier if necessary.
655 pub fn codePoint(619 pub fn ident(self: *Serializer, name: []const u8) Error!void {
656 self: *Self,620 try self.writer.print(".{f}", .{std.zig.fmtIdPU(name)});
657 val: u21,621 }
658 ) (Writer.Error || error{InvalidCodepoint})!void {
659 var buf: [8]u8 = undefined;
660 const len = std.unicode.utf8Encode(val, &buf) catch return error.InvalidCodepoint;
661 const str = buf[0..len];
662 try std.fmt.format(self.writer, "'{f}'", .{std.zig.fmtChar(str)});
663 }
664
665 /// Like `value`, but always serializes `val` as a tuple.
666 ///
667 /// Will fail at comptime if `val` is not a tuple, array, pointer to an array, or slice.
668 pub fn tuple(self: *Self, val: anytype, options: ValueOptions) Writer.Error!void {
669 comptime assert(!typeIsRecursive(@TypeOf(val)));
670 try self.tupleArbitraryDepth(val, options);
671 }
672622
673 /// Like `tuple`, but recursive types are allowed.623 pub const CodePointError = Error || error{InvalidCodepoint};
674 ///
675 /// Returns `error.ExceededMaxDepth` if `depth` is exceeded.
676 pub fn tupleMaxDepth(
677 self: *Self,
678 val: anytype,
679 options: ValueOptions,
680 depth: usize,
681 ) (Writer.Error || error{ExceededMaxDepth})!void {
682 try checkValueDepth(val, depth);
683 try self.tupleArbitraryDepth(val, options);
684 }
685624
686 /// Like `tuple`, but recursive types are allowed.625 /// Serialize `val` as a Unicode codepoint.
687 ///626 ///
688 /// It is the caller's responsibility to ensure that `val` does not contain cycles.627 /// Returns `error.InvalidCodepoint` if `val` is not a valid Unicode codepoint.
689 pub fn tupleArbitraryDepth(628 pub fn codePoint(self: *Serializer, val: u21) CodePointError!void {
690 self: *Self,629 try self.writer.print("'{f}'", .{std.zig.fmtChar(val)});
691 val: anytype,630 }
692 options: ValueOptions,
693 ) Writer.Error!void {
694 try self.tupleImpl(val, options);
695 }
696631
697 fn tupleImpl(self: *Self, val: anytype, options: ValueOptions) Writer.Error!void {632 /// Like `value`, but always serializes `val` as a tuple.
698 comptime assert(canSerializeType(@TypeOf(val)));633 ///
699 switch (@typeInfo(@TypeOf(val))) {634 /// Will fail at comptime if `val` is not a tuple, array, pointer to an array, or slice.
700 .@"struct" => {635 pub fn tuple(self: *Serializer, val: anytype, options: ValueOptions) Error!void {
701 var container = try self.beginTuple(.{ .whitespace_style = .{ .fields = val.len } });636 comptime assert(!typeIsRecursive(@TypeOf(val)));
702 inline for (val) |item_val| {637 try self.tupleArbitraryDepth(val, options);
703 try container.fieldArbitraryDepth(item_val, options);638 }
704 }
705 try container.end();
706 },
707 .pointer, .array => {
708 var container = try self.beginTuple(.{ .whitespace_style = .{ .fields = val.len } });
709 for (val) |item_val| {
710 try container.fieldArbitraryDepth(item_val, options);
711 }
712 try container.end();
713 },
714 else => comptime unreachable,
715 }
716 }
717639
718 /// Like `value`, but always serializes `val` as a string.640 /// Like `tuple`, but recursive types are allowed.
719 pub fn string(self: *Self, val: []const u8) Writer.Error!void {641 ///
720 try std.fmt.format(self.writer, "\"{f}\"", .{std.zig.fmtString(val)});642 /// Returns `error.ExceededMaxDepth` if `depth` is exceeded.
721 }643 pub fn tupleMaxDepth(
644 self: *Serializer,
645 val: anytype,
646 options: ValueOptions,
647 depth: usize,
648 ) DepthError!void {
649 try checkValueDepth(val, depth);
650 try self.tupleArbitraryDepth(val, options);
651 }
722652
723 /// Options for formatting multiline strings.653 /// Like `tuple`, but recursive types are allowed.
724 pub const MultilineStringOptions = struct {654 ///
725 /// If top level is true, whitespace before and after the multiline string is elided.655 /// It is the caller's responsibility to ensure that `val` does not contain cycles.
726 /// If it is true, a newline is printed, then the value, followed by a newline, and if656 pub fn tupleArbitraryDepth(
727 /// whitespace is true any necessary indentation follows.657 self: *Serializer,
728 top_level: bool = false,658 val: anytype,
729 };659 options: ValueOptions,
660 ) Error!void {
661 try self.tupleImpl(val, options);
662 }
730663
731 /// Like `value`, but always serializes to a multiline string literal.664 fn tupleImpl(self: *Serializer, val: anytype, options: ValueOptions) Error!void {
732 ///665 comptime assert(canSerializeType(@TypeOf(val)));
733 /// Returns `error.InnerCarriageReturn` if `val` contains a CR not followed by a newline,666 switch (@typeInfo(@TypeOf(val))) {
734 /// since multiline strings cannot represent CR without a following newline.667 .@"struct" => {
735 pub fn multilineString(668 var container = try self.beginTuple(.{ .whitespace_style = .{ .fields = val.len } });
736 self: *Self,669 inline for (val) |item_val| {
737 val: []const u8,670 try container.fieldArbitraryDepth(item_val, options);
738 options: MultilineStringOptions,
739 ) (Writer.Error || error{InnerCarriageReturn})!void {
740 // Make sure the string does not contain any carriage returns not followed by a newline
741 var i: usize = 0;
742 while (i < val.len) : (i += 1) {
743 if (val[i] == '\r') {
744 if (i + 1 < val.len) {
745 if (val[i + 1] == '\n') {
746 i += 1;
747 continue;
748 }
749 }
750 return error.InnerCarriageReturn;
751 }671 }
752 }672 try container.end();
673 },
674 .pointer, .array => {
675 var container = try self.beginTuple(.{ .whitespace_style = .{ .fields = val.len } });
676 for (val) |item_val| {
677 try container.fieldArbitraryDepth(item_val, options);
678 }
679 try container.end();
680 },
681 else => comptime unreachable,
682 }
683 }
753684
754 if (!options.top_level) {685 /// Like `value`, but always serializes `val` as a string.
755 try self.newline();686 pub fn string(self: *Serializer, val: []const u8) Error!void {
756 try self.indent();687 try self.writer.print("\"{f}\"", .{std.zig.fmtString(val)});
757 }688 }
689
690 /// Options for formatting multiline strings.
691 pub const MultilineStringOptions = struct {
692 /// If top level is true, whitespace before and after the multiline string is elided.
693 /// If it is true, a newline is printed, then the value, followed by a newline, and if
694 /// whitespace is true any necessary indentation follows.
695 top_level: bool = false,
696 };
758697
759 try self.writer.writeAll("\\\\");698 pub const MultilineStringError = Error || error{InnerCarriageReturn};
760 for (val) |c| {699
761 if (c != '\r') {700 /// Like `value`, but always serializes to a multiline string literal.
762 try self.writer.writeByte(c); // We write newlines here even if whitespace off701 ///
763 if (c == '\n') {702 /// Returns `error.InnerCarriageReturn` if `val` contains a CR not followed by a newline,
764 try self.indent();703 /// since multiline strings cannot represent CR without a following newline.
765 try self.writer.writeAll("\\\\");704 pub fn multilineString(
705 self: *Serializer,
706 val: []const u8,
707 options: MultilineStringOptions,
708 ) MultilineStringError!void {
709 // Make sure the string does not contain any carriage returns not followed by a newline
710 var i: usize = 0;
711 while (i < val.len) : (i += 1) {
712 if (val[i] == '\r') {
713 if (i + 1 < val.len) {
714 if (val[i + 1] == '\n') {
715 i += 1;
716 continue;
766 }717 }
767 }718 }
719 return error.InnerCarriageReturn;
768 }720 }
721 }
769722
770 if (!options.top_level) {723 if (!options.top_level) {
771 try self.writer.writeByte('\n'); // Even if whitespace off724 try self.newline();
772 try self.indent();725 try self.indent();
773 }
774 }726 }
775727
776 /// Create a `Struct` for writing ZON structs field by field.728 try self.writer.writeAll("\\\\");
777 pub fn beginStruct(729 for (val) |c| {
778 self: *Self,730 if (c != '\r') {
779 options: SerializeContainerOptions,731 try self.writer.writeByte(c); // We write newlines here even if whitespace off
780 ) Writer.Error!Struct {732 if (c == '\n') {
781 return Struct.begin(self, options);733 try self.indent();
734 try self.writer.writeAll("\\\\");
735 }
736 }
782 }737 }
783738
784 /// Creates a `Tuple` for writing ZON tuples field by field.739 if (!options.top_level) {
785 pub fn beginTuple(740 try self.writer.writeByte('\n'); // Even if whitespace off
786 self: *Self,741 try self.indent();
787 options: SerializeContainerOptions,
788 ) Writer.Error!Tuple {
789 return Tuple.begin(self, options);
790 }742 }
743 }
791744
792 fn indent(self: *Self) Writer.Error!void {745 /// Create a `Struct` for writing ZON structs field by field.
793 if (self.options.whitespace) {746 pub fn beginStruct(
794 try self.writer.writeByteNTimes(' ', 4 * self.indent_level);747 self: *Serializer,
795 }748 options: SerializeContainerOptions,
749 ) Error!Struct {
750 return Struct.begin(self, options);
751 }
752
753 /// Creates a `Tuple` for writing ZON tuples field by field.
754 pub fn beginTuple(
755 self: *Serializer,
756 options: SerializeContainerOptions,
757 ) Error!Tuple {
758 return Tuple.begin(self, options);
759 }
760
761 fn indent(self: *Serializer) Error!void {
762 if (self.options.whitespace) {
763 try self.writer.splatByteAll(' ', 4 * self.indent_level);
796 }764 }
765 }
797766
798 fn newline(self: *Self) Writer.Error!void {767 fn newline(self: *Serializer) Error!void {
799 if (self.options.whitespace) {768 if (self.options.whitespace) {
800 try self.writer.writeByte('\n');769 try self.writer.writeByte('\n');
801 }
802 }770 }
771 }
803772
804 fn newlineOrSpace(self: *Self, len: usize) Writer.Error!void {773 fn newlineOrSpace(self: *Serializer, len: usize) Error!void {
805 if (self.containerShouldWrap(len)) {774 if (self.containerShouldWrap(len)) {
806 try self.newline();775 try self.newline();
807 } else {776 } else {
808 try self.space();777 try self.space();
809 }
810 }778 }
779 }
811780
812 fn space(self: *Self) Writer.Error!void {781 fn space(self: *Serializer) Error!void {
813 if (self.options.whitespace) {782 if (self.options.whitespace) {
814 try self.writer.writeByte(' ');783 try self.writer.writeByte(' ');
815 }
816 }784 }
785 }
817786
818 /// Writes ZON tuples field by field.787 /// Writes ZON tuples field by field.
819 pub const Tuple = struct {788 pub const Tuple = struct {
820 container: Container,789 container: Container,
821790
822 fn begin(parent: *Self, options: SerializeContainerOptions) Writer.Error!Tuple {791 fn begin(parent: *Serializer, options: SerializeContainerOptions) Error!Tuple {
823 return .{792 return .{
824 .container = try Container.begin(parent, .anon, options),793 .container = try Container.begin(parent, .anon, options),
825 };794 };
826 }795 }
827796
828 /// Finishes serializing the tuple.797 /// Finishes serializing the tuple.
829 ///798 ///
830 /// Prints a trailing comma as configured when appropriate, and the closing bracket.799 /// Prints a trailing comma as configured when appropriate, and the closing bracket.
831 pub fn end(self: *Tuple) Writer.Error!void {800 pub fn end(self: *Tuple) Error!void {
832 try self.container.end();801 try self.container.end();
833 self.* = undefined;802 self.* = undefined;
834 }803 }
835804
836 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `value`.805 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `value`.
837 pub fn field(806 pub fn field(
838 self: *Tuple,807 self: *Tuple,
839 val: anytype,808 val: anytype,
840 options: ValueOptions,809 options: ValueOptions,
841 ) Writer.Error!void {810 ) Error!void {
842 try self.container.field(null, val, options);811 try self.container.field(null, val, options);
843 }812 }
844813
845 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `valueMaxDepth`.814 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `valueMaxDepth`.
846 pub fn fieldMaxDepth(815 /// Returns `error.ExceededMaxDepth` if `depth` is exceeded.
847 self: *Tuple,816 pub fn fieldMaxDepth(
848 val: anytype,817 self: *Tuple,
849 options: ValueOptions,818 val: anytype,
850 depth: usize,819 options: ValueOptions,
851 ) (Writer.Error || error{ExceededMaxDepth})!void {820 depth: usize,
852 try self.container.fieldMaxDepth(null, val, options, depth);821 ) DepthError!void {
853 }822 try self.container.fieldMaxDepth(null, val, options, depth);
823 }
854824
855 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by825 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by
856 /// `valueArbitraryDepth`.826 /// `valueArbitraryDepth`.
857 pub fn fieldArbitraryDepth(827 pub fn fieldArbitraryDepth(
858 self: *Tuple,828 self: *Tuple,
859 val: anytype,829 val: anytype,
860 options: ValueOptions,830 options: ValueOptions,
861 ) Writer.Error!void {831 ) Error!void {
862 try self.container.fieldArbitraryDepth(null, val, options);832 try self.container.fieldArbitraryDepth(null, val, options);
863 }833 }
864834
865 /// Starts a field with a struct as a value. Returns the struct.835 /// Starts a field with a struct as a value. Returns the struct.
866 pub fn beginStructField(836 pub fn beginStructField(
867 self: *Tuple,837 self: *Tuple,
868 options: SerializeContainerOptions,838 options: SerializeContainerOptions,
869 ) Writer.Error!Struct {839 ) Error!Struct {
870 try self.fieldPrefix();840 try self.fieldPrefix();
871 return self.container.serializer.beginStruct(options);841 return self.container.serializer.beginStruct(options);
872 }842 }
873843
874 /// Starts a field with a tuple as a value. Returns the tuple.844 /// Starts a field with a tuple as a value. Returns the tuple.
875 pub fn beginTupleField(845 pub fn beginTupleField(
876 self: *Tuple,846 self: *Tuple,
877 options: SerializeContainerOptions,847 options: SerializeContainerOptions,
878 ) Writer.Error!Tuple {848 ) Error!Tuple {
879 try self.fieldPrefix();849 try self.fieldPrefix();
880 return self.container.serializer.beginTuple(options);850 return self.container.serializer.beginTuple(options);
881 }851 }
882852
883 /// Print a field prefix. This prints any necessary commas, and whitespace as853 /// Print a field prefix. This prints any necessary commas, and whitespace as
884 /// configured. Useful if you want to serialize the field value yourself.854 /// configured. Useful if you want to serialize the field value yourself.
885 pub fn fieldPrefix(self: *Tuple) Writer.Error!void {855 pub fn fieldPrefix(self: *Tuple) Error!void {
886 try self.container.fieldPrefix(null);856 try self.container.fieldPrefix(null);
887 }857 }
888 };858 };
889859
890 /// Writes ZON structs field by field.860 /// Writes ZON structs field by field.
891 pub const Struct = struct {861 pub const Struct = struct {
892 container: Container,862 container: Container,
893863
894 fn begin(parent: *Self, options: SerializeContainerOptions) Writer.Error!Struct {864 fn begin(parent: *Serializer, options: SerializeContainerOptions) Error!Struct {
895 return .{865 return .{
896 .container = try Container.begin(parent, .named, options),866 .container = try Container.begin(parent, .named, options),
897 };867 };
898 }868 }
899869
900 /// Finishes serializing the struct.870 /// Finishes serializing the struct.
901 ///871 ///
902 /// Prints a trailing comma as configured when appropriate, and the closing bracket.872 /// Prints a trailing comma as configured when appropriate, and the closing bracket.
903 pub fn end(self: *Struct) Writer.Error!void {873 pub fn end(self: *Struct) Error!void {
904 try self.container.end();874 try self.container.end();
905 self.* = undefined;875 self.* = undefined;
906 }876 }
907877
908 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `value`.878 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `value`.
909 pub fn field(879 pub fn field(
910 self: *Struct,880 self: *Struct,
911 name: []const u8,881 name: []const u8,
912 val: anytype,882 val: anytype,
913 options: ValueOptions,883 options: ValueOptions,
914 ) Writer.Error!void {884 ) Error!void {
915 try self.container.field(name, val, options);885 try self.container.field(name, val, options);
916 }886 }
917887
918 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `valueMaxDepth`.888 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `valueMaxDepth`.
919 pub fn fieldMaxDepth(889 /// Returns `error.ExceededMaxDepth` if `depth` is exceeded.
920 self: *Struct,890 pub fn fieldMaxDepth(
921 name: []const u8,891 self: *Struct,
922 val: anytype,892 name: []const u8,
923 options: ValueOptions,893 val: anytype,
924 depth: usize,894 options: ValueOptions,
925 ) (Writer.Error || error{ExceededMaxDepth})!void {895 depth: usize,
926 try self.container.fieldMaxDepth(name, val, options, depth);896 ) DepthError!void {
927 }897 try self.container.fieldMaxDepth(name, val, options, depth);
898 }
928899
929 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by900 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by
930 /// `valueArbitraryDepth`.901 /// `valueArbitraryDepth`.
931 pub fn fieldArbitraryDepth(902 pub fn fieldArbitraryDepth(
932 self: *Struct,903 self: *Struct,
933 name: []const u8,904 name: []const u8,
934 val: anytype,905 val: anytype,
935 options: ValueOptions,906 options: ValueOptions,
936 ) Writer.Error!void {907 ) Error!void {
937 try self.container.fieldArbitraryDepth(name, val, options);908 try self.container.fieldArbitraryDepth(name, val, options);
938 }909 }
939910
940 /// Starts a field with a struct as a value. Returns the struct.911 /// Starts a field with a struct as a value. Returns the struct.
941 pub fn beginStructField(912 pub fn beginStructField(
942 self: *Struct,913 self: *Struct,
943 name: []const u8,914 name: []const u8,
944 options: SerializeContainerOptions,915 options: SerializeContainerOptions,
945 ) Writer.Error!Struct {916 ) Error!Struct {
946 try self.fieldPrefix(name);917 try self.fieldPrefix(name);
947 return self.container.serializer.beginStruct(options);918 return self.container.serializer.beginStruct(options);
948 }919 }
949920
950 /// Starts a field with a tuple as a value. Returns the tuple.921 /// Starts a field with a tuple as a value. Returns the tuple.
951 pub fn beginTupleField(922 pub fn beginTupleField(
952 self: *Struct,923 self: *Struct,
953 name: []const u8,924 name: []const u8,
954 options: SerializeContainerOptions,925 options: SerializeContainerOptions,
955 ) Writer.Error!Tuple {926 ) Error!Tuple {
956 try self.fieldPrefix(name);927 try self.fieldPrefix(name);
957 return self.container.serializer.beginTuple(options);928 return self.container.serializer.beginTuple(options);
958 }929 }
959930
960 /// Print a field prefix. This prints any necessary commas, the field name (escaped if931 /// Print a field prefix. This prints any necessary commas, the field name (escaped if
961 /// necessary) and whitespace as configured. Useful if you want to serialize the field932 /// necessary) and whitespace as configured. Useful if you want to serialize the field
962 /// value yourself.933 /// value yourself.
963 pub fn fieldPrefix(self: *Struct, name: []const u8) Writer.Error!void {934 pub fn fieldPrefix(self: *Struct, name: []const u8) Error!void {
964 try self.container.fieldPrefix(name);935 try self.container.fieldPrefix(name);
965 }936 }
966 };937 };
967938
968 const Container = struct {939 const Container = struct {
969 const FieldStyle = enum { named, anon };940 const FieldStyle = enum { named, anon };
970941
971 serializer: *Self,942 serializer: *Serializer,
943 field_style: FieldStyle,
944 options: SerializeContainerOptions,
945 empty: bool,
946
947 fn begin(
948 sz: *Serializer,
972 field_style: FieldStyle,949 field_style: FieldStyle,
973 options: SerializeContainerOptions,950 options: SerializeContainerOptions,
974 empty: bool,951 ) Error!Container {
975952 if (options.shouldWrap()) sz.indent_level +|= 1;
976 fn begin(953 try sz.writer.writeAll(".{");
977 sz: *Self,954 return .{
978 field_style: FieldStyle,955 .serializer = sz,
979 options: SerializeContainerOptions,956 .field_style = field_style,
980 ) Writer.Error!Container {957 .options = options,
981 if (options.shouldWrap()) sz.indent_level +|= 1;958 .empty = true,
982 try sz.writer.writeAll(".{");959 };
983 return .{960 }
984 .serializer = sz,
985 .field_style = field_style,
986 .options = options,
987 .empty = true,
988 };
989 }
990
991 fn end(self: *Container) Writer.Error!void {
992 if (self.options.shouldWrap()) self.serializer.indent_level -|= 1;
993 if (!self.empty) {
994 if (self.options.shouldWrap()) {
995 if (self.serializer.options.whitespace) {
996 try self.serializer.writer.writeByte(',');
997 }
998 try self.serializer.newline();
999 try self.serializer.indent();
1000 } else if (!self.shouldElideSpaces()) {
1001 try self.serializer.space();
1002 }
1003 }
1004 try self.serializer.writer.writeByte('}');
1005 self.* = undefined;
1006 }
1007961
1008 fn fieldPrefix(self: *Container, name: ?[]const u8) Writer.Error!void {962 fn end(self: *Container) Error!void {
1009 if (!self.empty) {963 if (self.options.shouldWrap()) self.serializer.indent_level -|= 1;
1010 try self.serializer.writer.writeByte(',');964 if (!self.empty) {
1011 }
1012 self.empty = false;
1013 if (self.options.shouldWrap()) {965 if (self.options.shouldWrap()) {
966 if (self.serializer.options.whitespace) {
967 try self.serializer.writer.writeByte(',');
968 }
1014 try self.serializer.newline();969 try self.serializer.newline();
970 try self.serializer.indent();
1015 } else if (!self.shouldElideSpaces()) {971 } else if (!self.shouldElideSpaces()) {
1016 try self.serializer.space();972 try self.serializer.space();
1017 }973 }
1018 if (self.options.shouldWrap()) try self.serializer.indent();
1019 if (name) |n| {
1020 try self.serializer.ident(n);
1021 try self.serializer.space();
1022 try self.serializer.writer.writeByte('=');
1023 try self.serializer.space();
1024 }
1025 }974 }
975 try self.serializer.writer.writeByte('}');
976 self.* = undefined;
977 }
1026978
1027 fn field(979 fn fieldPrefix(self: *Container, name: ?[]const u8) Error!void {
1028 self: *Container,980 if (!self.empty) {
1029 name: ?[]const u8,981 try self.serializer.writer.writeByte(',');
1030 val: anytype,
1031 options: ValueOptions,
1032 ) Writer.Error!void {
1033 comptime assert(!typeIsRecursive(@TypeOf(val)));
1034 try self.fieldArbitraryDepth(name, val, options);
1035 }982 }
1036983 self.empty = false;
1037 fn fieldMaxDepth(984 if (self.options.shouldWrap()) {
1038 self: *Container,985 try self.serializer.newline();
1039 name: ?[]const u8,986 } else if (!self.shouldElideSpaces()) {
1040 val: anytype,987 try self.serializer.space();
1041 options: ValueOptions,
1042 depth: usize,
1043 ) (Writer.Error || error{ExceededMaxDepth})!void {
1044 try checkValueDepth(val, depth);
1045 try self.fieldArbitraryDepth(name, val, options);
1046 }988 }
1047989 if (self.options.shouldWrap()) try self.serializer.indent();
1048 fn fieldArbitraryDepth(990 if (name) |n| {
1049 self: *Container,991 try self.serializer.ident(n);
1050 name: ?[]const u8,992 try self.serializer.space();
1051 val: anytype,993 try self.serializer.writer.writeByte('=');
1052 options: ValueOptions,994 try self.serializer.space();
1053 ) Writer.Error!void {
1054 try self.fieldPrefix(name);
1055 try self.serializer.valueArbitraryDepth(val, options);
1056 }995 }
996 }
1057997
1058 fn shouldElideSpaces(self: *const Container) bool {998 fn field(
1059 return switch (self.options.whitespace_style) {999 self: *Container,
1060 .fields => |fields| self.field_style != .named and fields == 1,1000 name: ?[]const u8,
1061 else => false,1001 val: anytype,
1062 };1002 options: ValueOptions,
1063 }1003 ) Error!void {
1064 };1004 comptime assert(!typeIsRecursive(@TypeOf(val)));
1005 try self.fieldArbitraryDepth(name, val, options);
1006 }
1007
1008 /// Returns `error.ExceededMaxDepth` if `depth` is exceeded.
1009 fn fieldMaxDepth(
1010 self: *Container,
1011 name: ?[]const u8,
1012 val: anytype,
1013 options: ValueOptions,
1014 depth: usize,
1015 ) DepthError!void {
1016 try checkValueDepth(val, depth);
1017 try self.fieldArbitraryDepth(name, val, options);
1018 }
1019
1020 fn fieldArbitraryDepth(
1021 self: *Container,
1022 name: ?[]const u8,
1023 val: anytype,
1024 options: ValueOptions,
1025 ) Error!void {
1026 try self.fieldPrefix(name);
1027 try self.serializer.valueArbitraryDepth(val, options);
1028 }
1029
1030 fn shouldElideSpaces(self: *const Container) bool {
1031 return switch (self.options.whitespace_style) {
1032 .fields => |fields| self.field_style != .named and fields == 1,
1033 else => false,
1034 };
1035 }
1065 };1036 };
1066}1037};
10671038
1068/// Creates a new `Serializer` with the given writer and options.1039test Serializer {
1069pub fn serializer(writer: anytype, options: SerializerOptions) Serializer(@TypeOf(writer)) {1040 var discarding: Writer.Discarding = .init(&.{});
1070 return .init(writer, options);1041 var s: Serializer = .{ .writer = &discarding.writer };
1042 var vec2 = try s.beginStruct(.{});
1043 try vec2.field("x", 1.5, .{});
1044 try vec2.fieldPrefix("prefix");
1045 try s.value(2.5, .{});
1046 try vec2.end();
1071}1047}
10721048
1073fn expectSerializeEqual(1049fn expectSerializeEqual(
...@@ -1075,10 +1051,12 @@ fn expectSerializeEqual(...@@ -1075,10 +1051,12 @@ fn expectSerializeEqual(
1075 value: anytype,1051 value: anytype,
1076 options: SerializeOptions,1052 options: SerializeOptions,
1077) !void {1053) !void {
1078 var buf = std.ArrayList(u8).init(std.testing.allocator);1054 var aw: Writer.Allocating = .init(std.testing.allocator);
1079 defer buf.deinit();1055 const bw = &aw.writer;
1080 try serialize(value, options, buf.writer());1056 defer aw.deinit();
1081 try std.testing.expectEqualStrings(expected, buf.items);1057
1058 try serialize(value, options, bw);
1059 try std.testing.expectEqualStrings(expected, aw.getWritten());
1082}1060}
10831061
1084test "std.zon stringify whitespace, high level API" {1062test "std.zon stringify whitespace, high level API" {
...@@ -1175,59 +1153,59 @@ test "std.zon stringify whitespace, high level API" {...@@ -1175,59 +1153,59 @@ test "std.zon stringify whitespace, high level API" {
1175}1153}
11761154
1177test "std.zon stringify whitespace, low level API" {1155test "std.zon stringify whitespace, low level API" {
1178 var buf = std.ArrayList(u8).init(std.testing.allocator);1156 var aw: Writer.Allocating = .init(std.testing.allocator);
1179 defer buf.deinit();1157 var s: Serializer = .{ .writer = &aw.writer };
1180 var sz = serializer(buf.writer(), .{});1158 defer aw.deinit();
11811159
1182 inline for (.{ true, false }) |whitespace| {1160 for ([2]bool{ true, false }) |whitespace| {
1183 sz.options = .{ .whitespace = whitespace };1161 s.options = .{ .whitespace = whitespace };
11841162
1185 // Empty containers1163 // Empty containers
1186 {1164 {
1187 var container = try sz.beginStruct(.{});1165 var container = try s.beginStruct(.{});
1188 try container.end();1166 try container.end();
1189 try std.testing.expectEqualStrings(".{}", buf.items);1167 try std.testing.expectEqualStrings(".{}", aw.getWritten());
1190 buf.clearRetainingCapacity();1168 aw.clearRetainingCapacity();
1191 }1169 }
11921170
1193 {1171 {
1194 var container = try sz.beginTuple(.{});1172 var container = try s.beginTuple(.{});
1195 try container.end();1173 try container.end();
1196 try std.testing.expectEqualStrings(".{}", buf.items);1174 try std.testing.expectEqualStrings(".{}", aw.getWritten());
1197 buf.clearRetainingCapacity();1175 aw.clearRetainingCapacity();
1198 }1176 }
11991177
1200 {1178 {
1201 var container = try sz.beginStruct(.{ .whitespace_style = .{ .wrap = false } });1179 var container = try s.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
1202 try container.end();1180 try container.end();
1203 try std.testing.expectEqualStrings(".{}", buf.items);1181 try std.testing.expectEqualStrings(".{}", aw.getWritten());
1204 buf.clearRetainingCapacity();1182 aw.clearRetainingCapacity();
1205 }1183 }
12061184
1207 {1185 {
1208 var container = try sz.beginTuple(.{ .whitespace_style = .{ .wrap = false } });1186 var container = try s.beginTuple(.{ .whitespace_style = .{ .wrap = false } });
1209 try container.end();1187 try container.end();
1210 try std.testing.expectEqualStrings(".{}", buf.items);1188 try std.testing.expectEqualStrings(".{}", aw.getWritten());
1211 buf.clearRetainingCapacity();1189 aw.clearRetainingCapacity();
1212 }1190 }
12131191
1214 {1192 {
1215 var container = try sz.beginStruct(.{ .whitespace_style = .{ .fields = 0 } });1193 var container = try s.beginStruct(.{ .whitespace_style = .{ .fields = 0 } });
1216 try container.end();1194 try container.end();
1217 try std.testing.expectEqualStrings(".{}", buf.items);1195 try std.testing.expectEqualStrings(".{}", aw.getWritten());
1218 buf.clearRetainingCapacity();1196 aw.clearRetainingCapacity();
1219 }1197 }
12201198
1221 {1199 {
1222 var container = try sz.beginTuple(.{ .whitespace_style = .{ .fields = 0 } });1200 var container = try s.beginTuple(.{ .whitespace_style = .{ .fields = 0 } });
1223 try container.end();1201 try container.end();
1224 try std.testing.expectEqualStrings(".{}", buf.items);1202 try std.testing.expectEqualStrings(".{}", aw.getWritten());
1225 buf.clearRetainingCapacity();1203 aw.clearRetainingCapacity();
1226 }1204 }
12271205
1228 // Size 11206 // Size 1
1229 {1207 {
1230 var container = try sz.beginStruct(.{});1208 var container = try s.beginStruct(.{});
1231 try container.field("a", 1, .{});1209 try container.field("a", 1, .{});
1232 try container.end();1210 try container.end();
1233 if (whitespace) {1211 if (whitespace) {
...@@ -1235,15 +1213,15 @@ test "std.zon stringify whitespace, low level API" {...@@ -1235,15 +1213,15 @@ test "std.zon stringify whitespace, low level API" {
1235 \\.{1213 \\.{
1236 \\ .a = 1,1214 \\ .a = 1,
1237 \\}1215 \\}
1238 , buf.items);1216 , aw.getWritten());
1239 } else {1217 } else {
1240 try std.testing.expectEqualStrings(".{.a=1}", buf.items);1218 try std.testing.expectEqualStrings(".{.a=1}", aw.getWritten());
1241 }1219 }
1242 buf.clearRetainingCapacity();1220 aw.clearRetainingCapacity();
1243 }1221 }
12441222
1245 {1223 {
1246 var container = try sz.beginTuple(.{});1224 var container = try s.beginTuple(.{});
1247 try container.field(1, .{});1225 try container.field(1, .{});
1248 try container.end();1226 try container.end();
1249 if (whitespace) {1227 if (whitespace) {
...@@ -1251,62 +1229,62 @@ test "std.zon stringify whitespace, low level API" {...@@ -1251,62 +1229,62 @@ test "std.zon stringify whitespace, low level API" {
1251 \\.{1229 \\.{
1252 \\ 1,1230 \\ 1,
1253 \\}1231 \\}
1254 , buf.items);1232 , aw.getWritten());
1255 } else {1233 } else {
1256 try std.testing.expectEqualStrings(".{1}", buf.items);1234 try std.testing.expectEqualStrings(".{1}", aw.getWritten());
1257 }1235 }
1258 buf.clearRetainingCapacity();1236 aw.clearRetainingCapacity();
1259 }1237 }
12601238
1261 {1239 {
1262 var container = try sz.beginStruct(.{ .whitespace_style = .{ .wrap = false } });1240 var container = try s.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
1263 try container.field("a", 1, .{});1241 try container.field("a", 1, .{});
1264 try container.end();1242 try container.end();
1265 if (whitespace) {1243 if (whitespace) {
1266 try std.testing.expectEqualStrings(".{ .a = 1 }", buf.items);1244 try std.testing.expectEqualStrings(".{ .a = 1 }", aw.getWritten());
1267 } else {1245 } else {
1268 try std.testing.expectEqualStrings(".{.a=1}", buf.items);1246 try std.testing.expectEqualStrings(".{.a=1}", aw.getWritten());
1269 }1247 }
1270 buf.clearRetainingCapacity();1248 aw.clearRetainingCapacity();
1271 }1249 }
12721250
1273 {1251 {
1274 // We get extra spaces here, since we didn't know up front that there would only be one1252 // We get extra spaces here, since we didn't know up front that there would only be one
1275 // field.1253 // field.
1276 var container = try sz.beginTuple(.{ .whitespace_style = .{ .wrap = false } });1254 var container = try s.beginTuple(.{ .whitespace_style = .{ .wrap = false } });
1277 try container.field(1, .{});1255 try container.field(1, .{});
1278 try container.end();1256 try container.end();
1279 if (whitespace) {1257 if (whitespace) {
1280 try std.testing.expectEqualStrings(".{ 1 }", buf.items);1258 try std.testing.expectEqualStrings(".{ 1 }", aw.getWritten());
1281 } else {1259 } else {
1282 try std.testing.expectEqualStrings(".{1}", buf.items);1260 try std.testing.expectEqualStrings(".{1}", aw.getWritten());
1283 }1261 }
1284 buf.clearRetainingCapacity();1262 aw.clearRetainingCapacity();
1285 }1263 }
12861264
1287 {1265 {
1288 var container = try sz.beginStruct(.{ .whitespace_style = .{ .fields = 1 } });1266 var container = try s.beginStruct(.{ .whitespace_style = .{ .fields = 1 } });
1289 try container.field("a", 1, .{});1267 try container.field("a", 1, .{});
1290 try container.end();1268 try container.end();
1291 if (whitespace) {1269 if (whitespace) {
1292 try std.testing.expectEqualStrings(".{ .a = 1 }", buf.items);1270 try std.testing.expectEqualStrings(".{ .a = 1 }", aw.getWritten());
1293 } else {1271 } else {
1294 try std.testing.expectEqualStrings(".{.a=1}", buf.items);1272 try std.testing.expectEqualStrings(".{.a=1}", aw.getWritten());
1295 }1273 }
1296 buf.clearRetainingCapacity();1274 aw.clearRetainingCapacity();
1297 }1275 }
12981276
1299 {1277 {
1300 var container = try sz.beginTuple(.{ .whitespace_style = .{ .fields = 1 } });1278 var container = try s.beginTuple(.{ .whitespace_style = .{ .fields = 1 } });
1301 try container.field(1, .{});1279 try container.field(1, .{});
1302 try container.end();1280 try container.end();
1303 try std.testing.expectEqualStrings(".{1}", buf.items);1281 try std.testing.expectEqualStrings(".{1}", aw.getWritten());
1304 buf.clearRetainingCapacity();1282 aw.clearRetainingCapacity();
1305 }1283 }
13061284
1307 // Size 21285 // Size 2
1308 {1286 {
1309 var container = try sz.beginStruct(.{});1287 var container = try s.beginStruct(.{});
1310 try container.field("a", 1, .{});1288 try container.field("a", 1, .{});
1311 try container.field("b", 2, .{});1289 try container.field("b", 2, .{});
1312 try container.end();1290 try container.end();
...@@ -1316,15 +1294,15 @@ test "std.zon stringify whitespace, low level API" {...@@ -1316,15 +1294,15 @@ test "std.zon stringify whitespace, low level API" {
1316 \\ .a = 1,1294 \\ .a = 1,
1317 \\ .b = 2,1295 \\ .b = 2,
1318 \\}1296 \\}
1319 , buf.items);1297 , aw.getWritten());
1320 } else {1298 } else {
1321 try std.testing.expectEqualStrings(".{.a=1,.b=2}", buf.items);1299 try std.testing.expectEqualStrings(".{.a=1,.b=2}", aw.getWritten());
1322 }1300 }
1323 buf.clearRetainingCapacity();1301 aw.clearRetainingCapacity();
1324 }1302 }
13251303
1326 {1304 {
1327 var container = try sz.beginTuple(.{});1305 var container = try s.beginTuple(.{});
1328 try container.field(1, .{});1306 try container.field(1, .{});
1329 try container.field(2, .{});1307 try container.field(2, .{});
1330 try container.end();1308 try container.end();
...@@ -1334,68 +1312,68 @@ test "std.zon stringify whitespace, low level API" {...@@ -1334,68 +1312,68 @@ test "std.zon stringify whitespace, low level API" {
1334 \\ 1,1312 \\ 1,
1335 \\ 2,1313 \\ 2,
1336 \\}1314 \\}
1337 , buf.items);1315 , aw.getWritten());
1338 } else {1316 } else {
1339 try std.testing.expectEqualStrings(".{1,2}", buf.items);1317 try std.testing.expectEqualStrings(".{1,2}", aw.getWritten());
1340 }1318 }
1341 buf.clearRetainingCapacity();1319 aw.clearRetainingCapacity();
1342 }1320 }
13431321
1344 {1322 {
1345 var container = try sz.beginStruct(.{ .whitespace_style = .{ .wrap = false } });1323 var container = try s.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
1346 try container.field("a", 1, .{});1324 try container.field("a", 1, .{});
1347 try container.field("b", 2, .{});1325 try container.field("b", 2, .{});
1348 try container.end();1326 try container.end();
1349 if (whitespace) {1327 if (whitespace) {
1350 try std.testing.expectEqualStrings(".{ .a = 1, .b = 2 }", buf.items);1328 try std.testing.expectEqualStrings(".{ .a = 1, .b = 2 }", aw.getWritten());
1351 } else {1329 } else {
1352 try std.testing.expectEqualStrings(".{.a=1,.b=2}", buf.items);1330 try std.testing.expectEqualStrings(".{.a=1,.b=2}", aw.getWritten());
1353 }1331 }
1354 buf.clearRetainingCapacity();1332 aw.clearRetainingCapacity();
1355 }1333 }
13561334
1357 {1335 {
1358 var container = try sz.beginTuple(.{ .whitespace_style = .{ .wrap = false } });1336 var container = try s.beginTuple(.{ .whitespace_style = .{ .wrap = false } });
1359 try container.field(1, .{});1337 try container.field(1, .{});
1360 try container.field(2, .{});1338 try container.field(2, .{});
1361 try container.end();1339 try container.end();
1362 if (whitespace) {1340 if (whitespace) {
1363 try std.testing.expectEqualStrings(".{ 1, 2 }", buf.items);1341 try std.testing.expectEqualStrings(".{ 1, 2 }", aw.getWritten());
1364 } else {1342 } else {
1365 try std.testing.expectEqualStrings(".{1,2}", buf.items);1343 try std.testing.expectEqualStrings(".{1,2}", aw.getWritten());
1366 }1344 }
1367 buf.clearRetainingCapacity();1345 aw.clearRetainingCapacity();
1368 }1346 }
13691347
1370 {1348 {
1371 var container = try sz.beginStruct(.{ .whitespace_style = .{ .fields = 2 } });1349 var container = try s.beginStruct(.{ .whitespace_style = .{ .fields = 2 } });
1372 try container.field("a", 1, .{});1350 try container.field("a", 1, .{});
1373 try container.field("b", 2, .{});1351 try container.field("b", 2, .{});
1374 try container.end();1352 try container.end();
1375 if (whitespace) {1353 if (whitespace) {
1376 try std.testing.expectEqualStrings(".{ .a = 1, .b = 2 }", buf.items);1354 try std.testing.expectEqualStrings(".{ .a = 1, .b = 2 }", aw.getWritten());
1377 } else {1355 } else {
1378 try std.testing.expectEqualStrings(".{.a=1,.b=2}", buf.items);1356 try std.testing.expectEqualStrings(".{.a=1,.b=2}", aw.getWritten());
1379 }1357 }
1380 buf.clearRetainingCapacity();1358 aw.clearRetainingCapacity();
1381 }1359 }
13821360
1383 {1361 {
1384 var container = try sz.beginTuple(.{ .whitespace_style = .{ .fields = 2 } });1362 var container = try s.beginTuple(.{ .whitespace_style = .{ .fields = 2 } });
1385 try container.field(1, .{});1363 try container.field(1, .{});
1386 try container.field(2, .{});1364 try container.field(2, .{});
1387 try container.end();1365 try container.end();
1388 if (whitespace) {1366 if (whitespace) {
1389 try std.testing.expectEqualStrings(".{ 1, 2 }", buf.items);1367 try std.testing.expectEqualStrings(".{ 1, 2 }", aw.getWritten());
1390 } else {1368 } else {
1391 try std.testing.expectEqualStrings(".{1,2}", buf.items);1369 try std.testing.expectEqualStrings(".{1,2}", aw.getWritten());
1392 }1370 }
1393 buf.clearRetainingCapacity();1371 aw.clearRetainingCapacity();
1394 }1372 }
13951373
1396 // Size 31374 // Size 3
1397 {1375 {
1398 var container = try sz.beginStruct(.{});1376 var container = try s.beginStruct(.{});
1399 try container.field("a", 1, .{});1377 try container.field("a", 1, .{});
1400 try container.field("b", 2, .{});1378 try container.field("b", 2, .{});
1401 try container.field("c", 3, .{});1379 try container.field("c", 3, .{});
...@@ -1407,15 +1385,15 @@ test "std.zon stringify whitespace, low level API" {...@@ -1407,15 +1385,15 @@ test "std.zon stringify whitespace, low level API" {
1407 \\ .b = 2,1385 \\ .b = 2,
1408 \\ .c = 3,1386 \\ .c = 3,
1409 \\}1387 \\}
1410 , buf.items);1388 , aw.getWritten());
1411 } else {1389 } else {
1412 try std.testing.expectEqualStrings(".{.a=1,.b=2,.c=3}", buf.items);1390 try std.testing.expectEqualStrings(".{.a=1,.b=2,.c=3}", aw.getWritten());
1413 }1391 }
1414 buf.clearRetainingCapacity();1392 aw.clearRetainingCapacity();
1415 }1393 }
14161394
1417 {1395 {
1418 var container = try sz.beginTuple(.{});1396 var container = try s.beginTuple(.{});
1419 try container.field(1, .{});1397 try container.field(1, .{});
1420 try container.field(2, .{});1398 try container.field(2, .{});
1421 try container.field(3, .{});1399 try container.field(3, .{});
...@@ -1427,43 +1405,43 @@ test "std.zon stringify whitespace, low level API" {...@@ -1427,43 +1405,43 @@ test "std.zon stringify whitespace, low level API" {
1427 \\ 2,1405 \\ 2,
1428 \\ 3,1406 \\ 3,
1429 \\}1407 \\}
1430 , buf.items);1408 , aw.getWritten());
1431 } else {1409 } else {
1432 try std.testing.expectEqualStrings(".{1,2,3}", buf.items);1410 try std.testing.expectEqualStrings(".{1,2,3}", aw.getWritten());
1433 }1411 }
1434 buf.clearRetainingCapacity();1412 aw.clearRetainingCapacity();
1435 }1413 }
14361414
1437 {1415 {
1438 var container = try sz.beginStruct(.{ .whitespace_style = .{ .wrap = false } });1416 var container = try s.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
1439 try container.field("a", 1, .{});1417 try container.field("a", 1, .{});
1440 try container.field("b", 2, .{});1418 try container.field("b", 2, .{});
1441 try container.field("c", 3, .{});1419 try container.field("c", 3, .{});
1442 try container.end();1420 try container.end();
1443 if (whitespace) {1421 if (whitespace) {
1444 try std.testing.expectEqualStrings(".{ .a = 1, .b = 2, .c = 3 }", buf.items);1422 try std.testing.expectEqualStrings(".{ .a = 1, .b = 2, .c = 3 }", aw.getWritten());
1445 } else {1423 } else {
1446 try std.testing.expectEqualStrings(".{.a=1,.b=2,.c=3}", buf.items);1424 try std.testing.expectEqualStrings(".{.a=1,.b=2,.c=3}", aw.getWritten());
1447 }1425 }
1448 buf.clearRetainingCapacity();1426 aw.clearRetainingCapacity();
1449 }1427 }
14501428
1451 {1429 {
1452 var container = try sz.beginTuple(.{ .whitespace_style = .{ .wrap = false } });1430 var container = try s.beginTuple(.{ .whitespace_style = .{ .wrap = false } });
1453 try container.field(1, .{});1431 try container.field(1, .{});
1454 try container.field(2, .{});1432 try container.field(2, .{});
1455 try container.field(3, .{});1433 try container.field(3, .{});
1456 try container.end();1434 try container.end();
1457 if (whitespace) {1435 if (whitespace) {
1458 try std.testing.expectEqualStrings(".{ 1, 2, 3 }", buf.items);1436 try std.testing.expectEqualStrings(".{ 1, 2, 3 }", aw.getWritten());
1459 } else {1437 } else {
1460 try std.testing.expectEqualStrings(".{1,2,3}", buf.items);1438 try std.testing.expectEqualStrings(".{1,2,3}", aw.getWritten());
1461 }1439 }
1462 buf.clearRetainingCapacity();1440 aw.clearRetainingCapacity();
1463 }1441 }
14641442
1465 {1443 {
1466 var container = try sz.beginStruct(.{ .whitespace_style = .{ .fields = 3 } });1444 var container = try s.beginStruct(.{ .whitespace_style = .{ .fields = 3 } });
1467 try container.field("a", 1, .{});1445 try container.field("a", 1, .{});
1468 try container.field("b", 2, .{});1446 try container.field("b", 2, .{});
1469 try container.field("c", 3, .{});1447 try container.field("c", 3, .{});
...@@ -1475,15 +1453,15 @@ test "std.zon stringify whitespace, low level API" {...@@ -1475,15 +1453,15 @@ test "std.zon stringify whitespace, low level API" {
1475 \\ .b = 2,1453 \\ .b = 2,
1476 \\ .c = 3,1454 \\ .c = 3,
1477 \\}1455 \\}
1478 , buf.items);1456 , aw.getWritten());
1479 } else {1457 } else {
1480 try std.testing.expectEqualStrings(".{.a=1,.b=2,.c=3}", buf.items);1458 try std.testing.expectEqualStrings(".{.a=1,.b=2,.c=3}", aw.getWritten());
1481 }1459 }
1482 buf.clearRetainingCapacity();1460 aw.clearRetainingCapacity();
1483 }1461 }
14841462
1485 {1463 {
1486 var container = try sz.beginTuple(.{ .whitespace_style = .{ .fields = 3 } });1464 var container = try s.beginTuple(.{ .whitespace_style = .{ .fields = 3 } });
1487 try container.field(1, .{});1465 try container.field(1, .{});
1488 try container.field(2, .{});1466 try container.field(2, .{});
1489 try container.field(3, .{});1467 try container.field(3, .{});
...@@ -1495,16 +1473,16 @@ test "std.zon stringify whitespace, low level API" {...@@ -1495,16 +1473,16 @@ test "std.zon stringify whitespace, low level API" {
1495 \\ 2,1473 \\ 2,
1496 \\ 3,1474 \\ 3,
1497 \\}1475 \\}
1498 , buf.items);1476 , aw.getWritten());
1499 } else {1477 } else {
1500 try std.testing.expectEqualStrings(".{1,2,3}", buf.items);1478 try std.testing.expectEqualStrings(".{1,2,3}", aw.getWritten());
1501 }1479 }
1502 buf.clearRetainingCapacity();1480 aw.clearRetainingCapacity();
1503 }1481 }
15041482
1505 // Nested objects where the outer container doesn't wrap but the inner containers do1483 // Nested objects where the outer container doesn't wrap but the inner containers do
1506 {1484 {
1507 var container = try sz.beginStruct(.{ .whitespace_style = .{ .wrap = false } });1485 var container = try s.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
1508 try container.field("first", .{ 1, 2, 3 }, .{});1486 try container.field("first", .{ 1, 2, 3 }, .{});
1509 try container.field("second", .{ 4, 5, 6 }, .{});1487 try container.field("second", .{ 4, 5, 6 }, .{});
1510 try container.end();1488 try container.end();
...@@ -1519,139 +1497,141 @@ test "std.zon stringify whitespace, low level API" {...@@ -1519,139 +1497,141 @@ test "std.zon stringify whitespace, low level API" {
1519 \\ 5,1497 \\ 5,
1520 \\ 6,1498 \\ 6,
1521 \\} }1499 \\} }
1522 , buf.items);1500 , aw.getWritten());
1523 } else {1501 } else {
1524 try std.testing.expectEqualStrings(1502 try std.testing.expectEqualStrings(
1525 ".{.first=.{1,2,3},.second=.{4,5,6}}",1503 ".{.first=.{1,2,3},.second=.{4,5,6}}",
1526 buf.items,1504 aw.getWritten(),
1527 );1505 );
1528 }1506 }
1529 buf.clearRetainingCapacity();1507 aw.clearRetainingCapacity();
1530 }1508 }
1531 }1509 }
1532}1510}
15331511
1534test "std.zon stringify utf8 codepoints" {1512test "std.zon stringify utf8 codepoints" {
1535 var buf = std.ArrayList(u8).init(std.testing.allocator);1513 var aw: Writer.Allocating = .init(std.testing.allocator);
1536 defer buf.deinit();1514 var s: Serializer = .{ .writer = &aw.writer };
1537 var sz = serializer(buf.writer(), .{});1515 defer aw.deinit();
15381516
1539 // Printable ASCII1517 // Printable ASCII
1540 try sz.int('a');1518 try s.int('a');
1541 try std.testing.expectEqualStrings("97", buf.items);1519 try std.testing.expectEqualStrings("97", aw.getWritten());
1542 buf.clearRetainingCapacity();1520 aw.clearRetainingCapacity();
15431521
1544 try sz.codePoint('a');1522 try s.codePoint('a');
1545 try std.testing.expectEqualStrings("'a'", buf.items);1523 try std.testing.expectEqualStrings("'a'", aw.getWritten());
1546 buf.clearRetainingCapacity();1524 aw.clearRetainingCapacity();
15471525
1548 try sz.value('a', .{ .emit_codepoint_literals = .always });1526 try s.value('a', .{ .emit_codepoint_literals = .always });
1549 try std.testing.expectEqualStrings("'a'", buf.items);1527 try std.testing.expectEqualStrings("'a'", aw.getWritten());
1550 buf.clearRetainingCapacity();1528 aw.clearRetainingCapacity();
15511529
1552 try sz.value('a', .{ .emit_codepoint_literals = .printable_ascii });1530 try s.value('a', .{ .emit_codepoint_literals = .printable_ascii });
1553 try std.testing.expectEqualStrings("'a'", buf.items);1531 try std.testing.expectEqualStrings("'a'", aw.getWritten());
1554 buf.clearRetainingCapacity();1532 aw.clearRetainingCapacity();
15551533
1556 try sz.value('a', .{ .emit_codepoint_literals = .never });1534 try s.value('a', .{ .emit_codepoint_literals = .never });
1557 try std.testing.expectEqualStrings("97", buf.items);1535 try std.testing.expectEqualStrings("97", aw.getWritten());
1558 buf.clearRetainingCapacity();1536 aw.clearRetainingCapacity();
15591537
1560 // Short escaped codepoint1538 // Short escaped codepoint
1561 try sz.int('\n');1539 try s.int('\n');
1562 try std.testing.expectEqualStrings("10", buf.items);1540 try std.testing.expectEqualStrings("10", aw.getWritten());
1563 buf.clearRetainingCapacity();1541 aw.clearRetainingCapacity();
15641542
1565 try sz.codePoint('\n');1543 try s.codePoint('\n');
1566 try std.testing.expectEqualStrings("'\\n'", buf.items);1544 try std.testing.expectEqualStrings("'\\n'", aw.getWritten());
1567 buf.clearRetainingCapacity();1545 aw.clearRetainingCapacity();
15681546
1569 try sz.value('\n', .{ .emit_codepoint_literals = .always });1547 try s.value('\n', .{ .emit_codepoint_literals = .always });
1570 try std.testing.expectEqualStrings("'\\n'", buf.items);1548 try std.testing.expectEqualStrings("'\\n'", aw.getWritten());
1571 buf.clearRetainingCapacity();1549 aw.clearRetainingCapacity();
15721550
1573 try sz.value('\n', .{ .emit_codepoint_literals = .printable_ascii });1551 try s.value('\n', .{ .emit_codepoint_literals = .printable_ascii });
1574 try std.testing.expectEqualStrings("10", buf.items);1552 try std.testing.expectEqualStrings("10", aw.getWritten());
1575 buf.clearRetainingCapacity();1553 aw.clearRetainingCapacity();
15761554
1577 try sz.value('\n', .{ .emit_codepoint_literals = .never });1555 try s.value('\n', .{ .emit_codepoint_literals = .never });
1578 try std.testing.expectEqualStrings("10", buf.items);1556 try std.testing.expectEqualStrings("10", aw.getWritten());
1579 buf.clearRetainingCapacity();1557 aw.clearRetainingCapacity();
15801558
1581 // Large codepoint1559 // Large codepoint
1582 try sz.int('⚡');1560 try s.int('⚡');
1583 try std.testing.expectEqualStrings("9889", buf.items);1561 try std.testing.expectEqualStrings("9889", aw.getWritten());
1584 buf.clearRetainingCapacity();1562 aw.clearRetainingCapacity();
15851563
1586 try sz.codePoint('⚡');1564 try s.codePoint('⚡');
1587 try std.testing.expectEqualStrings("'\\xe2\\x9a\\xa1'", buf.items);1565 try std.testing.expectEqualStrings("'\\u{26a1}'", aw.getWritten());
1588 buf.clearRetainingCapacity();1566 aw.clearRetainingCapacity();
15891567
1590 try sz.value('⚡', .{ .emit_codepoint_literals = .always });1568 try s.value('⚡', .{ .emit_codepoint_literals = .always });
1591 try std.testing.expectEqualStrings("'\\xe2\\x9a\\xa1'", buf.items);1569 try std.testing.expectEqualStrings("'\\u{26a1}'", aw.getWritten());
1592 buf.clearRetainingCapacity();1570 aw.clearRetainingCapacity();
15931571
1594 try sz.value('⚡', .{ .emit_codepoint_literals = .printable_ascii });1572 try s.value('⚡', .{ .emit_codepoint_literals = .printable_ascii });
1595 try std.testing.expectEqualStrings("9889", buf.items);1573 try std.testing.expectEqualStrings("9889", aw.getWritten());
1596 buf.clearRetainingCapacity();1574 aw.clearRetainingCapacity();
15971575
1598 try sz.value('⚡', .{ .emit_codepoint_literals = .never });1576 try s.value('⚡', .{ .emit_codepoint_literals = .never });
1599 try std.testing.expectEqualStrings("9889", buf.items);1577 try std.testing.expectEqualStrings("9889", aw.getWritten());
1600 buf.clearRetainingCapacity();1578 aw.clearRetainingCapacity();
16011579
1602 // Invalid codepoint1580 // Invalid codepoint
1603 try std.testing.expectError(error.InvalidCodepoint, sz.codePoint(0x110000 + 1));1581 try s.codePoint(0x110000 + 1);
1582 try std.testing.expectEqualStrings("'\\u{110001}'", aw.getWritten());
1583 aw.clearRetainingCapacity();
16041584
1605 try sz.int(0x110000 + 1);1585 try s.int(0x110000 + 1);
1606 try std.testing.expectEqualStrings("1114113", buf.items);1586 try std.testing.expectEqualStrings("1114113", aw.getWritten());
1607 buf.clearRetainingCapacity();1587 aw.clearRetainingCapacity();
16081588
1609 try sz.value(0x110000 + 1, .{ .emit_codepoint_literals = .always });1589 try s.value(0x110000 + 1, .{ .emit_codepoint_literals = .always });
1610 try std.testing.expectEqualStrings("1114113", buf.items);1590 try std.testing.expectEqualStrings("1114113", aw.getWritten());
1611 buf.clearRetainingCapacity();1591 aw.clearRetainingCapacity();
16121592
1613 try sz.value(0x110000 + 1, .{ .emit_codepoint_literals = .printable_ascii });1593 try s.value(0x110000 + 1, .{ .emit_codepoint_literals = .printable_ascii });
1614 try std.testing.expectEqualStrings("1114113", buf.items);1594 try std.testing.expectEqualStrings("1114113", aw.getWritten());
1615 buf.clearRetainingCapacity();1595 aw.clearRetainingCapacity();
16161596
1617 try sz.value(0x110000 + 1, .{ .emit_codepoint_literals = .never });1597 try s.value(0x110000 + 1, .{ .emit_codepoint_literals = .never });
1618 try std.testing.expectEqualStrings("1114113", buf.items);1598 try std.testing.expectEqualStrings("1114113", aw.getWritten());
1619 buf.clearRetainingCapacity();1599 aw.clearRetainingCapacity();
16201600
1621 // Valid codepoint, not a codepoint type1601 // Valid codepoint, not a codepoint type
1622 try sz.value(@as(u22, 'a'), .{ .emit_codepoint_literals = .always });1602 try s.value(@as(u22, 'a'), .{ .emit_codepoint_literals = .always });
1623 try std.testing.expectEqualStrings("97", buf.items);1603 try std.testing.expectEqualStrings("97", aw.getWritten());
1624 buf.clearRetainingCapacity();1604 aw.clearRetainingCapacity();
16251605
1626 try sz.value(@as(u22, 'a'), .{ .emit_codepoint_literals = .printable_ascii });1606 try s.value(@as(u22, 'a'), .{ .emit_codepoint_literals = .printable_ascii });
1627 try std.testing.expectEqualStrings("97", buf.items);1607 try std.testing.expectEqualStrings("97", aw.getWritten());
1628 buf.clearRetainingCapacity();1608 aw.clearRetainingCapacity();
16291609
1630 try sz.value(@as(i32, 'a'), .{ .emit_codepoint_literals = .never });1610 try s.value(@as(i32, 'a'), .{ .emit_codepoint_literals = .never });
1631 try std.testing.expectEqualStrings("97", buf.items);1611 try std.testing.expectEqualStrings("97", aw.getWritten());
1632 buf.clearRetainingCapacity();1612 aw.clearRetainingCapacity();
16331613
1634 // Make sure value options are passed to children1614 // Make sure value options are passed to children
1635 try sz.value(.{ .c = '⚡' }, .{ .emit_codepoint_literals = .always });1615 try s.value(.{ .c = '⚡' }, .{ .emit_codepoint_literals = .always });
1636 try std.testing.expectEqualStrings(".{ .c = '\\xe2\\x9a\\xa1' }", buf.items);1616 try std.testing.expectEqualStrings(".{ .c = '\\u{26a1}' }", aw.getWritten());
1637 buf.clearRetainingCapacity();1617 aw.clearRetainingCapacity();
16381618
1639 try sz.value(.{ .c = '⚡' }, .{ .emit_codepoint_literals = .never });1619 try s.value(.{ .c = '⚡' }, .{ .emit_codepoint_literals = .never });
1640 try std.testing.expectEqualStrings(".{ .c = 9889 }", buf.items);1620 try std.testing.expectEqualStrings(".{ .c = 9889 }", aw.getWritten());
1641 buf.clearRetainingCapacity();1621 aw.clearRetainingCapacity();
1642}1622}
16431623
1644test "std.zon stringify strings" {1624test "std.zon stringify strings" {
1645 var buf = std.ArrayList(u8).init(std.testing.allocator);1625 var aw: Writer.Allocating = .init(std.testing.allocator);
1646 defer buf.deinit();1626 var s: Serializer = .{ .writer = &aw.writer };
1647 var sz = serializer(buf.writer(), .{});1627 defer aw.deinit();
16481628
1649 // Minimal case1629 // Minimal case
1650 try sz.string("abc⚡\n");1630 try s.string("abc⚡\n");
1651 try std.testing.expectEqualStrings("\"abc\\xe2\\x9a\\xa1\\n\"", buf.items);1631 try std.testing.expectEqualStrings("\"abc\\xe2\\x9a\\xa1\\n\"", aw.getWritten());
1652 buf.clearRetainingCapacity();1632 aw.clearRetainingCapacity();
16531633
1654 try sz.tuple("abc⚡\n", .{});1634 try s.tuple("abc⚡\n", .{});
1655 try std.testing.expectEqualStrings(1635 try std.testing.expectEqualStrings(
1656 \\.{1636 \\.{
1657 \\ 97,1637 \\ 97,
...@@ -1662,14 +1642,14 @@ test "std.zon stringify strings" {...@@ -1662,14 +1642,14 @@ test "std.zon stringify strings" {
1662 \\ 161,1642 \\ 161,
1663 \\ 10,1643 \\ 10,
1664 \\}1644 \\}
1665 , buf.items);1645 , aw.getWritten());
1666 buf.clearRetainingCapacity();1646 aw.clearRetainingCapacity();
16671647
1668 try sz.value("abc⚡\n", .{});1648 try s.value("abc⚡\n", .{});
1669 try std.testing.expectEqualStrings("\"abc\\xe2\\x9a\\xa1\\n\"", buf.items);1649 try std.testing.expectEqualStrings("\"abc\\xe2\\x9a\\xa1\\n\"", aw.getWritten());
1670 buf.clearRetainingCapacity();1650 aw.clearRetainingCapacity();
16711651
1672 try sz.value("abc⚡\n", .{ .emit_strings_as_containers = true });1652 try s.value("abc⚡\n", .{ .emit_strings_as_containers = true });
1673 try std.testing.expectEqualStrings(1653 try std.testing.expectEqualStrings(
1674 \\.{1654 \\.{
1675 \\ 97,1655 \\ 97,
...@@ -1680,113 +1660,113 @@ test "std.zon stringify strings" {...@@ -1680,113 +1660,113 @@ test "std.zon stringify strings" {
1680 \\ 161,1660 \\ 161,
1681 \\ 10,1661 \\ 10,
1682 \\}1662 \\}
1683 , buf.items);1663 , aw.getWritten());
1684 buf.clearRetainingCapacity();1664 aw.clearRetainingCapacity();
16851665
1686 // Value options are inherited by children1666 // Value options are inherited by children
1687 try sz.value(.{ .str = "abc" }, .{});1667 try s.value(.{ .str = "abc" }, .{});
1688 try std.testing.expectEqualStrings(".{ .str = \"abc\" }", buf.items);1668 try std.testing.expectEqualStrings(".{ .str = \"abc\" }", aw.getWritten());
1689 buf.clearRetainingCapacity();1669 aw.clearRetainingCapacity();
16901670
1691 try sz.value(.{ .str = "abc" }, .{ .emit_strings_as_containers = true });1671 try s.value(.{ .str = "abc" }, .{ .emit_strings_as_containers = true });
1692 try std.testing.expectEqualStrings(1672 try std.testing.expectEqualStrings(
1693 \\.{ .str = .{1673 \\.{ .str = .{
1694 \\ 97,1674 \\ 97,
1695 \\ 98,1675 \\ 98,
1696 \\ 99,1676 \\ 99,
1697 \\} }1677 \\} }
1698 , buf.items);1678 , aw.getWritten());
1699 buf.clearRetainingCapacity();1679 aw.clearRetainingCapacity();
17001680
1701 // Arrays (rather than pointers to arrays) of u8s are not considered strings, so that data can1681 // Arrays (rather than pointers to arrays) of u8s are not considered strings, so that data can
1702 // round trip correctly.1682 // round trip correctly.
1703 try sz.value("abc".*, .{});1683 try s.value("abc".*, .{});
1704 try std.testing.expectEqualStrings(1684 try std.testing.expectEqualStrings(
1705 \\.{1685 \\.{
1706 \\ 97,1686 \\ 97,
1707 \\ 98,1687 \\ 98,
1708 \\ 99,1688 \\ 99,
1709 \\}1689 \\}
1710 , buf.items);1690 , aw.getWritten());
1711 buf.clearRetainingCapacity();1691 aw.clearRetainingCapacity();
1712}1692}
17131693
1714test "std.zon stringify multiline strings" {1694test "std.zon stringify multiline strings" {
1715 var buf = std.ArrayList(u8).init(std.testing.allocator);1695 var aw: Writer.Allocating = .init(std.testing.allocator);
1716 defer buf.deinit();1696 var s: Serializer = .{ .writer = &aw.writer };
1717 var sz = serializer(buf.writer(), .{});1697 defer aw.deinit();
17181698
1719 inline for (.{ true, false }) |whitespace| {1699 inline for (.{ true, false }) |whitespace| {
1720 sz.options.whitespace = whitespace;1700 s.options.whitespace = whitespace;
17211701
1722 {1702 {
1723 try sz.multilineString("", .{ .top_level = true });1703 try s.multilineString("", .{ .top_level = true });
1724 try std.testing.expectEqualStrings("\\\\", buf.items);1704 try std.testing.expectEqualStrings("\\\\", aw.getWritten());
1725 buf.clearRetainingCapacity();1705 aw.clearRetainingCapacity();
1726 }1706 }
17271707
1728 {1708 {
1729 try sz.multilineString("abc⚡", .{ .top_level = true });1709 try s.multilineString("abc⚡", .{ .top_level = true });
1730 try std.testing.expectEqualStrings("\\\\abc⚡", buf.items);1710 try std.testing.expectEqualStrings("\\\\abc⚡", aw.getWritten());
1731 buf.clearRetainingCapacity();1711 aw.clearRetainingCapacity();
1732 }1712 }
17331713
1734 {1714 {
1735 try sz.multilineString("abc⚡\ndef", .{ .top_level = true });1715 try s.multilineString("abc⚡\ndef", .{ .top_level = true });
1736 try std.testing.expectEqualStrings("\\\\abc⚡\n\\\\def", buf.items);1716 try std.testing.expectEqualStrings("\\\\abc⚡\n\\\\def", aw.getWritten());
1737 buf.clearRetainingCapacity();1717 aw.clearRetainingCapacity();
1738 }1718 }
17391719
1740 {1720 {
1741 try sz.multilineString("abc⚡\r\ndef", .{ .top_level = true });1721 try s.multilineString("abc⚡\r\ndef", .{ .top_level = true });
1742 try std.testing.expectEqualStrings("\\\\abc⚡\n\\\\def", buf.items);1722 try std.testing.expectEqualStrings("\\\\abc⚡\n\\\\def", aw.getWritten());
1743 buf.clearRetainingCapacity();1723 aw.clearRetainingCapacity();
1744 }1724 }
17451725
1746 {1726 {
1747 try sz.multilineString("\nabc⚡", .{ .top_level = true });1727 try s.multilineString("\nabc⚡", .{ .top_level = true });
1748 try std.testing.expectEqualStrings("\\\\\n\\\\abc⚡", buf.items);1728 try std.testing.expectEqualStrings("\\\\\n\\\\abc⚡", aw.getWritten());
1749 buf.clearRetainingCapacity();1729 aw.clearRetainingCapacity();
1750 }1730 }
17511731
1752 {1732 {
1753 try sz.multilineString("\r\nabc⚡", .{ .top_level = true });1733 try s.multilineString("\r\nabc⚡", .{ .top_level = true });
1754 try std.testing.expectEqualStrings("\\\\\n\\\\abc⚡", buf.items);1734 try std.testing.expectEqualStrings("\\\\\n\\\\abc⚡", aw.getWritten());
1755 buf.clearRetainingCapacity();1735 aw.clearRetainingCapacity();
1756 }1736 }
17571737
1758 {1738 {
1759 try sz.multilineString("abc\ndef", .{});1739 try s.multilineString("abc\ndef", .{});
1760 if (whitespace) {1740 if (whitespace) {
1761 try std.testing.expectEqualStrings("\n\\\\abc\n\\\\def\n", buf.items);1741 try std.testing.expectEqualStrings("\n\\\\abc\n\\\\def\n", aw.getWritten());
1762 } else {1742 } else {
1763 try std.testing.expectEqualStrings("\\\\abc\n\\\\def\n", buf.items);1743 try std.testing.expectEqualStrings("\\\\abc\n\\\\def\n", aw.getWritten());
1764 }1744 }
1765 buf.clearRetainingCapacity();1745 aw.clearRetainingCapacity();
1766 }1746 }
17671747
1768 {1748 {
1769 const str: []const u8 = &.{ 'a', '\r', 'c' };1749 const str: []const u8 = &.{ 'a', '\r', 'c' };
1770 try sz.string(str);1750 try s.string(str);
1771 try std.testing.expectEqualStrings("\"a\\rc\"", buf.items);1751 try std.testing.expectEqualStrings("\"a\\rc\"", aw.getWritten());
1772 buf.clearRetainingCapacity();1752 aw.clearRetainingCapacity();
1773 }1753 }
17741754
1775 {1755 {
1776 try std.testing.expectError(1756 try std.testing.expectError(
1777 error.InnerCarriageReturn,1757 error.InnerCarriageReturn,
1778 sz.multilineString(@as([]const u8, &.{ 'a', '\r', 'c' }), .{}),1758 s.multilineString(@as([]const u8, &.{ 'a', '\r', 'c' }), .{}),
1779 );1759 );
1780 try std.testing.expectError(1760 try std.testing.expectError(
1781 error.InnerCarriageReturn,1761 error.InnerCarriageReturn,
1782 sz.multilineString(@as([]const u8, &.{ 'a', '\r', 'c', '\n' }), .{}),1762 s.multilineString(@as([]const u8, &.{ 'a', '\r', 'c', '\n' }), .{}),
1783 );1763 );
1784 try std.testing.expectError(1764 try std.testing.expectError(
1785 error.InnerCarriageReturn,1765 error.InnerCarriageReturn,
1786 sz.multilineString(@as([]const u8, &.{ 'a', '\r', 'c', '\r', '\n' }), .{}),1766 s.multilineString(@as([]const u8, &.{ 'a', '\r', 'c', '\r', '\n' }), .{}),
1787 );1767 );
1788 try std.testing.expectEqualStrings("", buf.items);1768 try std.testing.expectEqualStrings("", aw.getWritten());
1789 buf.clearRetainingCapacity();1769 aw.clearRetainingCapacity();
1790 }1770 }
1791 }1771 }
1792}1772}
...@@ -1932,42 +1912,43 @@ test "std.zon stringify skip default fields" {...@@ -1932,42 +1912,43 @@ test "std.zon stringify skip default fields" {
1932}1912}
19331913
1934test "std.zon depth limits" {1914test "std.zon depth limits" {
1935 var buf = std.ArrayList(u8).init(std.testing.allocator);1915 var aw: Writer.Allocating = .init(std.testing.allocator);
1936 defer buf.deinit();1916 const bw = &aw.writer;
1917 defer aw.deinit();
19371918
1938 const Recurse = struct { r: []const @This() };1919 const Recurse = struct { r: []const @This() };
19391920
1940 // Normal operation1921 // Normal operation
1941 try serializeMaxDepth(.{ 1, .{ 2, 3 } }, .{}, buf.writer(), 16);1922 try serializeMaxDepth(.{ 1, .{ 2, 3 } }, .{}, bw, 16);
1942 try std.testing.expectEqualStrings(".{ 1, .{ 2, 3 } }", buf.items);1923 try std.testing.expectEqualStrings(".{ 1, .{ 2, 3 } }", aw.getWritten());
1943 buf.clearRetainingCapacity();1924 aw.clearRetainingCapacity();
19441925
1945 try serializeArbitraryDepth(.{ 1, .{ 2, 3 } }, .{}, buf.writer());1926 try serializeArbitraryDepth(.{ 1, .{ 2, 3 } }, .{}, bw);
1946 try std.testing.expectEqualStrings(".{ 1, .{ 2, 3 } }", buf.items);1927 try std.testing.expectEqualStrings(".{ 1, .{ 2, 3 } }", aw.getWritten());
1947 buf.clearRetainingCapacity();1928 aw.clearRetainingCapacity();
19481929
1949 // Max depth failing on non recursive type1930 // Max depth failing on non recursive type
1950 try std.testing.expectError(1931 try std.testing.expectError(
1951 error.ExceededMaxDepth,1932 error.ExceededMaxDepth,
1952 serializeMaxDepth(.{ 1, .{ 2, .{ 3, 4 } } }, .{}, buf.writer(), 3),1933 serializeMaxDepth(.{ 1, .{ 2, .{ 3, 4 } } }, .{}, bw, 3),
1953 );1934 );
1954 try std.testing.expectEqualStrings("", buf.items);1935 try std.testing.expectEqualStrings("", aw.getWritten());
1955 buf.clearRetainingCapacity();1936 aw.clearRetainingCapacity();
19561937
1957 // Max depth passing on recursive type1938 // Max depth passing on recursive type
1958 {1939 {
1959 const maybe_recurse = Recurse{ .r = &.{} };1940 const maybe_recurse = Recurse{ .r = &.{} };
1960 try serializeMaxDepth(maybe_recurse, .{}, buf.writer(), 2);1941 try serializeMaxDepth(maybe_recurse, .{}, bw, 2);
1961 try std.testing.expectEqualStrings(".{ .r = .{} }", buf.items);1942 try std.testing.expectEqualStrings(".{ .r = .{} }", aw.getWritten());
1962 buf.clearRetainingCapacity();1943 aw.clearRetainingCapacity();
1963 }1944 }
19641945
1965 // Unchecked passing on recursive type1946 // Unchecked passing on recursive type
1966 {1947 {
1967 const maybe_recurse = Recurse{ .r = &.{} };1948 const maybe_recurse = Recurse{ .r = &.{} };
1968 try serializeArbitraryDepth(maybe_recurse, .{}, buf.writer());1949 try serializeArbitraryDepth(maybe_recurse, .{}, bw);
1969 try std.testing.expectEqualStrings(".{ .r = .{} }", buf.items);1950 try std.testing.expectEqualStrings(".{ .r = .{} }", aw.getWritten());
1970 buf.clearRetainingCapacity();1951 aw.clearRetainingCapacity();
1971 }1952 }
19721953
1973 // Max depth failing on recursive type due to depth1954 // Max depth failing on recursive type due to depth
...@@ -1976,10 +1957,10 @@ test "std.zon depth limits" {...@@ -1976,10 +1957,10 @@ test "std.zon depth limits" {
1976 maybe_recurse.r = &.{.{ .r = &.{} }};1957 maybe_recurse.r = &.{.{ .r = &.{} }};
1977 try std.testing.expectError(1958 try std.testing.expectError(
1978 error.ExceededMaxDepth,1959 error.ExceededMaxDepth,
1979 serializeMaxDepth(maybe_recurse, .{}, buf.writer(), 2),1960 serializeMaxDepth(maybe_recurse, .{}, bw, 2),
1980 );1961 );
1981 try std.testing.expectEqualStrings("", buf.items);1962 try std.testing.expectEqualStrings("", aw.getWritten());
1982 buf.clearRetainingCapacity();1963 aw.clearRetainingCapacity();
1983 }1964 }
19841965
1985 // Same but for a slice1966 // Same but for a slice
...@@ -1989,23 +1970,23 @@ test "std.zon depth limits" {...@@ -1989,23 +1970,23 @@ test "std.zon depth limits" {
19891970
1990 try std.testing.expectError(1971 try std.testing.expectError(
1991 error.ExceededMaxDepth,1972 error.ExceededMaxDepth,
1992 serializeMaxDepth(maybe_recurse, .{}, buf.writer(), 2),1973 serializeMaxDepth(maybe_recurse, .{}, bw, 2),
1993 );1974 );
1994 try std.testing.expectEqualStrings("", buf.items);1975 try std.testing.expectEqualStrings("", aw.getWritten());
1995 buf.clearRetainingCapacity();1976 aw.clearRetainingCapacity();
19961977
1997 var sz = serializer(buf.writer(), .{});1978 var s: Serializer = .{ .writer = bw };
19981979
1999 try std.testing.expectError(1980 try std.testing.expectError(
2000 error.ExceededMaxDepth,1981 error.ExceededMaxDepth,
2001 sz.tupleMaxDepth(maybe_recurse, .{}, 2),1982 s.tupleMaxDepth(maybe_recurse, .{}, 2),
2002 );1983 );
2003 try std.testing.expectEqualStrings("", buf.items);1984 try std.testing.expectEqualStrings("", aw.getWritten());
2004 buf.clearRetainingCapacity();1985 aw.clearRetainingCapacity();
20051986
2006 try sz.tupleArbitraryDepth(maybe_recurse, .{});1987 try s.tupleArbitraryDepth(maybe_recurse, .{});
2007 try std.testing.expectEqualStrings(".{.{ .r = .{} }}", buf.items);1988 try std.testing.expectEqualStrings(".{.{ .r = .{} }}", aw.getWritten());
2008 buf.clearRetainingCapacity();1989 aw.clearRetainingCapacity();
2009 }1990 }
20101991
2011 // A slice succeeding1992 // A slice succeeding
...@@ -2013,19 +1994,19 @@ test "std.zon depth limits" {...@@ -2013,19 +1994,19 @@ test "std.zon depth limits" {
2013 var temp: [1]Recurse = .{.{ .r = &.{} }};1994 var temp: [1]Recurse = .{.{ .r = &.{} }};
2014 const maybe_recurse: []const Recurse = &temp;1995 const maybe_recurse: []const Recurse = &temp;
20151996
2016 try serializeMaxDepth(maybe_recurse, .{}, buf.writer(), 3);1997 try serializeMaxDepth(maybe_recurse, .{}, bw, 3);
2017 try std.testing.expectEqualStrings(".{.{ .r = .{} }}", buf.items);1998 try std.testing.expectEqualStrings(".{.{ .r = .{} }}", aw.getWritten());
2018 buf.clearRetainingCapacity();1999 aw.clearRetainingCapacity();
20192000
2020 var sz = serializer(buf.writer(), .{});2001 var s: Serializer = .{ .writer = bw };
20212002
2022 try sz.tupleMaxDepth(maybe_recurse, .{}, 3);2003 try s.tupleMaxDepth(maybe_recurse, .{}, 3);
2023 try std.testing.expectEqualStrings(".{.{ .r = .{} }}", buf.items);2004 try std.testing.expectEqualStrings(".{.{ .r = .{} }}", aw.getWritten());
2024 buf.clearRetainingCapacity();2005 aw.clearRetainingCapacity();
20252006
2026 try sz.tupleArbitraryDepth(maybe_recurse, .{});2007 try s.tupleArbitraryDepth(maybe_recurse, .{});
2027 try std.testing.expectEqualStrings(".{.{ .r = .{} }}", buf.items);2008 try std.testing.expectEqualStrings(".{.{ .r = .{} }}", aw.getWritten());
2028 buf.clearRetainingCapacity();2009 aw.clearRetainingCapacity();
2029 }2010 }
20302011
2031 // Max depth failing on recursive type due to recursion2012 // Max depth failing on recursive type due to recursion
...@@ -2036,46 +2017,46 @@ test "std.zon depth limits" {...@@ -2036,46 +2017,46 @@ test "std.zon depth limits" {
20362017
2037 try std.testing.expectError(2018 try std.testing.expectError(
2038 error.ExceededMaxDepth,2019 error.ExceededMaxDepth,
2039 serializeMaxDepth(maybe_recurse, .{}, buf.writer(), 128),2020 serializeMaxDepth(maybe_recurse, .{}, bw, 128),
2040 );2021 );
2041 try std.testing.expectEqualStrings("", buf.items);2022 try std.testing.expectEqualStrings("", aw.getWritten());
2042 buf.clearRetainingCapacity();2023 aw.clearRetainingCapacity();
20432024
2044 var sz = serializer(buf.writer(), .{});2025 var s: Serializer = .{ .writer = bw };
2045 try std.testing.expectError(2026 try std.testing.expectError(
2046 error.ExceededMaxDepth,2027 error.ExceededMaxDepth,
2047 sz.tupleMaxDepth(maybe_recurse, .{}, 128),2028 s.tupleMaxDepth(maybe_recurse, .{}, 128),
2048 );2029 );
2049 try std.testing.expectEqualStrings("", buf.items);2030 try std.testing.expectEqualStrings("", aw.getWritten());
2050 buf.clearRetainingCapacity();2031 aw.clearRetainingCapacity();
2051 }2032 }
20522033
2053 // Max depth on other parts of the lower level API2034 // Max depth on other parts of the lower level API
2054 {2035 {
2055 var sz = serializer(buf.writer(), .{});2036 var s: Serializer = .{ .writer = bw };
20562037
2057 const maybe_recurse: []const Recurse = &.{};2038 const maybe_recurse: []const Recurse = &.{};
20582039
2059 try std.testing.expectError(error.ExceededMaxDepth, sz.valueMaxDepth(1, .{}, 0));2040 try std.testing.expectError(error.ExceededMaxDepth, s.valueMaxDepth(1, .{}, 0));
2060 try sz.valueMaxDepth(2, .{}, 1);2041 try s.valueMaxDepth(2, .{}, 1);
2061 try sz.value(3, .{});2042 try s.value(3, .{});
2062 try sz.valueArbitraryDepth(maybe_recurse, .{});2043 try s.valueArbitraryDepth(maybe_recurse, .{});
20632044
2064 var s = try sz.beginStruct(.{});2045 var wip_struct = try s.beginStruct(.{});
2065 try std.testing.expectError(error.ExceededMaxDepth, s.fieldMaxDepth("a", 1, .{}, 0));2046 try std.testing.expectError(error.ExceededMaxDepth, wip_struct.fieldMaxDepth("a", 1, .{}, 0));
2066 try s.fieldMaxDepth("b", 4, .{}, 1);2047 try wip_struct.fieldMaxDepth("b", 4, .{}, 1);
2067 try s.field("c", 5, .{});2048 try wip_struct.field("c", 5, .{});
2068 try s.fieldArbitraryDepth("d", maybe_recurse, .{});2049 try wip_struct.fieldArbitraryDepth("d", maybe_recurse, .{});
2069 try s.end();2050 try wip_struct.end();
20702051
2071 var t = try sz.beginTuple(.{});2052 var t = try s.beginTuple(.{});
2072 try std.testing.expectError(error.ExceededMaxDepth, t.fieldMaxDepth(1, .{}, 0));2053 try std.testing.expectError(error.ExceededMaxDepth, t.fieldMaxDepth(1, .{}, 0));
2073 try t.fieldMaxDepth(6, .{}, 1);2054 try t.fieldMaxDepth(6, .{}, 1);
2074 try t.field(7, .{});2055 try t.field(7, .{});
2075 try t.fieldArbitraryDepth(maybe_recurse, .{});2056 try t.fieldArbitraryDepth(maybe_recurse, .{});
2076 try t.end();2057 try t.end();
20772058
2078 var a = try sz.beginTuple(.{});2059 var a = try s.beginTuple(.{});
2079 try std.testing.expectError(error.ExceededMaxDepth, a.fieldMaxDepth(1, .{}, 0));2060 try std.testing.expectError(error.ExceededMaxDepth, a.fieldMaxDepth(1, .{}, 0));
2080 try a.fieldMaxDepth(8, .{}, 1);2061 try a.fieldMaxDepth(8, .{}, 1);
2081 try a.field(9, .{});2062 try a.field(9, .{});
...@@ -2096,7 +2077,7 @@ test "std.zon depth limits" {...@@ -2096,7 +2077,7 @@ test "std.zon depth limits" {
2096 \\ 9,2077 \\ 9,
2097 \\ .{},2078 \\ .{},
2098 \\}2079 \\}
2099 , buf.items);2080 , aw.getWritten());
2100 }2081 }
2101}2082}
21022083
...@@ -2192,42 +2173,42 @@ test "std.zon stringify primitives" {...@@ -2192,42 +2173,42 @@ test "std.zon stringify primitives" {
2192}2173}
21932174
2194test "std.zon stringify ident" {2175test "std.zon stringify ident" {
2195 var buf = std.ArrayList(u8).init(std.testing.allocator);2176 var aw: Writer.Allocating = .init(std.testing.allocator);
2196 defer buf.deinit();2177 var s: Serializer = .{ .writer = &aw.writer };
2197 var sz = serializer(buf.writer(), .{});2178 defer aw.deinit();
21982179
2199 try expectSerializeEqual(".{ .a = 0 }", .{ .a = 0 }, .{});2180 try expectSerializeEqual(".{ .a = 0 }", .{ .a = 0 }, .{});
2200 try sz.ident("a");2181 try s.ident("a");
2201 try std.testing.expectEqualStrings(".a", buf.items);2182 try std.testing.expectEqualStrings(".a", aw.getWritten());
2202 buf.clearRetainingCapacity();2183 aw.clearRetainingCapacity();
22032184
2204 try sz.ident("foo_1");2185 try s.ident("foo_1");
2205 try std.testing.expectEqualStrings(".foo_1", buf.items);2186 try std.testing.expectEqualStrings(".foo_1", aw.getWritten());
2206 buf.clearRetainingCapacity();2187 aw.clearRetainingCapacity();
22072188
2208 try sz.ident("_foo_1");2189 try s.ident("_foo_1");
2209 try std.testing.expectEqualStrings("._foo_1", buf.items);2190 try std.testing.expectEqualStrings("._foo_1", aw.getWritten());
2210 buf.clearRetainingCapacity();2191 aw.clearRetainingCapacity();
22112192
2212 try sz.ident("foo bar");2193 try s.ident("foo bar");
2213 try std.testing.expectEqualStrings(".@\"foo bar\"", buf.items);2194 try std.testing.expectEqualStrings(".@\"foo bar\"", aw.getWritten());
2214 buf.clearRetainingCapacity();2195 aw.clearRetainingCapacity();
22152196
2216 try sz.ident("1foo");2197 try s.ident("1foo");
2217 try std.testing.expectEqualStrings(".@\"1foo\"", buf.items);2198 try std.testing.expectEqualStrings(".@\"1foo\"", aw.getWritten());
2218 buf.clearRetainingCapacity();2199 aw.clearRetainingCapacity();
22192200
2220 try sz.ident("var");2201 try s.ident("var");
2221 try std.testing.expectEqualStrings(".@\"var\"", buf.items);2202 try std.testing.expectEqualStrings(".@\"var\"", aw.getWritten());
2222 buf.clearRetainingCapacity();2203 aw.clearRetainingCapacity();
22232204
2224 try sz.ident("true");2205 try s.ident("true");
2225 try std.testing.expectEqualStrings(".true", buf.items);2206 try std.testing.expectEqualStrings(".true", aw.getWritten());
2226 buf.clearRetainingCapacity();2207 aw.clearRetainingCapacity();
22272208
2228 try sz.ident("_");2209 try s.ident("_");
2229 try std.testing.expectEqualStrings("._", buf.items);2210 try std.testing.expectEqualStrings("._", aw.getWritten());
2230 buf.clearRetainingCapacity();2211 aw.clearRetainingCapacity();
22312212
2232 const Enum = enum {2213 const Enum = enum {
2233 @"foo bar",2214 @"foo bar",
...@@ -2239,40 +2220,40 @@ test "std.zon stringify ident" {...@@ -2239,40 +2220,40 @@ test "std.zon stringify ident" {
2239}2220}
22402221
2241test "std.zon stringify as tuple" {2222test "std.zon stringify as tuple" {
2242 var buf = std.ArrayList(u8).init(std.testing.allocator);2223 var aw: Writer.Allocating = .init(std.testing.allocator);
2243 defer buf.deinit();2224 var s: Serializer = .{ .writer = &aw.writer };
2244 var sz = serializer(buf.writer(), .{});2225 defer aw.deinit();
22452226
2246 // Tuples2227 // Tuples
2247 try sz.tuple(.{ 1, 2 }, .{});2228 try s.tuple(.{ 1, 2 }, .{});
2248 try std.testing.expectEqualStrings(".{ 1, 2 }", buf.items);2229 try std.testing.expectEqualStrings(".{ 1, 2 }", aw.getWritten());
2249 buf.clearRetainingCapacity();2230 aw.clearRetainingCapacity();
22502231
2251 // Slice2232 // Slice
2252 try sz.tuple(@as([]const u8, &.{ 1, 2 }), .{});2233 try s.tuple(@as([]const u8, &.{ 1, 2 }), .{});
2253 try std.testing.expectEqualStrings(".{ 1, 2 }", buf.items);2234 try std.testing.expectEqualStrings(".{ 1, 2 }", aw.getWritten());
2254 buf.clearRetainingCapacity();2235 aw.clearRetainingCapacity();
22552236
2256 // Array2237 // Array
2257 try sz.tuple([2]u8{ 1, 2 }, .{});2238 try s.tuple([2]u8{ 1, 2 }, .{});
2258 try std.testing.expectEqualStrings(".{ 1, 2 }", buf.items);2239 try std.testing.expectEqualStrings(".{ 1, 2 }", aw.getWritten());
2259 buf.clearRetainingCapacity();2240 aw.clearRetainingCapacity();
2260}2241}
22612242
2262test "std.zon stringify as float" {2243test "std.zon stringify as float" {
2263 var buf = std.ArrayList(u8).init(std.testing.allocator);2244 var aw: Writer.Allocating = .init(std.testing.allocator);
2264 defer buf.deinit();2245 var s: Serializer = .{ .writer = &aw.writer };
2265 var sz = serializer(buf.writer(), .{});2246 defer aw.deinit();
22662247
2267 // Comptime float2248 // Comptime float
2268 try sz.float(2.5);2249 try s.float(2.5);
2269 try std.testing.expectEqualStrings("2.5", buf.items);2250 try std.testing.expectEqualStrings("2.5", aw.getWritten());
2270 buf.clearRetainingCapacity();2251 aw.clearRetainingCapacity();
22712252
2272 // Sized float2253 // Sized float
2273 try sz.float(@as(f32, 2.5));2254 try s.float(@as(f32, 2.5));
2274 try std.testing.expectEqualStrings("2.5", buf.items);2255 try std.testing.expectEqualStrings("2.5", aw.getWritten());
2275 buf.clearRetainingCapacity();2256 aw.clearRetainingCapacity();
2276}2257}
22772258
2278test "std.zon stringify vector" {2259test "std.zon stringify vector" {
...@@ -2364,13 +2345,13 @@ test "std.zon pointers" {...@@ -2364,13 +2345,13 @@ test "std.zon pointers" {
2364}2345}
23652346
2366test "std.zon tuple/struct field" {2347test "std.zon tuple/struct field" {
2367 var buf = std.ArrayList(u8).init(std.testing.allocator);2348 var aw: Writer.Allocating = .init(std.testing.allocator);
2368 defer buf.deinit();2349 var s: Serializer = .{ .writer = &aw.writer };
2369 var sz = serializer(buf.writer(), .{});2350 defer aw.deinit();
23702351
2371 // Test on structs2352 // Test on structs
2372 {2353 {
2373 var root = try sz.beginStruct(.{});2354 var root = try s.beginStruct(.{});
2374 {2355 {
2375 var tuple = try root.beginTupleField("foo", .{});2356 var tuple = try root.beginTupleField("foo", .{});
2376 try tuple.field(0, .{});2357 try tuple.field(0, .{});
...@@ -2396,13 +2377,13 @@ test "std.zon tuple/struct field" {...@@ -2396,13 +2377,13 @@ test "std.zon tuple/struct field" {
2396 \\ .b = 1,2377 \\ .b = 1,
2397 \\ },2378 \\ },
2398 \\}2379 \\}
2399 , buf.items);2380 , aw.getWritten());
2400 buf.clearRetainingCapacity();2381 aw.clearRetainingCapacity();
2401 }2382 }
24022383
2403 // Test on tuples2384 // Test on tuples
2404 {2385 {
2405 var root = try sz.beginTuple(.{});2386 var root = try s.beginTuple(.{});
2406 {2387 {
2407 var tuple = try root.beginTupleField(.{});2388 var tuple = try root.beginTupleField(.{});
2408 try tuple.field(0, .{});2389 try tuple.field(0, .{});
...@@ -2428,7 +2409,7 @@ test "std.zon tuple/struct field" {...@@ -2428,7 +2409,7 @@ test "std.zon tuple/struct field" {
2428 \\ .b = 1,2409 \\ .b = 1,
2429 \\ },2410 \\ },
2430 \\}2411 \\}
2431 , buf.items);2412 , aw.getWritten());
2432 buf.clearRetainingCapacity();2413 aw.clearRetainingCapacity();
2433 }2414 }
2434}2415}