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
161161 }
162162}
163163
164/// Deprecated, use double quoted escape to print paths.
164165pub fn fmtEscapeChar(path: Path) std.fmt.Formatter(Path, formatEscapeChar) {
165166 return .{ .data = path };
166167}
167168
169/// Deprecated, use double quoted escape to print paths.
168170pub fn formatEscapeChar(path: Path, writer: *std.io.Writer) std.io.Writer.Error!void {
169171 if (path.root_dir.path) |p| {
170 try std.zig.charEscape(p, writer);
171 if (path.sub_path.len > 0) try std.zig.charEscape(fs.path.sep_str, writer);
172 for (p) |byte| try std.zig.charEscape(byte, writer);
173 if (path.sub_path.len > 0) try writer.writeByte(fs.path.sep);
172174 }
173175 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);
175177 }
176178}
177179
lib/std/zig.zig+16-13
......@@ -446,8 +446,8 @@ pub fn fmtString(bytes: []const u8) std.fmt.Formatter([]const u8, stringEscape)
446446}
447447
448448/// Return a formatter for escaping a single quoted Zig string.
449pub fn fmtChar(bytes: []const u8) std.fmt.Formatter([]const u8, charEscape) {
450 return .{ .data = bytes };
449pub fn fmtChar(c: u21) std.fmt.Formatter(u21, charEscape) {
450 return .{ .data = c };
451451}
452452
453453test fmtString {
......@@ -458,9 +458,7 @@ test fmtString {
458458}
459459
460460test fmtChar {
461 try std.testing.expectFmt(
462 \\" \\ hi \x07 \x11 " derp \'"
463 , "\"{f}\"", .{fmtChar(" \\ hi \x07 \x11 \" derp '")});
461 try std.testing.expectFmt("c \\u{26a1}", "{f} {f}", .{ fmtChar('c'), fmtChar('⚡') });
464462}
465463
466464/// 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 {
480478 };
481479}
482480
483/// Print the string as escaped contents of a single-quoted string.
484pub fn charEscape(bytes: []const u8, w: *Writer) Writer.Error!void {
485 for (bytes) |byte| switch (byte) {
481/// Print as escaped contents of a single-quoted string.
482pub fn charEscape(codepoint: u21, w: *Writer) Writer.Error!void {
483 switch (codepoint) {
486484 '\n' => try w.writeAll("\\n"),
487485 '\r' => try w.writeAll("\\r"),
488486 '\t' => try w.writeAll("\\t"),
489487 '\\' => try w.writeAll("\\\\"),
490 '"' => try w.writeByte('"'),
491488 '\'' => try w.writeAll("\\'"),
492 ' ', '!', '#'...'&', '('...'[', ']'...'~' => try w.writeByte(byte),
489 '"', ' ', '!', '#'...'&', '('...'[', ']'...'~' => try w.writeByte(@intCast(codepoint)),
493490 else => {
494 try w.writeAll("\\x");
495 try w.printInt(byte, 16, .lower, .{ .width = 2, .fill = '0' });
491 if (std.math.cast(u8, codepoint)) |byte| {
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 }
496499 },
497 };
500 }
498501}
499502
500503pub 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
574574 '/' => "comment",
575575 else => unreachable,
576576 },
577 std.zig.fmtChar(tok_slice[parse_error.extra.offset..][0..1]),
577 std.zig.fmtChar(tok_slice[parse_error.extra.offset]),
578578 });
579579 },
580580
lib/std/zon/parse.zig+13-13
......@@ -64,14 +64,14 @@ pub const Error = union(enum) {
6464 }
6565 };
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 {
6868 // Just writes the string for now, but we're keeping this behind a formatter so we have
6969 // the option to extend it in the future to print more advanced messages (like `Error`
7070 // does) without breaking the API.
7171 try w.writeAll(self);
7272 }
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) {
7575 return .{ .data = switch (self) {
7676 .zoir => |note| note.msg.get(diag.zoir),
7777 .type_check => |note| note.msg,
......@@ -147,14 +147,14 @@ pub const Error = union(enum) {
147147 diag: *const Diagnostics,
148148 };
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 {
151151 switch (self.err) {
152152 .zoir => |err| try w.writeAll(err.msg.get(self.diag.zoir)),
153153 .type_check => |tc| try w.writeAll(tc.message),
154154 }
155155 }
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) {
158158 return .{ .data = .{
159159 .err = self,
160160 .diag = diag,
......@@ -226,7 +226,7 @@ pub const Diagnostics = struct {
226226 return .{ .diag = self };
227227 }
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 {
230230 var errors = self.iterateErrors();
231231 while (errors.next()) |err| {
232232 const loc = err.getLocation(self);
......@@ -606,7 +606,7 @@ const Parser = struct {
606606 }
607607 }
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 {
610610 switch (node.get(self.zoir)) {
611611 .string_literal => return self.parseString(T, node),
612612 .array_literal => |nodes| return self.parseSlice(T, nodes),
......@@ -1048,6 +1048,7 @@ const Parser = struct {
10481048 name: []const u8,
10491049 ) error{ OutOfMemory, ParseZon } {
10501050 @branchHint(.cold);
1051 const gpa = self.gpa;
10511052 const token = if (field) |f| b: {
10521053 var buf: [2]Ast.Node.Index = undefined;
10531054 const struct_init = self.ast.fullStructInit(&buf, node.getAstNode(self.zoir)).?;
......@@ -1065,13 +1066,12 @@ const Parser = struct {
10651066 };
10661067 } else b: {
10671068 const msg = "supported: ";
1068 var buf: std.ArrayListUnmanaged(u8) = try .initCapacity(self.gpa, 64);
1069 defer buf.deinit(self.gpa);
1070 const writer = buf.writer(self.gpa);
1071 try writer.writeAll(msg);
1069 var buf: std.ArrayListUnmanaged(u8) = try .initCapacity(gpa, 64);
1070 defer buf.deinit(gpa);
1071 try buf.appendSlice(gpa, msg);
10721072 inline for (info.fields, 0..) |field_info, i| {
1073 if (i != 0) try writer.writeAll(", ");
1074 try writer.print("'{f}'", .{std.zig.fmtIdFlags(field_info.name, .{
1073 if (i != 0) try buf.appendSlice(gpa, ", ");
1074 try buf.print(gpa, "'{f}'", .{std.zig.fmtIdFlags(field_info.name, .{
10751075 .allow_primitive = true,
10761076 .allow_underscore = true,
10771077 })});
......@@ -1079,7 +1079,7 @@ const Parser = struct {
10791079 break :b .{
10801080 .token = token,
10811081 .offset = 0,
1082 .msg = try buf.toOwnedSlice(self.gpa),
1082 .msg = try buf.toOwnedSlice(gpa),
10831083 .owned = true,
10841084 };
10851085 };
lib/std/zon/stringify.zig+924-943
......@@ -22,6 +22,7 @@
2222
2323const std = @import("std");
2424const assert = std.debug.assert;
25const Writer = std.Io.Writer;
2526
2627/// Options for `serialize`.
2728pub const SerializeOptions = struct {
......@@ -40,15 +41,12 @@ pub const SerializeOptions = struct {
4041/// Serialize the given value as ZON.
4142///
4243/// It is asserted at comptime that `@TypeOf(val)` is not a recursive type.
43pub fn serialize(
44 val: anytype,
45 options: SerializeOptions,
46 writer: anytype,
47) @TypeOf(writer).Error!void {
48 var sz = serializer(writer, .{
49 .whitespace = options.whitespace,
50 });
51 try sz.value(val, .{
44pub fn serialize(val: anytype, options: SerializeOptions, writer: *Writer) Writer.Error!void {
45 var s: Serializer = .{
46 .writer = writer,
47 .options = .{ .whitespace = options.whitespace },
48 };
49 try s.value(val, .{
5250 .emit_codepoint_literals = options.emit_codepoint_literals,
5351 .emit_strings_as_containers = options.emit_strings_as_containers,
5452 .emit_default_optional_fields = options.emit_default_optional_fields,
......@@ -62,13 +60,14 @@ pub fn serialize(
6260pub fn serializeMaxDepth(
6361 val: anytype,
6462 options: SerializeOptions,
65 writer: anytype,
63 writer: *Writer,
6664 depth: usize,
67) (@TypeOf(writer).Error || error{ExceededMaxDepth})!void {
68 var sz = serializer(writer, .{
69 .whitespace = options.whitespace,
70 });
71 try sz.valueMaxDepth(val, .{
65) Serializer.DepthError!void {
66 var s: Serializer = .{
67 .writer = writer,
68 .options = .{ .whitespace = options.whitespace },
69 };
70 try s.valueMaxDepth(val, .{
7271 .emit_codepoint_literals = options.emit_codepoint_literals,
7372 .emit_strings_as_containers = options.emit_strings_as_containers,
7473 .emit_default_optional_fields = options.emit_default_optional_fields,
......@@ -81,44 +80,45 @@ pub fn serializeMaxDepth(
8180pub fn serializeArbitraryDepth(
8281 val: anytype,
8382 options: SerializeOptions,
84 writer: anytype,
85) @TypeOf(writer).Error!void {
86 var sz = serializer(writer, .{
87 .whitespace = options.whitespace,
88 });
89 try sz.valueArbitraryDepth(val, .{
83 writer: *Writer,
84) Serializer.Error!void {
85 var s: Serializer = .{
86 .writer = writer,
87 .options = .{ .whitespace = options.whitespace },
88 };
89 try s.valueArbitraryDepth(val, .{
9090 .emit_codepoint_literals = options.emit_codepoint_literals,
9191 .emit_strings_as_containers = options.emit_strings_as_containers,
9292 .emit_default_optional_fields = options.emit_default_optional_fields,
9393 });
9494}
9595
96fn typeIsRecursive(comptime T: type) bool {
97 return comptime typeIsRecursiveImpl(T, &.{});
96inline fn typeIsRecursive(comptime T: type) bool {
97 return comptime typeIsRecursiveInner(T, &.{});
9898}
9999
100fn typeIsRecursiveImpl(comptime T: type, comptime prev_visited: []const type) bool {
100fn typeIsRecursiveInner(comptime T: type, comptime prev_visited: []const type) bool {
101101 for (prev_visited) |V| {
102102 if (V == T) return true;
103103 }
104104 const visited = prev_visited ++ .{T};
105105
106106 return switch (@typeInfo(T)) {
107 .pointer => |pointer| typeIsRecursiveImpl(pointer.child, visited),
108 .optional => |optional| typeIsRecursiveImpl(optional.child, visited),
109 .array => |array| typeIsRecursiveImpl(array.child, visited),
110 .vector => |vector| typeIsRecursiveImpl(vector.child, visited),
107 .pointer => |pointer| typeIsRecursiveInner(pointer.child, visited),
108 .optional => |optional| typeIsRecursiveInner(optional.child, visited),
109 .array => |array| typeIsRecursiveInner(array.child, visited),
110 .vector => |vector| typeIsRecursiveInner(vector.child, visited),
111111 .@"struct" => |@"struct"| for (@"struct".fields) |field| {
112 if (typeIsRecursiveImpl(field.type, visited)) break true;
112 if (typeIsRecursiveInner(field.type, visited)) break true;
113113 } else false,
114114 .@"union" => |@"union"| inline for (@"union".fields) |field| {
115 if (typeIsRecursiveImpl(field.type, visited)) break true;
115 if (typeIsRecursiveInner(field.type, visited)) break true;
116116 } else false,
117117 else => false,
118118 };
119119}
120120
121fn canSerializeType(T: type) bool {
121inline fn canSerializeType(T: type) bool {
122122 comptime return canSerializeTypeInner(T, &.{}, false);
123123}
124124
......@@ -343,12 +343,6 @@ test "std.zon checkValueDepth" {
343343 try expectValueDepthEquals(3, @as([]const []const u8, &.{&.{ 1, 2, 3 }}));
344344}
345345
346/// Options for `Serializer`.
347pub const SerializerOptions = struct {
348 /// If false, only syntactically necessary whitespace is emitted.
349 whitespace: bool = true,
350};
351
352346/// Determines when to emit Unicode code point literals as opposed to integer literals.
353347pub const EmitCodepointLiterals = enum {
354348 /// Never emit Unicode code point literals.
......@@ -440,634 +434,616 @@ pub const SerializeContainerOptions = struct {
440434/// For manual serialization of containers, see:
441435/// * `beginStruct`
442436/// * `beginTuple`
443///
444/// # Example
445/// ```zig
446/// var sz = serializer(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 }
437pub const Serializer = struct {
438 options: Options = .{},
439 indent_level: u8 = 0,
440 writer: *Writer,
469441
470 /// Serialize a value, similar to `serialize`.
471 pub fn value(self: *Self, val: anytype, options: ValueOptions) Writer.Error!void {
472 comptime assert(!typeIsRecursive(@TypeOf(val)));
473 return self.valueArbitraryDepth(val, options);
474 }
442 pub const Error = Writer.Error;
443 pub const DepthError = Error || error{ExceededMaxDepth};
475444
476 /// Serialize a value, similar to `serializeMaxDepth`.
477 pub fn valueMaxDepth(
478 self: *Self,
479 val: anytype,
480 options: ValueOptions,
481 depth: usize,
482 ) (Writer.Error || error{ExceededMaxDepth})!void {
483 try checkValueDepth(val, depth);
484 return self.valueArbitraryDepth(val, options);
485 }
445 pub const Options = struct {
446 /// If false, only syntactically necessary whitespace is emitted.
447 whitespace: bool = true,
448 };
486449
487 /// Serialize a value, similar to `serializeArbitraryDepth`.
488 pub fn valueArbitraryDepth(
489 self: *Self,
490 val: anytype,
491 options: ValueOptions,
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 }
450 /// Serialize a value, similar to `serialize`.
451 pub fn value(self: *Serializer, val: anytype, options: ValueOptions) Error!void {
452 comptime assert(!typeIsRecursive(@TypeOf(val)));
453 return self.valueArbitraryDepth(val, options);
454 }
519455
520 // Serialize as either a tuple or as the child type
521 switch (pointer.size) {
522 .slice => try self.tupleImpl(val, options),
523 .one => try self.valueArbitraryDepth(val.*, options),
524 else => comptime unreachable,
525 }
526 },
527 .array => {
528 var container = try self.beginTuple(
529 .{ .whitespace_style = .{ .fields = val.len } },
530 );
531 for (val) |item_val| {
532 try container.fieldArbitraryDepth(item_val, options);
533 }
534 try container.end();
535 },
536 .@"struct" => |@"struct"| if (@"struct".is_tuple) {
537 var container = try self.beginTuple(
538 .{ .whitespace_style = .{ .fields = @"struct".fields.len } },
539 );
540 inline for (val) |field_value| {
541 try container.fieldArbitraryDepth(field_value, options);
542 }
543 try container.end();
544 } else {
545 // Decide which fields to emit
546 const fields, const skipped: [@"struct".fields.len]bool = if (options.emit_default_optional_fields) b: {
547 break :b .{ @"struct".fields.len, @splat(false) };
548 } else b: {
549 var fields = @"struct".fields.len;
550 var skipped: [@"struct".fields.len]bool = @splat(false);
551 inline for (@"struct".fields, &skipped) |field_info, *skip| {
552 if (field_info.default_value_ptr) |ptr| {
553 const default: *const field_info.type = @ptrCast(@alignCast(ptr));
554 const field_value = @field(val, field_info.name);
555 if (std.meta.eql(field_value, default.*)) {
556 skip.* = true;
557 fields -= 1;
558 }
456 /// Serialize a value, similar to `serializeMaxDepth`.
457 /// Can return `error.ExceededMaxDepth`.
458 pub fn valueMaxDepth(self: *Serializer, val: anytype, options: ValueOptions, depth: usize) DepthError!void {
459 try checkValueDepth(val, depth);
460 return self.valueArbitraryDepth(val, options);
461 }
462
463 /// Serialize a value, similar to `serializeArbitraryDepth`.
464 pub fn valueArbitraryDepth(self: *Serializer, val: anytype, options: ValueOptions) Error!void {
465 comptime assert(canSerializeType(@TypeOf(val)));
466 switch (@typeInfo(@TypeOf(val))) {
467 .int, .comptime_int => if (options.emit_codepoint_literals.emitAsCodepoint(val)) |c| {
468 self.codePoint(c) catch |err| switch (err) {
469 error.InvalidCodepoint => unreachable, // Already validated
470 else => |e| return e,
471 };
472 } else {
473 try self.int(val);
474 },
475 .float, .comptime_float => try self.float(val),
476 .bool, .null => try self.writer.print("{}", .{val}),
477 .enum_literal => try self.ident(@tagName(val)),
478 .@"enum" => try self.ident(@tagName(val)),
479 .pointer => |pointer| {
480 // Try to serialize as a string
481 const item: ?type = switch (@typeInfo(pointer.child)) {
482 .array => |array| array.child,
483 else => if (pointer.size == .slice) pointer.child else null,
484 };
485 if (item == u8 and
486 (pointer.sentinel() == null or pointer.sentinel() == 0) and
487 !options.emit_strings_as_containers)
488 {
489 return try self.string(val);
490 }
491
492 // Serialize as either a tuple or as the child type
493 switch (pointer.size) {
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;
559530 }
560531 }
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 },
595532 }
596 },
597 .optional => if (val) |inner| {
598 try self.valueArbitraryDepth(inner, options);
599 } else {
600 try self.writer.writeAll("null");
601 },
602 .vector => |vector| {
603 var container = try self.beginTuple(
604 .{ .whitespace_style = .{ .fields = vector.len } },
605 );
606 for (0..vector.len) |i| {
607 try container.fieldArbitraryDepth(val[i], options);
533 break :b .{ fields, skipped };
534 };
535
536 // Emit those fields
537 var container = try self.beginStruct(
538 .{ .whitespace_style = .{ .fields = fields } },
539 );
540 inline for (@"struct".fields, skipped) |field_info, skip| {
541 if (!skip) {
542 try container.fieldArbitraryDepth(
543 field_info.name,
544 @field(val, field_info.name),
545 options,
546 );
608547 }
609 try container.end();
610 },
548 }
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,
613 }
584 else => comptime unreachable,
614585 }
586 }
615587
616 /// Serialize an integer.
617 pub fn int(self: *Self, val: anytype) Writer.Error!void {
618 //try self.writer.printInt(val, 10, .lower, .{});
619 try std.fmt.format(self.writer, "{d}", .{val});
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 }
588 /// Serialize an integer.
589 pub fn int(self: *Serializer, val: anytype) Error!void {
590 try self.writer.printInt(val, 10, .lower, .{});
591 }
644592
645 /// Serialize `name` as an identifier prefixed with `.`.
646 ///
647 /// Escapes the identifier if necessary.
648 pub fn ident(self: *Self, name: []const u8) Writer.Error!void {
649 try self.writer.print(".{f}", .{std.zig.fmtIdPU(name)});
593 /// Serialize a float.
594 pub fn float(self: *Serializer, val: anytype) Error!void {
595 switch (@typeInfo(@TypeOf(val))) {
596 .float => if (std.math.isNan(val)) {
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,
650613 }
614 }
651615
652 /// Serialize `val` as a Unicode codepoint.
653 ///
654 /// Returns `error.InvalidCodepoint` if `val` is not a valid Unicode codepoint.
655 pub fn codePoint(
656 self: *Self,
657 val: u21,
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 }
616 /// Serialize `name` as an identifier prefixed with `.`.
617 ///
618 /// Escapes the identifier if necessary.
619 pub fn ident(self: *Serializer, name: []const u8) Error!void {
620 try self.writer.print(".{f}", .{std.zig.fmtIdPU(name)});
621 }
672622
673 /// Like `tuple`, but recursive types are allowed.
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 }
623 pub const CodePointError = Error || error{InvalidCodepoint};
685624
686 /// Like `tuple`, but recursive types are allowed.
687 ///
688 /// It is the caller's responsibility to ensure that `val` does not contain cycles.
689 pub fn tupleArbitraryDepth(
690 self: *Self,
691 val: anytype,
692 options: ValueOptions,
693 ) Writer.Error!void {
694 try self.tupleImpl(val, options);
695 }
625 /// Serialize `val` as a Unicode codepoint.
626 ///
627 /// Returns `error.InvalidCodepoint` if `val` is not a valid Unicode codepoint.
628 pub fn codePoint(self: *Serializer, val: u21) CodePointError!void {
629 try self.writer.print("'{f}'", .{std.zig.fmtChar(val)});
630 }
696631
697 fn tupleImpl(self: *Self, val: anytype, options: ValueOptions) Writer.Error!void {
698 comptime assert(canSerializeType(@TypeOf(val)));
699 switch (@typeInfo(@TypeOf(val))) {
700 .@"struct" => {
701 var container = try self.beginTuple(.{ .whitespace_style = .{ .fields = val.len } });
702 inline for (val) |item_val| {
703 try container.fieldArbitraryDepth(item_val, options);
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 }
632 /// Like `value`, but always serializes `val` as a tuple.
633 ///
634 /// Will fail at comptime if `val` is not a tuple, array, pointer to an array, or slice.
635 pub fn tuple(self: *Serializer, val: anytype, options: ValueOptions) Error!void {
636 comptime assert(!typeIsRecursive(@TypeOf(val)));
637 try self.tupleArbitraryDepth(val, options);
638 }
717639
718 /// Like `value`, but always serializes `val` as a string.
719 pub fn string(self: *Self, val: []const u8) Writer.Error!void {
720 try std.fmt.format(self.writer, "\"{f}\"", .{std.zig.fmtString(val)});
721 }
640 /// Like `tuple`, but recursive types are allowed.
641 ///
642 /// Returns `error.ExceededMaxDepth` if `depth` is exceeded.
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.
724 pub const MultilineStringOptions = struct {
725 /// If top level is true, whitespace before and after the multiline string is elided.
726 /// If it is true, a newline is printed, then the value, followed by a newline, and if
727 /// whitespace is true any necessary indentation follows.
728 top_level: bool = false,
729 };
653 /// Like `tuple`, but recursive types are allowed.
654 ///
655 /// It is the caller's responsibility to ensure that `val` does not contain cycles.
656 pub fn tupleArbitraryDepth(
657 self: *Serializer,
658 val: anytype,
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.
732 ///
733 /// Returns `error.InnerCarriageReturn` if `val` contains a CR not followed by a newline,
734 /// since multiline strings cannot represent CR without a following newline.
735 pub fn multilineString(
736 self: *Self,
737 val: []const u8,
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;
664 fn tupleImpl(self: *Serializer, val: anytype, options: ValueOptions) Error!void {
665 comptime assert(canSerializeType(@TypeOf(val)));
666 switch (@typeInfo(@TypeOf(val))) {
667 .@"struct" => {
668 var container = try self.beginTuple(.{ .whitespace_style = .{ .fields = val.len } });
669 inline for (val) |item_val| {
670 try container.fieldArbitraryDepth(item_val, options);
751671 }
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) {
755 try self.newline();
756 try self.indent();
757 }
685 /// Like `value`, but always serializes `val` as a string.
686 pub fn string(self: *Serializer, val: []const u8) Error!void {
687 try self.writer.print("\"{f}\"", .{std.zig.fmtString(val)});
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("\\\\");
760 for (val) |c| {
761 if (c != '\r') {
762 try self.writer.writeByte(c); // We write newlines here even if whitespace off
763 if (c == '\n') {
764 try self.indent();
765 try self.writer.writeAll("\\\\");
698 pub const MultilineStringError = Error || error{InnerCarriageReturn};
699
700 /// Like `value`, but always serializes to a multiline string literal.
701 ///
702 /// Returns `error.InnerCarriageReturn` if `val` contains a CR not followed by a newline,
703 /// since multiline strings cannot represent CR without a following newline.
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;
766717 }
767718 }
719 return error.InnerCarriageReturn;
768720 }
721 }
769722
770 if (!options.top_level) {
771 try self.writer.writeByte('\n'); // Even if whitespace off
772 try self.indent();
773 }
723 if (!options.top_level) {
724 try self.newline();
725 try self.indent();
774726 }
775727
776 /// Create a `Struct` for writing ZON structs field by field.
777 pub fn beginStruct(
778 self: *Self,
779 options: SerializeContainerOptions,
780 ) Writer.Error!Struct {
781 return Struct.begin(self, options);
728 try self.writer.writeAll("\\\\");
729 for (val) |c| {
730 if (c != '\r') {
731 try self.writer.writeByte(c); // We write newlines here even if whitespace off
732 if (c == '\n') {
733 try self.indent();
734 try self.writer.writeAll("\\\\");
735 }
736 }
782737 }
783738
784 /// Creates a `Tuple` for writing ZON tuples field by field.
785 pub fn beginTuple(
786 self: *Self,
787 options: SerializeContainerOptions,
788 ) Writer.Error!Tuple {
789 return Tuple.begin(self, options);
739 if (!options.top_level) {
740 try self.writer.writeByte('\n'); // Even if whitespace off
741 try self.indent();
790742 }
743 }
791744
792 fn indent(self: *Self) Writer.Error!void {
793 if (self.options.whitespace) {
794 try self.writer.writeByteNTimes(' ', 4 * self.indent_level);
795 }
745 /// Create a `Struct` for writing ZON structs field by field.
746 pub fn beginStruct(
747 self: *Serializer,
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);
796764 }
765 }
797766
798 fn newline(self: *Self) Writer.Error!void {
799 if (self.options.whitespace) {
800 try self.writer.writeByte('\n');
801 }
767 fn newline(self: *Serializer) Error!void {
768 if (self.options.whitespace) {
769 try self.writer.writeByte('\n');
802770 }
771 }
803772
804 fn newlineOrSpace(self: *Self, len: usize) Writer.Error!void {
805 if (self.containerShouldWrap(len)) {
806 try self.newline();
807 } else {
808 try self.space();
809 }
773 fn newlineOrSpace(self: *Serializer, len: usize) Error!void {
774 if (self.containerShouldWrap(len)) {
775 try self.newline();
776 } else {
777 try self.space();
810778 }
779 }
811780
812 fn space(self: *Self) Writer.Error!void {
813 if (self.options.whitespace) {
814 try self.writer.writeByte(' ');
815 }
781 fn space(self: *Serializer) Error!void {
782 if (self.options.whitespace) {
783 try self.writer.writeByte(' ');
816784 }
785 }
817786
818 /// Writes ZON tuples field by field.
819 pub const Tuple = struct {
820 container: Container,
787 /// Writes ZON tuples field by field.
788 pub const Tuple = struct {
789 container: Container,
821790
822 fn begin(parent: *Self, options: SerializeContainerOptions) Writer.Error!Tuple {
823 return .{
824 .container = try Container.begin(parent, .anon, options),
825 };
826 }
791 fn begin(parent: *Serializer, options: SerializeContainerOptions) Error!Tuple {
792 return .{
793 .container = try Container.begin(parent, .anon, options),
794 };
795 }
827796
828 /// Finishes serializing the tuple.
829 ///
830 /// Prints a trailing comma as configured when appropriate, and the closing bracket.
831 pub fn end(self: *Tuple) Writer.Error!void {
832 try self.container.end();
833 self.* = undefined;
834 }
797 /// Finishes serializing the tuple.
798 ///
799 /// Prints a trailing comma as configured when appropriate, and the closing bracket.
800 pub fn end(self: *Tuple) Error!void {
801 try self.container.end();
802 self.* = undefined;
803 }
835804
836 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `value`.
837 pub fn field(
838 self: *Tuple,
839 val: anytype,
840 options: ValueOptions,
841 ) Writer.Error!void {
842 try self.container.field(null, val, options);
843 }
805 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `value`.
806 pub fn field(
807 self: *Tuple,
808 val: anytype,
809 options: ValueOptions,
810 ) Error!void {
811 try self.container.field(null, val, options);
812 }
844813
845 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `valueMaxDepth`.
846 pub fn fieldMaxDepth(
847 self: *Tuple,
848 val: anytype,
849 options: ValueOptions,
850 depth: usize,
851 ) (Writer.Error || error{ExceededMaxDepth})!void {
852 try self.container.fieldMaxDepth(null, val, options, depth);
853 }
814 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `valueMaxDepth`.
815 /// Returns `error.ExceededMaxDepth` if `depth` is exceeded.
816 pub fn fieldMaxDepth(
817 self: *Tuple,
818 val: anytype,
819 options: ValueOptions,
820 depth: usize,
821 ) DepthError!void {
822 try self.container.fieldMaxDepth(null, val, options, depth);
823 }
854824
855 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by
856 /// `valueArbitraryDepth`.
857 pub fn fieldArbitraryDepth(
858 self: *Tuple,
859 val: anytype,
860 options: ValueOptions,
861 ) Writer.Error!void {
862 try self.container.fieldArbitraryDepth(null, val, options);
863 }
825 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by
826 /// `valueArbitraryDepth`.
827 pub fn fieldArbitraryDepth(
828 self: *Tuple,
829 val: anytype,
830 options: ValueOptions,
831 ) Error!void {
832 try self.container.fieldArbitraryDepth(null, val, options);
833 }
864834
865 /// Starts a field with a struct as a value. Returns the struct.
866 pub fn beginStructField(
867 self: *Tuple,
868 options: SerializeContainerOptions,
869 ) Writer.Error!Struct {
870 try self.fieldPrefix();
871 return self.container.serializer.beginStruct(options);
872 }
835 /// Starts a field with a struct as a value. Returns the struct.
836 pub fn beginStructField(
837 self: *Tuple,
838 options: SerializeContainerOptions,
839 ) Error!Struct {
840 try self.fieldPrefix();
841 return self.container.serializer.beginStruct(options);
842 }
873843
874 /// Starts a field with a tuple as a value. Returns the tuple.
875 pub fn beginTupleField(
876 self: *Tuple,
877 options: SerializeContainerOptions,
878 ) Writer.Error!Tuple {
879 try self.fieldPrefix();
880 return self.container.serializer.beginTuple(options);
881 }
844 /// Starts a field with a tuple as a value. Returns the tuple.
845 pub fn beginTupleField(
846 self: *Tuple,
847 options: SerializeContainerOptions,
848 ) Error!Tuple {
849 try self.fieldPrefix();
850 return self.container.serializer.beginTuple(options);
851 }
882852
883 /// Print a field prefix. This prints any necessary commas, and whitespace as
884 /// configured. Useful if you want to serialize the field value yourself.
885 pub fn fieldPrefix(self: *Tuple) Writer.Error!void {
886 try self.container.fieldPrefix(null);
887 }
888 };
853 /// Print a field prefix. This prints any necessary commas, and whitespace as
854 /// configured. Useful if you want to serialize the field value yourself.
855 pub fn fieldPrefix(self: *Tuple) Error!void {
856 try self.container.fieldPrefix(null);
857 }
858 };
889859
890 /// Writes ZON structs field by field.
891 pub const Struct = struct {
892 container: Container,
860 /// Writes ZON structs field by field.
861 pub const Struct = struct {
862 container: Container,
893863
894 fn begin(parent: *Self, options: SerializeContainerOptions) Writer.Error!Struct {
895 return .{
896 .container = try Container.begin(parent, .named, options),
897 };
898 }
864 fn begin(parent: *Serializer, options: SerializeContainerOptions) Error!Struct {
865 return .{
866 .container = try Container.begin(parent, .named, options),
867 };
868 }
899869
900 /// Finishes serializing the struct.
901 ///
902 /// Prints a trailing comma as configured when appropriate, and the closing bracket.
903 pub fn end(self: *Struct) Writer.Error!void {
904 try self.container.end();
905 self.* = undefined;
906 }
870 /// Finishes serializing the struct.
871 ///
872 /// Prints a trailing comma as configured when appropriate, and the closing bracket.
873 pub fn end(self: *Struct) Error!void {
874 try self.container.end();
875 self.* = undefined;
876 }
907877
908 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `value`.
909 pub fn field(
910 self: *Struct,
911 name: []const u8,
912 val: anytype,
913 options: ValueOptions,
914 ) Writer.Error!void {
915 try self.container.field(name, val, options);
916 }
878 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `value`.
879 pub fn field(
880 self: *Struct,
881 name: []const u8,
882 val: anytype,
883 options: ValueOptions,
884 ) Error!void {
885 try self.container.field(name, val, options);
886 }
917887
918 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `valueMaxDepth`.
919 pub fn fieldMaxDepth(
920 self: *Struct,
921 name: []const u8,
922 val: anytype,
923 options: ValueOptions,
924 depth: usize,
925 ) (Writer.Error || error{ExceededMaxDepth})!void {
926 try self.container.fieldMaxDepth(name, val, options, depth);
927 }
888 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by `valueMaxDepth`.
889 /// Returns `error.ExceededMaxDepth` if `depth` is exceeded.
890 pub fn fieldMaxDepth(
891 self: *Struct,
892 name: []const u8,
893 val: anytype,
894 options: ValueOptions,
895 depth: usize,
896 ) DepthError!void {
897 try self.container.fieldMaxDepth(name, val, options, depth);
898 }
928899
929 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by
930 /// `valueArbitraryDepth`.
931 pub fn fieldArbitraryDepth(
932 self: *Struct,
933 name: []const u8,
934 val: anytype,
935 options: ValueOptions,
936 ) Writer.Error!void {
937 try self.container.fieldArbitraryDepth(name, val, options);
938 }
900 /// Serialize a field. Equivalent to calling `fieldPrefix` followed by
901 /// `valueArbitraryDepth`.
902 pub fn fieldArbitraryDepth(
903 self: *Struct,
904 name: []const u8,
905 val: anytype,
906 options: ValueOptions,
907 ) Error!void {
908 try self.container.fieldArbitraryDepth(name, val, options);
909 }
939910
940 /// Starts a field with a struct as a value. Returns the struct.
941 pub fn beginStructField(
942 self: *Struct,
943 name: []const u8,
944 options: SerializeContainerOptions,
945 ) Writer.Error!Struct {
946 try self.fieldPrefix(name);
947 return self.container.serializer.beginStruct(options);
948 }
911 /// Starts a field with a struct as a value. Returns the struct.
912 pub fn beginStructField(
913 self: *Struct,
914 name: []const u8,
915 options: SerializeContainerOptions,
916 ) Error!Struct {
917 try self.fieldPrefix(name);
918 return self.container.serializer.beginStruct(options);
919 }
949920
950 /// Starts a field with a tuple as a value. Returns the tuple.
951 pub fn beginTupleField(
952 self: *Struct,
953 name: []const u8,
954 options: SerializeContainerOptions,
955 ) Writer.Error!Tuple {
956 try self.fieldPrefix(name);
957 return self.container.serializer.beginTuple(options);
958 }
921 /// Starts a field with a tuple as a value. Returns the tuple.
922 pub fn beginTupleField(
923 self: *Struct,
924 name: []const u8,
925 options: SerializeContainerOptions,
926 ) Error!Tuple {
927 try self.fieldPrefix(name);
928 return self.container.serializer.beginTuple(options);
929 }
959930
960 /// 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 field
962 /// value yourself.
963 pub fn fieldPrefix(self: *Struct, name: []const u8) Writer.Error!void {
964 try self.container.fieldPrefix(name);
965 }
966 };
931 /// Print a field prefix. This prints any necessary commas, the field name (escaped if
932 /// necessary) and whitespace as configured. Useful if you want to serialize the field
933 /// value yourself.
934 pub fn fieldPrefix(self: *Struct, name: []const u8) Error!void {
935 try self.container.fieldPrefix(name);
936 }
937 };
967938
968 const Container = struct {
969 const FieldStyle = enum { named, anon };
939 const Container = struct {
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,
972949 field_style: FieldStyle,
973950 options: SerializeContainerOptions,
974 empty: bool,
975
976 fn begin(
977 sz: *Self,
978 field_style: FieldStyle,
979 options: SerializeContainerOptions,
980 ) Writer.Error!Container {
981 if (options.shouldWrap()) sz.indent_level +|= 1;
982 try sz.writer.writeAll(".{");
983 return .{
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 }
951 ) Error!Container {
952 if (options.shouldWrap()) sz.indent_level +|= 1;
953 try sz.writer.writeAll(".{");
954 return .{
955 .serializer = sz,
956 .field_style = field_style,
957 .options = options,
958 .empty = true,
959 };
960 }
1007961
1008 fn fieldPrefix(self: *Container, name: ?[]const u8) Writer.Error!void {
1009 if (!self.empty) {
1010 try self.serializer.writer.writeByte(',');
1011 }
1012 self.empty = false;
962 fn end(self: *Container) Error!void {
963 if (self.options.shouldWrap()) self.serializer.indent_level -|= 1;
964 if (!self.empty) {
1013965 if (self.options.shouldWrap()) {
966 if (self.serializer.options.whitespace) {
967 try self.serializer.writer.writeByte(',');
968 }
1014969 try self.serializer.newline();
970 try self.serializer.indent();
1015971 } else if (!self.shouldElideSpaces()) {
1016972 try self.serializer.space();
1017973 }
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 }
1025974 }
975 try self.serializer.writer.writeByte('}');
976 self.* = undefined;
977 }
1026978
1027 fn field(
1028 self: *Container,
1029 name: ?[]const u8,
1030 val: anytype,
1031 options: ValueOptions,
1032 ) Writer.Error!void {
1033 comptime assert(!typeIsRecursive(@TypeOf(val)));
1034 try self.fieldArbitraryDepth(name, val, options);
979 fn fieldPrefix(self: *Container, name: ?[]const u8) Error!void {
980 if (!self.empty) {
981 try self.serializer.writer.writeByte(',');
1035982 }
1036
1037 fn fieldMaxDepth(
1038 self: *Container,
1039 name: ?[]const u8,
1040 val: anytype,
1041 options: ValueOptions,
1042 depth: usize,
1043 ) (Writer.Error || error{ExceededMaxDepth})!void {
1044 try checkValueDepth(val, depth);
1045 try self.fieldArbitraryDepth(name, val, options);
983 self.empty = false;
984 if (self.options.shouldWrap()) {
985 try self.serializer.newline();
986 } else if (!self.shouldElideSpaces()) {
987 try self.serializer.space();
1046988 }
1047
1048 fn fieldArbitraryDepth(
1049 self: *Container,
1050 name: ?[]const u8,
1051 val: anytype,
1052 options: ValueOptions,
1053 ) Writer.Error!void {
1054 try self.fieldPrefix(name);
1055 try self.serializer.valueArbitraryDepth(val, options);
989 if (self.options.shouldWrap()) try self.serializer.indent();
990 if (name) |n| {
991 try self.serializer.ident(n);
992 try self.serializer.space();
993 try self.serializer.writer.writeByte('=');
994 try self.serializer.space();
1056995 }
996 }
1057997
1058 fn shouldElideSpaces(self: *const Container) bool {
1059 return switch (self.options.whitespace_style) {
1060 .fields => |fields| self.field_style != .named and fields == 1,
1061 else => false,
1062 };
1063 }
1064 };
998 fn field(
999 self: *Container,
1000 name: ?[]const u8,
1001 val: anytype,
1002 options: ValueOptions,
1003 ) Error!void {
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 }
10651036 };
1066}
1037};
10671038
1068/// Creates a new `Serializer` with the given writer and options.
1069pub fn serializer(writer: anytype, options: SerializerOptions) Serializer(@TypeOf(writer)) {
1070 return .init(writer, options);
1039test Serializer {
1040 var discarding: Writer.Discarding = .init(&.{});
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();
10711047}
10721048
10731049fn expectSerializeEqual(
......@@ -1075,10 +1051,12 @@ fn expectSerializeEqual(
10751051 value: anytype,
10761052 options: SerializeOptions,
10771053) !void {
1078 var buf = std.ArrayList(u8).init(std.testing.allocator);
1079 defer buf.deinit();
1080 try serialize(value, options, buf.writer());
1081 try std.testing.expectEqualStrings(expected, buf.items);
1054 var aw: Writer.Allocating = .init(std.testing.allocator);
1055 const bw = &aw.writer;
1056 defer aw.deinit();
1057
1058 try serialize(value, options, bw);
1059 try std.testing.expectEqualStrings(expected, aw.getWritten());
10821060}
10831061
10841062test "std.zon stringify whitespace, high level API" {
......@@ -1175,59 +1153,59 @@ test "std.zon stringify whitespace, high level API" {
11751153}
11761154
11771155test "std.zon stringify whitespace, low level API" {
1178 var buf = std.ArrayList(u8).init(std.testing.allocator);
1179 defer buf.deinit();
1180 var sz = serializer(buf.writer(), .{});
1156 var aw: Writer.Allocating = .init(std.testing.allocator);
1157 var s: Serializer = .{ .writer = &aw.writer };
1158 defer aw.deinit();
11811159
1182 inline for (.{ true, false }) |whitespace| {
1183 sz.options = .{ .whitespace = whitespace };
1160 for ([2]bool{ true, false }) |whitespace| {
1161 s.options = .{ .whitespace = whitespace };
11841162
11851163 // Empty containers
11861164 {
1187 var container = try sz.beginStruct(.{});
1165 var container = try s.beginStruct(.{});
11881166 try container.end();
1189 try std.testing.expectEqualStrings(".{}", buf.items);
1190 buf.clearRetainingCapacity();
1167 try std.testing.expectEqualStrings(".{}", aw.getWritten());
1168 aw.clearRetainingCapacity();
11911169 }
11921170
11931171 {
1194 var container = try sz.beginTuple(.{});
1172 var container = try s.beginTuple(.{});
11951173 try container.end();
1196 try std.testing.expectEqualStrings(".{}", buf.items);
1197 buf.clearRetainingCapacity();
1174 try std.testing.expectEqualStrings(".{}", aw.getWritten());
1175 aw.clearRetainingCapacity();
11981176 }
11991177
12001178 {
1201 var container = try sz.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
1179 var container = try s.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
12021180 try container.end();
1203 try std.testing.expectEqualStrings(".{}", buf.items);
1204 buf.clearRetainingCapacity();
1181 try std.testing.expectEqualStrings(".{}", aw.getWritten());
1182 aw.clearRetainingCapacity();
12051183 }
12061184
12071185 {
1208 var container = try sz.beginTuple(.{ .whitespace_style = .{ .wrap = false } });
1186 var container = try s.beginTuple(.{ .whitespace_style = .{ .wrap = false } });
12091187 try container.end();
1210 try std.testing.expectEqualStrings(".{}", buf.items);
1211 buf.clearRetainingCapacity();
1188 try std.testing.expectEqualStrings(".{}", aw.getWritten());
1189 aw.clearRetainingCapacity();
12121190 }
12131191
12141192 {
1215 var container = try sz.beginStruct(.{ .whitespace_style = .{ .fields = 0 } });
1193 var container = try s.beginStruct(.{ .whitespace_style = .{ .fields = 0 } });
12161194 try container.end();
1217 try std.testing.expectEqualStrings(".{}", buf.items);
1218 buf.clearRetainingCapacity();
1195 try std.testing.expectEqualStrings(".{}", aw.getWritten());
1196 aw.clearRetainingCapacity();
12191197 }
12201198
12211199 {
1222 var container = try sz.beginTuple(.{ .whitespace_style = .{ .fields = 0 } });
1200 var container = try s.beginTuple(.{ .whitespace_style = .{ .fields = 0 } });
12231201 try container.end();
1224 try std.testing.expectEqualStrings(".{}", buf.items);
1225 buf.clearRetainingCapacity();
1202 try std.testing.expectEqualStrings(".{}", aw.getWritten());
1203 aw.clearRetainingCapacity();
12261204 }
12271205
12281206 // Size 1
12291207 {
1230 var container = try sz.beginStruct(.{});
1208 var container = try s.beginStruct(.{});
12311209 try container.field("a", 1, .{});
12321210 try container.end();
12331211 if (whitespace) {
......@@ -1235,15 +1213,15 @@ test "std.zon stringify whitespace, low level API" {
12351213 \\.{
12361214 \\ .a = 1,
12371215 \\}
1238 , buf.items);
1216 , aw.getWritten());
12391217 } else {
1240 try std.testing.expectEqualStrings(".{.a=1}", buf.items);
1218 try std.testing.expectEqualStrings(".{.a=1}", aw.getWritten());
12411219 }
1242 buf.clearRetainingCapacity();
1220 aw.clearRetainingCapacity();
12431221 }
12441222
12451223 {
1246 var container = try sz.beginTuple(.{});
1224 var container = try s.beginTuple(.{});
12471225 try container.field(1, .{});
12481226 try container.end();
12491227 if (whitespace) {
......@@ -1251,62 +1229,62 @@ test "std.zon stringify whitespace, low level API" {
12511229 \\.{
12521230 \\ 1,
12531231 \\}
1254 , buf.items);
1232 , aw.getWritten());
12551233 } else {
1256 try std.testing.expectEqualStrings(".{1}", buf.items);
1234 try std.testing.expectEqualStrings(".{1}", aw.getWritten());
12571235 }
1258 buf.clearRetainingCapacity();
1236 aw.clearRetainingCapacity();
12591237 }
12601238
12611239 {
1262 var container = try sz.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
1240 var container = try s.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
12631241 try container.field("a", 1, .{});
12641242 try container.end();
12651243 if (whitespace) {
1266 try std.testing.expectEqualStrings(".{ .a = 1 }", buf.items);
1244 try std.testing.expectEqualStrings(".{ .a = 1 }", aw.getWritten());
12671245 } else {
1268 try std.testing.expectEqualStrings(".{.a=1}", buf.items);
1246 try std.testing.expectEqualStrings(".{.a=1}", aw.getWritten());
12691247 }
1270 buf.clearRetainingCapacity();
1248 aw.clearRetainingCapacity();
12711249 }
12721250
12731251 {
12741252 // We get extra spaces here, since we didn't know up front that there would only be one
12751253 // field.
1276 var container = try sz.beginTuple(.{ .whitespace_style = .{ .wrap = false } });
1254 var container = try s.beginTuple(.{ .whitespace_style = .{ .wrap = false } });
12771255 try container.field(1, .{});
12781256 try container.end();
12791257 if (whitespace) {
1280 try std.testing.expectEqualStrings(".{ 1 }", buf.items);
1258 try std.testing.expectEqualStrings(".{ 1 }", aw.getWritten());
12811259 } else {
1282 try std.testing.expectEqualStrings(".{1}", buf.items);
1260 try std.testing.expectEqualStrings(".{1}", aw.getWritten());
12831261 }
1284 buf.clearRetainingCapacity();
1262 aw.clearRetainingCapacity();
12851263 }
12861264
12871265 {
1288 var container = try sz.beginStruct(.{ .whitespace_style = .{ .fields = 1 } });
1266 var container = try s.beginStruct(.{ .whitespace_style = .{ .fields = 1 } });
12891267 try container.field("a", 1, .{});
12901268 try container.end();
12911269 if (whitespace) {
1292 try std.testing.expectEqualStrings(".{ .a = 1 }", buf.items);
1270 try std.testing.expectEqualStrings(".{ .a = 1 }", aw.getWritten());
12931271 } else {
1294 try std.testing.expectEqualStrings(".{.a=1}", buf.items);
1272 try std.testing.expectEqualStrings(".{.a=1}", aw.getWritten());
12951273 }
1296 buf.clearRetainingCapacity();
1274 aw.clearRetainingCapacity();
12971275 }
12981276
12991277 {
1300 var container = try sz.beginTuple(.{ .whitespace_style = .{ .fields = 1 } });
1278 var container = try s.beginTuple(.{ .whitespace_style = .{ .fields = 1 } });
13011279 try container.field(1, .{});
13021280 try container.end();
1303 try std.testing.expectEqualStrings(".{1}", buf.items);
1304 buf.clearRetainingCapacity();
1281 try std.testing.expectEqualStrings(".{1}", aw.getWritten());
1282 aw.clearRetainingCapacity();
13051283 }
13061284
13071285 // Size 2
13081286 {
1309 var container = try sz.beginStruct(.{});
1287 var container = try s.beginStruct(.{});
13101288 try container.field("a", 1, .{});
13111289 try container.field("b", 2, .{});
13121290 try container.end();
......@@ -1316,15 +1294,15 @@ test "std.zon stringify whitespace, low level API" {
13161294 \\ .a = 1,
13171295 \\ .b = 2,
13181296 \\}
1319 , buf.items);
1297 , aw.getWritten());
13201298 } else {
1321 try std.testing.expectEqualStrings(".{.a=1,.b=2}", buf.items);
1299 try std.testing.expectEqualStrings(".{.a=1,.b=2}", aw.getWritten());
13221300 }
1323 buf.clearRetainingCapacity();
1301 aw.clearRetainingCapacity();
13241302 }
13251303
13261304 {
1327 var container = try sz.beginTuple(.{});
1305 var container = try s.beginTuple(.{});
13281306 try container.field(1, .{});
13291307 try container.field(2, .{});
13301308 try container.end();
......@@ -1334,68 +1312,68 @@ test "std.zon stringify whitespace, low level API" {
13341312 \\ 1,
13351313 \\ 2,
13361314 \\}
1337 , buf.items);
1315 , aw.getWritten());
13381316 } else {
1339 try std.testing.expectEqualStrings(".{1,2}", buf.items);
1317 try std.testing.expectEqualStrings(".{1,2}", aw.getWritten());
13401318 }
1341 buf.clearRetainingCapacity();
1319 aw.clearRetainingCapacity();
13421320 }
13431321
13441322 {
1345 var container = try sz.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
1323 var container = try s.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
13461324 try container.field("a", 1, .{});
13471325 try container.field("b", 2, .{});
13481326 try container.end();
13491327 if (whitespace) {
1350 try std.testing.expectEqualStrings(".{ .a = 1, .b = 2 }", buf.items);
1328 try std.testing.expectEqualStrings(".{ .a = 1, .b = 2 }", aw.getWritten());
13511329 } else {
1352 try std.testing.expectEqualStrings(".{.a=1,.b=2}", buf.items);
1330 try std.testing.expectEqualStrings(".{.a=1,.b=2}", aw.getWritten());
13531331 }
1354 buf.clearRetainingCapacity();
1332 aw.clearRetainingCapacity();
13551333 }
13561334
13571335 {
1358 var container = try sz.beginTuple(.{ .whitespace_style = .{ .wrap = false } });
1336 var container = try s.beginTuple(.{ .whitespace_style = .{ .wrap = false } });
13591337 try container.field(1, .{});
13601338 try container.field(2, .{});
13611339 try container.end();
13621340 if (whitespace) {
1363 try std.testing.expectEqualStrings(".{ 1, 2 }", buf.items);
1341 try std.testing.expectEqualStrings(".{ 1, 2 }", aw.getWritten());
13641342 } else {
1365 try std.testing.expectEqualStrings(".{1,2}", buf.items);
1343 try std.testing.expectEqualStrings(".{1,2}", aw.getWritten());
13661344 }
1367 buf.clearRetainingCapacity();
1345 aw.clearRetainingCapacity();
13681346 }
13691347
13701348 {
1371 var container = try sz.beginStruct(.{ .whitespace_style = .{ .fields = 2 } });
1349 var container = try s.beginStruct(.{ .whitespace_style = .{ .fields = 2 } });
13721350 try container.field("a", 1, .{});
13731351 try container.field("b", 2, .{});
13741352 try container.end();
13751353 if (whitespace) {
1376 try std.testing.expectEqualStrings(".{ .a = 1, .b = 2 }", buf.items);
1354 try std.testing.expectEqualStrings(".{ .a = 1, .b = 2 }", aw.getWritten());
13771355 } else {
1378 try std.testing.expectEqualStrings(".{.a=1,.b=2}", buf.items);
1356 try std.testing.expectEqualStrings(".{.a=1,.b=2}", aw.getWritten());
13791357 }
1380 buf.clearRetainingCapacity();
1358 aw.clearRetainingCapacity();
13811359 }
13821360
13831361 {
1384 var container = try sz.beginTuple(.{ .whitespace_style = .{ .fields = 2 } });
1362 var container = try s.beginTuple(.{ .whitespace_style = .{ .fields = 2 } });
13851363 try container.field(1, .{});
13861364 try container.field(2, .{});
13871365 try container.end();
13881366 if (whitespace) {
1389 try std.testing.expectEqualStrings(".{ 1, 2 }", buf.items);
1367 try std.testing.expectEqualStrings(".{ 1, 2 }", aw.getWritten());
13901368 } else {
1391 try std.testing.expectEqualStrings(".{1,2}", buf.items);
1369 try std.testing.expectEqualStrings(".{1,2}", aw.getWritten());
13921370 }
1393 buf.clearRetainingCapacity();
1371 aw.clearRetainingCapacity();
13941372 }
13951373
13961374 // Size 3
13971375 {
1398 var container = try sz.beginStruct(.{});
1376 var container = try s.beginStruct(.{});
13991377 try container.field("a", 1, .{});
14001378 try container.field("b", 2, .{});
14011379 try container.field("c", 3, .{});
......@@ -1407,15 +1385,15 @@ test "std.zon stringify whitespace, low level API" {
14071385 \\ .b = 2,
14081386 \\ .c = 3,
14091387 \\}
1410 , buf.items);
1388 , aw.getWritten());
14111389 } 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());
14131391 }
1414 buf.clearRetainingCapacity();
1392 aw.clearRetainingCapacity();
14151393 }
14161394
14171395 {
1418 var container = try sz.beginTuple(.{});
1396 var container = try s.beginTuple(.{});
14191397 try container.field(1, .{});
14201398 try container.field(2, .{});
14211399 try container.field(3, .{});
......@@ -1427,43 +1405,43 @@ test "std.zon stringify whitespace, low level API" {
14271405 \\ 2,
14281406 \\ 3,
14291407 \\}
1430 , buf.items);
1408 , aw.getWritten());
14311409 } else {
1432 try std.testing.expectEqualStrings(".{1,2,3}", buf.items);
1410 try std.testing.expectEqualStrings(".{1,2,3}", aw.getWritten());
14331411 }
1434 buf.clearRetainingCapacity();
1412 aw.clearRetainingCapacity();
14351413 }
14361414
14371415 {
1438 var container = try sz.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
1416 var container = try s.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
14391417 try container.field("a", 1, .{});
14401418 try container.field("b", 2, .{});
14411419 try container.field("c", 3, .{});
14421420 try container.end();
14431421 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());
14451423 } 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());
14471425 }
1448 buf.clearRetainingCapacity();
1426 aw.clearRetainingCapacity();
14491427 }
14501428
14511429 {
1452 var container = try sz.beginTuple(.{ .whitespace_style = .{ .wrap = false } });
1430 var container = try s.beginTuple(.{ .whitespace_style = .{ .wrap = false } });
14531431 try container.field(1, .{});
14541432 try container.field(2, .{});
14551433 try container.field(3, .{});
14561434 try container.end();
14571435 if (whitespace) {
1458 try std.testing.expectEqualStrings(".{ 1, 2, 3 }", buf.items);
1436 try std.testing.expectEqualStrings(".{ 1, 2, 3 }", aw.getWritten());
14591437 } else {
1460 try std.testing.expectEqualStrings(".{1,2,3}", buf.items);
1438 try std.testing.expectEqualStrings(".{1,2,3}", aw.getWritten());
14611439 }
1462 buf.clearRetainingCapacity();
1440 aw.clearRetainingCapacity();
14631441 }
14641442
14651443 {
1466 var container = try sz.beginStruct(.{ .whitespace_style = .{ .fields = 3 } });
1444 var container = try s.beginStruct(.{ .whitespace_style = .{ .fields = 3 } });
14671445 try container.field("a", 1, .{});
14681446 try container.field("b", 2, .{});
14691447 try container.field("c", 3, .{});
......@@ -1475,15 +1453,15 @@ test "std.zon stringify whitespace, low level API" {
14751453 \\ .b = 2,
14761454 \\ .c = 3,
14771455 \\}
1478 , buf.items);
1456 , aw.getWritten());
14791457 } 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());
14811459 }
1482 buf.clearRetainingCapacity();
1460 aw.clearRetainingCapacity();
14831461 }
14841462
14851463 {
1486 var container = try sz.beginTuple(.{ .whitespace_style = .{ .fields = 3 } });
1464 var container = try s.beginTuple(.{ .whitespace_style = .{ .fields = 3 } });
14871465 try container.field(1, .{});
14881466 try container.field(2, .{});
14891467 try container.field(3, .{});
......@@ -1495,16 +1473,16 @@ test "std.zon stringify whitespace, low level API" {
14951473 \\ 2,
14961474 \\ 3,
14971475 \\}
1498 , buf.items);
1476 , aw.getWritten());
14991477 } else {
1500 try std.testing.expectEqualStrings(".{1,2,3}", buf.items);
1478 try std.testing.expectEqualStrings(".{1,2,3}", aw.getWritten());
15011479 }
1502 buf.clearRetainingCapacity();
1480 aw.clearRetainingCapacity();
15031481 }
15041482
15051483 // Nested objects where the outer container doesn't wrap but the inner containers do
15061484 {
1507 var container = try sz.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
1485 var container = try s.beginStruct(.{ .whitespace_style = .{ .wrap = false } });
15081486 try container.field("first", .{ 1, 2, 3 }, .{});
15091487 try container.field("second", .{ 4, 5, 6 }, .{});
15101488 try container.end();
......@@ -1519,139 +1497,141 @@ test "std.zon stringify whitespace, low level API" {
15191497 \\ 5,
15201498 \\ 6,
15211499 \\} }
1522 , buf.items);
1500 , aw.getWritten());
15231501 } else {
15241502 try std.testing.expectEqualStrings(
15251503 ".{.first=.{1,2,3},.second=.{4,5,6}}",
1526 buf.items,
1504 aw.getWritten(),
15271505 );
15281506 }
1529 buf.clearRetainingCapacity();
1507 aw.clearRetainingCapacity();
15301508 }
15311509 }
15321510}
15331511
15341512test "std.zon stringify utf8 codepoints" {
1535 var buf = std.ArrayList(u8).init(std.testing.allocator);
1536 defer buf.deinit();
1537 var sz = serializer(buf.writer(), .{});
1513 var aw: Writer.Allocating = .init(std.testing.allocator);
1514 var s: Serializer = .{ .writer = &aw.writer };
1515 defer aw.deinit();
15381516
15391517 // Printable ASCII
1540 try sz.int('a');
1541 try std.testing.expectEqualStrings("97", buf.items);
1542 buf.clearRetainingCapacity();
1518 try s.int('a');
1519 try std.testing.expectEqualStrings("97", aw.getWritten());
1520 aw.clearRetainingCapacity();
15431521
1544 try sz.codePoint('a');
1545 try std.testing.expectEqualStrings("'a'", buf.items);
1546 buf.clearRetainingCapacity();
1522 try s.codePoint('a');
1523 try std.testing.expectEqualStrings("'a'", aw.getWritten());
1524 aw.clearRetainingCapacity();
15471525
1548 try sz.value('a', .{ .emit_codepoint_literals = .always });
1549 try std.testing.expectEqualStrings("'a'", buf.items);
1550 buf.clearRetainingCapacity();
1526 try s.value('a', .{ .emit_codepoint_literals = .always });
1527 try std.testing.expectEqualStrings("'a'", aw.getWritten());
1528 aw.clearRetainingCapacity();
15511529
1552 try sz.value('a', .{ .emit_codepoint_literals = .printable_ascii });
1553 try std.testing.expectEqualStrings("'a'", buf.items);
1554 buf.clearRetainingCapacity();
1530 try s.value('a', .{ .emit_codepoint_literals = .printable_ascii });
1531 try std.testing.expectEqualStrings("'a'", aw.getWritten());
1532 aw.clearRetainingCapacity();
15551533
1556 try sz.value('a', .{ .emit_codepoint_literals = .never });
1557 try std.testing.expectEqualStrings("97", buf.items);
1558 buf.clearRetainingCapacity();
1534 try s.value('a', .{ .emit_codepoint_literals = .never });
1535 try std.testing.expectEqualStrings("97", aw.getWritten());
1536 aw.clearRetainingCapacity();
15591537
15601538 // Short escaped codepoint
1561 try sz.int('\n');
1562 try std.testing.expectEqualStrings("10", buf.items);
1563 buf.clearRetainingCapacity();
1539 try s.int('\n');
1540 try std.testing.expectEqualStrings("10", aw.getWritten());
1541 aw.clearRetainingCapacity();
15641542
1565 try sz.codePoint('\n');
1566 try std.testing.expectEqualStrings("'\\n'", buf.items);
1567 buf.clearRetainingCapacity();
1543 try s.codePoint('\n');
1544 try std.testing.expectEqualStrings("'\\n'", aw.getWritten());
1545 aw.clearRetainingCapacity();
15681546
1569 try sz.value('\n', .{ .emit_codepoint_literals = .always });
1570 try std.testing.expectEqualStrings("'\\n'", buf.items);
1571 buf.clearRetainingCapacity();
1547 try s.value('\n', .{ .emit_codepoint_literals = .always });
1548 try std.testing.expectEqualStrings("'\\n'", aw.getWritten());
1549 aw.clearRetainingCapacity();
15721550
1573 try sz.value('\n', .{ .emit_codepoint_literals = .printable_ascii });
1574 try std.testing.expectEqualStrings("10", buf.items);
1575 buf.clearRetainingCapacity();
1551 try s.value('\n', .{ .emit_codepoint_literals = .printable_ascii });
1552 try std.testing.expectEqualStrings("10", aw.getWritten());
1553 aw.clearRetainingCapacity();
15761554
1577 try sz.value('\n', .{ .emit_codepoint_literals = .never });
1578 try std.testing.expectEqualStrings("10", buf.items);
1579 buf.clearRetainingCapacity();
1555 try s.value('\n', .{ .emit_codepoint_literals = .never });
1556 try std.testing.expectEqualStrings("10", aw.getWritten());
1557 aw.clearRetainingCapacity();
15801558
15811559 // Large codepoint
1582 try sz.int('⚡');
1583 try std.testing.expectEqualStrings("9889", buf.items);
1584 buf.clearRetainingCapacity();
1560 try s.int('⚡');
1561 try std.testing.expectEqualStrings("9889", aw.getWritten());
1562 aw.clearRetainingCapacity();
15851563
1586 try sz.codePoint('⚡');
1587 try std.testing.expectEqualStrings("'\\xe2\\x9a\\xa1'", buf.items);
1588 buf.clearRetainingCapacity();
1564 try s.codePoint('⚡');
1565 try std.testing.expectEqualStrings("'\\u{26a1}'", aw.getWritten());
1566 aw.clearRetainingCapacity();
15891567
1590 try sz.value('⚡', .{ .emit_codepoint_literals = .always });
1591 try std.testing.expectEqualStrings("'\\xe2\\x9a\\xa1'", buf.items);
1592 buf.clearRetainingCapacity();
1568 try s.value('⚡', .{ .emit_codepoint_literals = .always });
1569 try std.testing.expectEqualStrings("'\\u{26a1}'", aw.getWritten());
1570 aw.clearRetainingCapacity();
15931571
1594 try sz.value('⚡', .{ .emit_codepoint_literals = .printable_ascii });
1595 try std.testing.expectEqualStrings("9889", buf.items);
1596 buf.clearRetainingCapacity();
1572 try s.value('⚡', .{ .emit_codepoint_literals = .printable_ascii });
1573 try std.testing.expectEqualStrings("9889", aw.getWritten());
1574 aw.clearRetainingCapacity();
15971575
1598 try sz.value('⚡', .{ .emit_codepoint_literals = .never });
1599 try std.testing.expectEqualStrings("9889", buf.items);
1600 buf.clearRetainingCapacity();
1576 try s.value('⚡', .{ .emit_codepoint_literals = .never });
1577 try std.testing.expectEqualStrings("9889", aw.getWritten());
1578 aw.clearRetainingCapacity();
16011579
16021580 // 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);
1606 try std.testing.expectEqualStrings("1114113", buf.items);
1607 buf.clearRetainingCapacity();
1585 try s.int(0x110000 + 1);
1586 try std.testing.expectEqualStrings("1114113", aw.getWritten());
1587 aw.clearRetainingCapacity();
16081588
1609 try sz.value(0x110000 + 1, .{ .emit_codepoint_literals = .always });
1610 try std.testing.expectEqualStrings("1114113", buf.items);
1611 buf.clearRetainingCapacity();
1589 try s.value(0x110000 + 1, .{ .emit_codepoint_literals = .always });
1590 try std.testing.expectEqualStrings("1114113", aw.getWritten());
1591 aw.clearRetainingCapacity();
16121592
1613 try sz.value(0x110000 + 1, .{ .emit_codepoint_literals = .printable_ascii });
1614 try std.testing.expectEqualStrings("1114113", buf.items);
1615 buf.clearRetainingCapacity();
1593 try s.value(0x110000 + 1, .{ .emit_codepoint_literals = .printable_ascii });
1594 try std.testing.expectEqualStrings("1114113", aw.getWritten());
1595 aw.clearRetainingCapacity();
16161596
1617 try sz.value(0x110000 + 1, .{ .emit_codepoint_literals = .never });
1618 try std.testing.expectEqualStrings("1114113", buf.items);
1619 buf.clearRetainingCapacity();
1597 try s.value(0x110000 + 1, .{ .emit_codepoint_literals = .never });
1598 try std.testing.expectEqualStrings("1114113", aw.getWritten());
1599 aw.clearRetainingCapacity();
16201600
16211601 // Valid codepoint, not a codepoint type
1622 try sz.value(@as(u22, 'a'), .{ .emit_codepoint_literals = .always });
1623 try std.testing.expectEqualStrings("97", buf.items);
1624 buf.clearRetainingCapacity();
1602 try s.value(@as(u22, 'a'), .{ .emit_codepoint_literals = .always });
1603 try std.testing.expectEqualStrings("97", aw.getWritten());
1604 aw.clearRetainingCapacity();
16251605
1626 try sz.value(@as(u22, 'a'), .{ .emit_codepoint_literals = .printable_ascii });
1627 try std.testing.expectEqualStrings("97", buf.items);
1628 buf.clearRetainingCapacity();
1606 try s.value(@as(u22, 'a'), .{ .emit_codepoint_literals = .printable_ascii });
1607 try std.testing.expectEqualStrings("97", aw.getWritten());
1608 aw.clearRetainingCapacity();
16291609
1630 try sz.value(@as(i32, 'a'), .{ .emit_codepoint_literals = .never });
1631 try std.testing.expectEqualStrings("97", buf.items);
1632 buf.clearRetainingCapacity();
1610 try s.value(@as(i32, 'a'), .{ .emit_codepoint_literals = .never });
1611 try std.testing.expectEqualStrings("97", aw.getWritten());
1612 aw.clearRetainingCapacity();
16331613
16341614 // Make sure value options are passed to children
1635 try sz.value(.{ .c = '⚡' }, .{ .emit_codepoint_literals = .always });
1636 try std.testing.expectEqualStrings(".{ .c = '\\xe2\\x9a\\xa1' }", buf.items);
1637 buf.clearRetainingCapacity();
1615 try s.value(.{ .c = '⚡' }, .{ .emit_codepoint_literals = .always });
1616 try std.testing.expectEqualStrings(".{ .c = '\\u{26a1}' }", aw.getWritten());
1617 aw.clearRetainingCapacity();
16381618
1639 try sz.value(.{ .c = '⚡' }, .{ .emit_codepoint_literals = .never });
1640 try std.testing.expectEqualStrings(".{ .c = 9889 }", buf.items);
1641 buf.clearRetainingCapacity();
1619 try s.value(.{ .c = '⚡' }, .{ .emit_codepoint_literals = .never });
1620 try std.testing.expectEqualStrings(".{ .c = 9889 }", aw.getWritten());
1621 aw.clearRetainingCapacity();
16421622}
16431623
16441624test "std.zon stringify strings" {
1645 var buf = std.ArrayList(u8).init(std.testing.allocator);
1646 defer buf.deinit();
1647 var sz = serializer(buf.writer(), .{});
1625 var aw: Writer.Allocating = .init(std.testing.allocator);
1626 var s: Serializer = .{ .writer = &aw.writer };
1627 defer aw.deinit();
16481628
16491629 // Minimal case
1650 try sz.string("abc⚡\n");
1651 try std.testing.expectEqualStrings("\"abc\\xe2\\x9a\\xa1\\n\"", buf.items);
1652 buf.clearRetainingCapacity();
1630 try s.string("abc⚡\n");
1631 try std.testing.expectEqualStrings("\"abc\\xe2\\x9a\\xa1\\n\"", aw.getWritten());
1632 aw.clearRetainingCapacity();
16531633
1654 try sz.tuple("abc⚡\n", .{});
1634 try s.tuple("abc⚡\n", .{});
16551635 try std.testing.expectEqualStrings(
16561636 \\.{
16571637 \\ 97,
......@@ -1662,14 +1642,14 @@ test "std.zon stringify strings" {
16621642 \\ 161,
16631643 \\ 10,
16641644 \\}
1665 , buf.items);
1666 buf.clearRetainingCapacity();
1645 , aw.getWritten());
1646 aw.clearRetainingCapacity();
16671647
1668 try sz.value("abc⚡\n", .{});
1669 try std.testing.expectEqualStrings("\"abc\\xe2\\x9a\\xa1\\n\"", buf.items);
1670 buf.clearRetainingCapacity();
1648 try s.value("abc⚡\n", .{});
1649 try std.testing.expectEqualStrings("\"abc\\xe2\\x9a\\xa1\\n\"", aw.getWritten());
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 });
16731653 try std.testing.expectEqualStrings(
16741654 \\.{
16751655 \\ 97,
......@@ -1680,113 +1660,113 @@ test "std.zon stringify strings" {
16801660 \\ 161,
16811661 \\ 10,
16821662 \\}
1683 , buf.items);
1684 buf.clearRetainingCapacity();
1663 , aw.getWritten());
1664 aw.clearRetainingCapacity();
16851665
16861666 // Value options are inherited by children
1687 try sz.value(.{ .str = "abc" }, .{});
1688 try std.testing.expectEqualStrings(".{ .str = \"abc\" }", buf.items);
1689 buf.clearRetainingCapacity();
1667 try s.value(.{ .str = "abc" }, .{});
1668 try std.testing.expectEqualStrings(".{ .str = \"abc\" }", aw.getWritten());
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 });
16921672 try std.testing.expectEqualStrings(
16931673 \\.{ .str = .{
16941674 \\ 97,
16951675 \\ 98,
16961676 \\ 99,
16971677 \\} }
1698 , buf.items);
1699 buf.clearRetainingCapacity();
1678 , aw.getWritten());
1679 aw.clearRetainingCapacity();
17001680
17011681 // Arrays (rather than pointers to arrays) of u8s are not considered strings, so that data can
17021682 // round trip correctly.
1703 try sz.value("abc".*, .{});
1683 try s.value("abc".*, .{});
17041684 try std.testing.expectEqualStrings(
17051685 \\.{
17061686 \\ 97,
17071687 \\ 98,
17081688 \\ 99,
17091689 \\}
1710 , buf.items);
1711 buf.clearRetainingCapacity();
1690 , aw.getWritten());
1691 aw.clearRetainingCapacity();
17121692}
17131693
17141694test "std.zon stringify multiline strings" {
1715 var buf = std.ArrayList(u8).init(std.testing.allocator);
1716 defer buf.deinit();
1717 var sz = serializer(buf.writer(), .{});
1695 var aw: Writer.Allocating = .init(std.testing.allocator);
1696 var s: Serializer = .{ .writer = &aw.writer };
1697 defer aw.deinit();
17181698
17191699 inline for (.{ true, false }) |whitespace| {
1720 sz.options.whitespace = whitespace;
1700 s.options.whitespace = whitespace;
17211701
17221702 {
1723 try sz.multilineString("", .{ .top_level = true });
1724 try std.testing.expectEqualStrings("\\\\", buf.items);
1725 buf.clearRetainingCapacity();
1703 try s.multilineString("", .{ .top_level = true });
1704 try std.testing.expectEqualStrings("\\\\", aw.getWritten());
1705 aw.clearRetainingCapacity();
17261706 }
17271707
17281708 {
1729 try sz.multilineString("abc⚡", .{ .top_level = true });
1730 try std.testing.expectEqualStrings("\\\\abc⚡", buf.items);
1731 buf.clearRetainingCapacity();
1709 try s.multilineString("abc⚡", .{ .top_level = true });
1710 try std.testing.expectEqualStrings("\\\\abc⚡", aw.getWritten());
1711 aw.clearRetainingCapacity();
17321712 }
17331713
17341714 {
1735 try sz.multilineString("abc⚡\ndef", .{ .top_level = true });
1736 try std.testing.expectEqualStrings("\\\\abc⚡\n\\\\def", buf.items);
1737 buf.clearRetainingCapacity();
1715 try s.multilineString("abc⚡\ndef", .{ .top_level = true });
1716 try std.testing.expectEqualStrings("\\\\abc⚡\n\\\\def", aw.getWritten());
1717 aw.clearRetainingCapacity();
17381718 }
17391719
17401720 {
1741 try sz.multilineString("abc⚡\r\ndef", .{ .top_level = true });
1742 try std.testing.expectEqualStrings("\\\\abc⚡\n\\\\def", buf.items);
1743 buf.clearRetainingCapacity();
1721 try s.multilineString("abc⚡\r\ndef", .{ .top_level = true });
1722 try std.testing.expectEqualStrings("\\\\abc⚡\n\\\\def", aw.getWritten());
1723 aw.clearRetainingCapacity();
17441724 }
17451725
17461726 {
1747 try sz.multilineString("\nabc⚡", .{ .top_level = true });
1748 try std.testing.expectEqualStrings("\\\\\n\\\\abc⚡", buf.items);
1749 buf.clearRetainingCapacity();
1727 try s.multilineString("\nabc⚡", .{ .top_level = true });
1728 try std.testing.expectEqualStrings("\\\\\n\\\\abc⚡", aw.getWritten());
1729 aw.clearRetainingCapacity();
17501730 }
17511731
17521732 {
1753 try sz.multilineString("\r\nabc⚡", .{ .top_level = true });
1754 try std.testing.expectEqualStrings("\\\\\n\\\\abc⚡", buf.items);
1755 buf.clearRetainingCapacity();
1733 try s.multilineString("\r\nabc⚡", .{ .top_level = true });
1734 try std.testing.expectEqualStrings("\\\\\n\\\\abc⚡", aw.getWritten());
1735 aw.clearRetainingCapacity();
17561736 }
17571737
17581738 {
1759 try sz.multilineString("abc\ndef", .{});
1739 try s.multilineString("abc\ndef", .{});
17601740 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());
17621742 } else {
1763 try std.testing.expectEqualStrings("\\\\abc\n\\\\def\n", buf.items);
1743 try std.testing.expectEqualStrings("\\\\abc\n\\\\def\n", aw.getWritten());
17641744 }
1765 buf.clearRetainingCapacity();
1745 aw.clearRetainingCapacity();
17661746 }
17671747
17681748 {
17691749 const str: []const u8 = &.{ 'a', '\r', 'c' };
1770 try sz.string(str);
1771 try std.testing.expectEqualStrings("\"a\\rc\"", buf.items);
1772 buf.clearRetainingCapacity();
1750 try s.string(str);
1751 try std.testing.expectEqualStrings("\"a\\rc\"", aw.getWritten());
1752 aw.clearRetainingCapacity();
17731753 }
17741754
17751755 {
17761756 try std.testing.expectError(
17771757 error.InnerCarriageReturn,
1778 sz.multilineString(@as([]const u8, &.{ 'a', '\r', 'c' }), .{}),
1758 s.multilineString(@as([]const u8, &.{ 'a', '\r', 'c' }), .{}),
17791759 );
17801760 try std.testing.expectError(
17811761 error.InnerCarriageReturn,
1782 sz.multilineString(@as([]const u8, &.{ 'a', '\r', 'c', '\n' }), .{}),
1762 s.multilineString(@as([]const u8, &.{ 'a', '\r', 'c', '\n' }), .{}),
17831763 );
17841764 try std.testing.expectError(
17851765 error.InnerCarriageReturn,
1786 sz.multilineString(@as([]const u8, &.{ 'a', '\r', 'c', '\r', '\n' }), .{}),
1766 s.multilineString(@as([]const u8, &.{ 'a', '\r', 'c', '\r', '\n' }), .{}),
17871767 );
1788 try std.testing.expectEqualStrings("", buf.items);
1789 buf.clearRetainingCapacity();
1768 try std.testing.expectEqualStrings("", aw.getWritten());
1769 aw.clearRetainingCapacity();
17901770 }
17911771 }
17921772}
......@@ -1932,42 +1912,43 @@ test "std.zon stringify skip default fields" {
19321912}
19331913
19341914test "std.zon depth limits" {
1935 var buf = std.ArrayList(u8).init(std.testing.allocator);
1936 defer buf.deinit();
1915 var aw: Writer.Allocating = .init(std.testing.allocator);
1916 const bw = &aw.writer;
1917 defer aw.deinit();
19371918
19381919 const Recurse = struct { r: []const @This() };
19391920
19401921 // Normal operation
1941 try serializeMaxDepth(.{ 1, .{ 2, 3 } }, .{}, buf.writer(), 16);
1942 try std.testing.expectEqualStrings(".{ 1, .{ 2, 3 } }", buf.items);
1943 buf.clearRetainingCapacity();
1922 try serializeMaxDepth(.{ 1, .{ 2, 3 } }, .{}, bw, 16);
1923 try std.testing.expectEqualStrings(".{ 1, .{ 2, 3 } }", aw.getWritten());
1924 aw.clearRetainingCapacity();
19441925
1945 try serializeArbitraryDepth(.{ 1, .{ 2, 3 } }, .{}, buf.writer());
1946 try std.testing.expectEqualStrings(".{ 1, .{ 2, 3 } }", buf.items);
1947 buf.clearRetainingCapacity();
1926 try serializeArbitraryDepth(.{ 1, .{ 2, 3 } }, .{}, bw);
1927 try std.testing.expectEqualStrings(".{ 1, .{ 2, 3 } }", aw.getWritten());
1928 aw.clearRetainingCapacity();
19481929
19491930 // Max depth failing on non recursive type
19501931 try std.testing.expectError(
19511932 error.ExceededMaxDepth,
1952 serializeMaxDepth(.{ 1, .{ 2, .{ 3, 4 } } }, .{}, buf.writer(), 3),
1933 serializeMaxDepth(.{ 1, .{ 2, .{ 3, 4 } } }, .{}, bw, 3),
19531934 );
1954 try std.testing.expectEqualStrings("", buf.items);
1955 buf.clearRetainingCapacity();
1935 try std.testing.expectEqualStrings("", aw.getWritten());
1936 aw.clearRetainingCapacity();
19561937
19571938 // Max depth passing on recursive type
19581939 {
19591940 const maybe_recurse = Recurse{ .r = &.{} };
1960 try serializeMaxDepth(maybe_recurse, .{}, buf.writer(), 2);
1961 try std.testing.expectEqualStrings(".{ .r = .{} }", buf.items);
1962 buf.clearRetainingCapacity();
1941 try serializeMaxDepth(maybe_recurse, .{}, bw, 2);
1942 try std.testing.expectEqualStrings(".{ .r = .{} }", aw.getWritten());
1943 aw.clearRetainingCapacity();
19631944 }
19641945
19651946 // Unchecked passing on recursive type
19661947 {
19671948 const maybe_recurse = Recurse{ .r = &.{} };
1968 try serializeArbitraryDepth(maybe_recurse, .{}, buf.writer());
1969 try std.testing.expectEqualStrings(".{ .r = .{} }", buf.items);
1970 buf.clearRetainingCapacity();
1949 try serializeArbitraryDepth(maybe_recurse, .{}, bw);
1950 try std.testing.expectEqualStrings(".{ .r = .{} }", aw.getWritten());
1951 aw.clearRetainingCapacity();
19711952 }
19721953
19731954 // Max depth failing on recursive type due to depth
......@@ -1976,10 +1957,10 @@ test "std.zon depth limits" {
19761957 maybe_recurse.r = &.{.{ .r = &.{} }};
19771958 try std.testing.expectError(
19781959 error.ExceededMaxDepth,
1979 serializeMaxDepth(maybe_recurse, .{}, buf.writer(), 2),
1960 serializeMaxDepth(maybe_recurse, .{}, bw, 2),
19801961 );
1981 try std.testing.expectEqualStrings("", buf.items);
1982 buf.clearRetainingCapacity();
1962 try std.testing.expectEqualStrings("", aw.getWritten());
1963 aw.clearRetainingCapacity();
19831964 }
19841965
19851966 // Same but for a slice
......@@ -1989,23 +1970,23 @@ test "std.zon depth limits" {
19891970
19901971 try std.testing.expectError(
19911972 error.ExceededMaxDepth,
1992 serializeMaxDepth(maybe_recurse, .{}, buf.writer(), 2),
1973 serializeMaxDepth(maybe_recurse, .{}, bw, 2),
19931974 );
1994 try std.testing.expectEqualStrings("", buf.items);
1995 buf.clearRetainingCapacity();
1975 try std.testing.expectEqualStrings("", aw.getWritten());
1976 aw.clearRetainingCapacity();
19961977
1997 var sz = serializer(buf.writer(), .{});
1978 var s: Serializer = .{ .writer = bw };
19981979
19991980 try std.testing.expectError(
20001981 error.ExceededMaxDepth,
2001 sz.tupleMaxDepth(maybe_recurse, .{}, 2),
1982 s.tupleMaxDepth(maybe_recurse, .{}, 2),
20021983 );
2003 try std.testing.expectEqualStrings("", buf.items);
2004 buf.clearRetainingCapacity();
1984 try std.testing.expectEqualStrings("", aw.getWritten());
1985 aw.clearRetainingCapacity();
20051986
2006 try sz.tupleArbitraryDepth(maybe_recurse, .{});
2007 try std.testing.expectEqualStrings(".{.{ .r = .{} }}", buf.items);
2008 buf.clearRetainingCapacity();
1987 try s.tupleArbitraryDepth(maybe_recurse, .{});
1988 try std.testing.expectEqualStrings(".{.{ .r = .{} }}", aw.getWritten());
1989 aw.clearRetainingCapacity();
20091990 }
20101991
20111992 // A slice succeeding
......@@ -2013,19 +1994,19 @@ test "std.zon depth limits" {
20131994 var temp: [1]Recurse = .{.{ .r = &.{} }};
20141995 const maybe_recurse: []const Recurse = &temp;
20151996
2016 try serializeMaxDepth(maybe_recurse, .{}, buf.writer(), 3);
2017 try std.testing.expectEqualStrings(".{.{ .r = .{} }}", buf.items);
2018 buf.clearRetainingCapacity();
1997 try serializeMaxDepth(maybe_recurse, .{}, bw, 3);
1998 try std.testing.expectEqualStrings(".{.{ .r = .{} }}", aw.getWritten());
1999 aw.clearRetainingCapacity();
20192000
2020 var sz = serializer(buf.writer(), .{});
2001 var s: Serializer = .{ .writer = bw };
20212002
2022 try sz.tupleMaxDepth(maybe_recurse, .{}, 3);
2023 try std.testing.expectEqualStrings(".{.{ .r = .{} }}", buf.items);
2024 buf.clearRetainingCapacity();
2003 try s.tupleMaxDepth(maybe_recurse, .{}, 3);
2004 try std.testing.expectEqualStrings(".{.{ .r = .{} }}", aw.getWritten());
2005 aw.clearRetainingCapacity();
20252006
2026 try sz.tupleArbitraryDepth(maybe_recurse, .{});
2027 try std.testing.expectEqualStrings(".{.{ .r = .{} }}", buf.items);
2028 buf.clearRetainingCapacity();
2007 try s.tupleArbitraryDepth(maybe_recurse, .{});
2008 try std.testing.expectEqualStrings(".{.{ .r = .{} }}", aw.getWritten());
2009 aw.clearRetainingCapacity();
20292010 }
20302011
20312012 // Max depth failing on recursive type due to recursion
......@@ -2036,46 +2017,46 @@ test "std.zon depth limits" {
20362017
20372018 try std.testing.expectError(
20382019 error.ExceededMaxDepth,
2039 serializeMaxDepth(maybe_recurse, .{}, buf.writer(), 128),
2020 serializeMaxDepth(maybe_recurse, .{}, bw, 128),
20402021 );
2041 try std.testing.expectEqualStrings("", buf.items);
2042 buf.clearRetainingCapacity();
2022 try std.testing.expectEqualStrings("", aw.getWritten());
2023 aw.clearRetainingCapacity();
20432024
2044 var sz = serializer(buf.writer(), .{});
2025 var s: Serializer = .{ .writer = bw };
20452026 try std.testing.expectError(
20462027 error.ExceededMaxDepth,
2047 sz.tupleMaxDepth(maybe_recurse, .{}, 128),
2028 s.tupleMaxDepth(maybe_recurse, .{}, 128),
20482029 );
2049 try std.testing.expectEqualStrings("", buf.items);
2050 buf.clearRetainingCapacity();
2030 try std.testing.expectEqualStrings("", aw.getWritten());
2031 aw.clearRetainingCapacity();
20512032 }
20522033
20532034 // Max depth on other parts of the lower level API
20542035 {
2055 var sz = serializer(buf.writer(), .{});
2036 var s: Serializer = .{ .writer = bw };
20562037
20572038 const maybe_recurse: []const Recurse = &.{};
20582039
2059 try std.testing.expectError(error.ExceededMaxDepth, sz.valueMaxDepth(1, .{}, 0));
2060 try sz.valueMaxDepth(2, .{}, 1);
2061 try sz.value(3, .{});
2062 try sz.valueArbitraryDepth(maybe_recurse, .{});
2040 try std.testing.expectError(error.ExceededMaxDepth, s.valueMaxDepth(1, .{}, 0));
2041 try s.valueMaxDepth(2, .{}, 1);
2042 try s.value(3, .{});
2043 try s.valueArbitraryDepth(maybe_recurse, .{});
20632044
2064 var s = try sz.beginStruct(.{});
2065 try std.testing.expectError(error.ExceededMaxDepth, s.fieldMaxDepth("a", 1, .{}, 0));
2066 try s.fieldMaxDepth("b", 4, .{}, 1);
2067 try s.field("c", 5, .{});
2068 try s.fieldArbitraryDepth("d", maybe_recurse, .{});
2069 try s.end();
2045 var wip_struct = try s.beginStruct(.{});
2046 try std.testing.expectError(error.ExceededMaxDepth, wip_struct.fieldMaxDepth("a", 1, .{}, 0));
2047 try wip_struct.fieldMaxDepth("b", 4, .{}, 1);
2048 try wip_struct.field("c", 5, .{});
2049 try wip_struct.fieldArbitraryDepth("d", maybe_recurse, .{});
2050 try wip_struct.end();
20702051
2071 var t = try sz.beginTuple(.{});
2052 var t = try s.beginTuple(.{});
20722053 try std.testing.expectError(error.ExceededMaxDepth, t.fieldMaxDepth(1, .{}, 0));
20732054 try t.fieldMaxDepth(6, .{}, 1);
20742055 try t.field(7, .{});
20752056 try t.fieldArbitraryDepth(maybe_recurse, .{});
20762057 try t.end();
20772058
2078 var a = try sz.beginTuple(.{});
2059 var a = try s.beginTuple(.{});
20792060 try std.testing.expectError(error.ExceededMaxDepth, a.fieldMaxDepth(1, .{}, 0));
20802061 try a.fieldMaxDepth(8, .{}, 1);
20812062 try a.field(9, .{});
......@@ -2096,7 +2077,7 @@ test "std.zon depth limits" {
20962077 \\ 9,
20972078 \\ .{},
20982079 \\}
2099 , buf.items);
2080 , aw.getWritten());
21002081 }
21012082}
21022083
......@@ -2192,42 +2173,42 @@ test "std.zon stringify primitives" {
21922173}
21932174
21942175test "std.zon stringify ident" {
2195 var buf = std.ArrayList(u8).init(std.testing.allocator);
2196 defer buf.deinit();
2197 var sz = serializer(buf.writer(), .{});
2176 var aw: Writer.Allocating = .init(std.testing.allocator);
2177 var s: Serializer = .{ .writer = &aw.writer };
2178 defer aw.deinit();
21982179
21992180 try expectSerializeEqual(".{ .a = 0 }", .{ .a = 0 }, .{});
2200 try sz.ident("a");
2201 try std.testing.expectEqualStrings(".a", buf.items);
2202 buf.clearRetainingCapacity();
2181 try s.ident("a");
2182 try std.testing.expectEqualStrings(".a", aw.getWritten());
2183 aw.clearRetainingCapacity();
22032184
2204 try sz.ident("foo_1");
2205 try std.testing.expectEqualStrings(".foo_1", buf.items);
2206 buf.clearRetainingCapacity();
2185 try s.ident("foo_1");
2186 try std.testing.expectEqualStrings(".foo_1", aw.getWritten());
2187 aw.clearRetainingCapacity();
22072188
2208 try sz.ident("_foo_1");
2209 try std.testing.expectEqualStrings("._foo_1", buf.items);
2210 buf.clearRetainingCapacity();
2189 try s.ident("_foo_1");
2190 try std.testing.expectEqualStrings("._foo_1", aw.getWritten());
2191 aw.clearRetainingCapacity();
22112192
2212 try sz.ident("foo bar");
2213 try std.testing.expectEqualStrings(".@\"foo bar\"", buf.items);
2214 buf.clearRetainingCapacity();
2193 try s.ident("foo bar");
2194 try std.testing.expectEqualStrings(".@\"foo bar\"", aw.getWritten());
2195 aw.clearRetainingCapacity();
22152196
2216 try sz.ident("1foo");
2217 try std.testing.expectEqualStrings(".@\"1foo\"", buf.items);
2218 buf.clearRetainingCapacity();
2197 try s.ident("1foo");
2198 try std.testing.expectEqualStrings(".@\"1foo\"", aw.getWritten());
2199 aw.clearRetainingCapacity();
22192200
2220 try sz.ident("var");
2221 try std.testing.expectEqualStrings(".@\"var\"", buf.items);
2222 buf.clearRetainingCapacity();
2201 try s.ident("var");
2202 try std.testing.expectEqualStrings(".@\"var\"", aw.getWritten());
2203 aw.clearRetainingCapacity();
22232204
2224 try sz.ident("true");
2225 try std.testing.expectEqualStrings(".true", buf.items);
2226 buf.clearRetainingCapacity();
2205 try s.ident("true");
2206 try std.testing.expectEqualStrings(".true", aw.getWritten());
2207 aw.clearRetainingCapacity();
22272208
2228 try sz.ident("_");
2229 try std.testing.expectEqualStrings("._", buf.items);
2230 buf.clearRetainingCapacity();
2209 try s.ident("_");
2210 try std.testing.expectEqualStrings("._", aw.getWritten());
2211 aw.clearRetainingCapacity();
22312212
22322213 const Enum = enum {
22332214 @"foo bar",
......@@ -2239,40 +2220,40 @@ test "std.zon stringify ident" {
22392220}
22402221
22412222test "std.zon stringify as tuple" {
2242 var buf = std.ArrayList(u8).init(std.testing.allocator);
2243 defer buf.deinit();
2244 var sz = serializer(buf.writer(), .{});
2223 var aw: Writer.Allocating = .init(std.testing.allocator);
2224 var s: Serializer = .{ .writer = &aw.writer };
2225 defer aw.deinit();
22452226
22462227 // Tuples
2247 try sz.tuple(.{ 1, 2 }, .{});
2248 try std.testing.expectEqualStrings(".{ 1, 2 }", buf.items);
2249 buf.clearRetainingCapacity();
2228 try s.tuple(.{ 1, 2 }, .{});
2229 try std.testing.expectEqualStrings(".{ 1, 2 }", aw.getWritten());
2230 aw.clearRetainingCapacity();
22502231
22512232 // Slice
2252 try sz.tuple(@as([]const u8, &.{ 1, 2 }), .{});
2253 try std.testing.expectEqualStrings(".{ 1, 2 }", buf.items);
2254 buf.clearRetainingCapacity();
2233 try s.tuple(@as([]const u8, &.{ 1, 2 }), .{});
2234 try std.testing.expectEqualStrings(".{ 1, 2 }", aw.getWritten());
2235 aw.clearRetainingCapacity();
22552236
22562237 // Array
2257 try sz.tuple([2]u8{ 1, 2 }, .{});
2258 try std.testing.expectEqualStrings(".{ 1, 2 }", buf.items);
2259 buf.clearRetainingCapacity();
2238 try s.tuple([2]u8{ 1, 2 }, .{});
2239 try std.testing.expectEqualStrings(".{ 1, 2 }", aw.getWritten());
2240 aw.clearRetainingCapacity();
22602241}
22612242
22622243test "std.zon stringify as float" {
2263 var buf = std.ArrayList(u8).init(std.testing.allocator);
2264 defer buf.deinit();
2265 var sz = serializer(buf.writer(), .{});
2244 var aw: Writer.Allocating = .init(std.testing.allocator);
2245 var s: Serializer = .{ .writer = &aw.writer };
2246 defer aw.deinit();
22662247
22672248 // Comptime float
2268 try sz.float(2.5);
2269 try std.testing.expectEqualStrings("2.5", buf.items);
2270 buf.clearRetainingCapacity();
2249 try s.float(2.5);
2250 try std.testing.expectEqualStrings("2.5", aw.getWritten());
2251 aw.clearRetainingCapacity();
22712252
22722253 // Sized float
2273 try sz.float(@as(f32, 2.5));
2274 try std.testing.expectEqualStrings("2.5", buf.items);
2275 buf.clearRetainingCapacity();
2254 try s.float(@as(f32, 2.5));
2255 try std.testing.expectEqualStrings("2.5", aw.getWritten());
2256 aw.clearRetainingCapacity();
22762257}
22772258
22782259test "std.zon stringify vector" {
......@@ -2364,13 +2345,13 @@ test "std.zon pointers" {
23642345}
23652346
23662347test "std.zon tuple/struct field" {
2367 var buf = std.ArrayList(u8).init(std.testing.allocator);
2368 defer buf.deinit();
2369 var sz = serializer(buf.writer(), .{});
2348 var aw: Writer.Allocating = .init(std.testing.allocator);
2349 var s: Serializer = .{ .writer = &aw.writer };
2350 defer aw.deinit();
23702351
23712352 // Test on structs
23722353 {
2373 var root = try sz.beginStruct(.{});
2354 var root = try s.beginStruct(.{});
23742355 {
23752356 var tuple = try root.beginTupleField("foo", .{});
23762357 try tuple.field(0, .{});
......@@ -2396,13 +2377,13 @@ test "std.zon tuple/struct field" {
23962377 \\ .b = 1,
23972378 \\ },
23982379 \\}
2399 , buf.items);
2400 buf.clearRetainingCapacity();
2380 , aw.getWritten());
2381 aw.clearRetainingCapacity();
24012382 }
24022383
24032384 // Test on tuples
24042385 {
2405 var root = try sz.beginTuple(.{});
2386 var root = try s.beginTuple(.{});
24062387 {
24072388 var tuple = try root.beginTupleField(.{});
24082389 try tuple.field(0, .{});
......@@ -2428,7 +2409,7 @@ test "std.zon tuple/struct field" {
24282409 \\ .b = 1,
24292410 \\ },
24302411 \\}
2431 , buf.items);
2432 buf.clearRetainingCapacity();
2412 , aw.getWritten());
2413 aw.clearRetainingCapacity();
24332414 }
24342415}