diff --git a/lib/std/zon/stringify.zig b/lib/std/zon/stringify.zig index d48004340b13..26ca7513197f 100644 --- a/lib/std/zon/stringify.zig +++ b/lib/std/zon/stringify.zig @@ -438,17 +438,17 @@ pub const SerializeContainerOptions = struct { /// * `multilineString` /// /// For manual serialization of containers, see: -/// * `startStruct` -/// * `startTuple` +/// * `beginStruct` +/// * `beginTuple` /// /// # Example /// ```zig /// var sz = serializer(writer, .{}); -/// var vec2 = try sz.startStruct(.{}); +/// var vec2 = try sz.beginStruct(.{}); /// try vec2.field("x", 1.5, .{}); /// try vec2.fieldPrefix(); /// try sz.value(2.5); -/// try vec2.finish(); +/// try vec2.end(); /// ``` pub fn Serializer(Writer: type) type { return struct { @@ -525,22 +525,22 @@ pub fn Serializer(Writer: type) type { } }, .array => { - var container = try self.startTuple( + var container = try self.beginTuple( .{ .whitespace_style = .{ .fields = val.len } }, ); for (val) |item_val| { try container.fieldArbitraryDepth(item_val, options); } - try container.finish(); + try container.end(); }, .@"struct" => |@"struct"| if (@"struct".is_tuple) { - var container = try self.startTuple( + var container = try self.beginTuple( .{ .whitespace_style = .{ .fields = @"struct".fields.len } }, ); inline for (val) |field_value| { try container.fieldArbitraryDepth(field_value, options); } - try container.finish(); + try container.end(); } else { // Decide which fields to emit const fields, const skipped: [@"struct".fields.len]bool = if (options.emit_default_optional_fields) b: { @@ -562,7 +562,7 @@ pub fn Serializer(Writer: type) type { }; // Emit those fields - var container = try self.startStruct( + var container = try self.beginStruct( .{ .whitespace_style = .{ .fields = fields } }, ); inline for (@"struct".fields, skipped) |field_info, skip| { @@ -574,7 +574,7 @@ pub fn Serializer(Writer: type) type { ); } } - try container.finish(); + try container.end(); }, .@"union" => |@"union"| { comptime assert(@"union".tag_type != null); @@ -582,7 +582,7 @@ pub fn Serializer(Writer: type) type { inline else => |pl, tag| if (@TypeOf(pl) == void) try self.writer.print(".{s}", .{@tagName(tag)}) else { - var container = try self.startStruct(.{ .whitespace_style = .{ .fields = 1 } }); + var container = try self.beginStruct(.{ .whitespace_style = .{ .fields = 1 } }); try container.fieldArbitraryDepth( @tagName(tag), @@ -590,7 +590,7 @@ pub fn Serializer(Writer: type) type { options, ); - try container.finish(); + try container.end(); }, } }, @@ -600,13 +600,13 @@ pub fn Serializer(Writer: type) type { try self.writer.writeAll("null"); }, .vector => |vector| { - var container = try self.startTuple( + var container = try self.beginTuple( .{ .whitespace_style = .{ .fields = vector.len } }, ); for (0..vector.len) |i| { try container.fieldArbitraryDepth(val[i], options); } - try container.finish(); + try container.end(); }, else => comptime unreachable, @@ -691,18 +691,18 @@ pub fn Serializer(Writer: type) type { comptime assert(canSerializeType(@TypeOf(val))); switch (@typeInfo(@TypeOf(val))) { .@"struct" => { - var container = try self.startTuple(.{ .whitespace_style = .{ .fields = val.len } }); + var container = try self.beginTuple(.{ .whitespace_style = .{ .fields = val.len } }); inline for (val) |item_val| { try container.fieldArbitraryDepth(item_val, options); } - try container.finish(); + try container.end(); }, .pointer, .array => { - var container = try self.startTuple(.{ .whitespace_style = .{ .fields = val.len } }); + var container = try self.beginTuple(.{ .whitespace_style = .{ .fields = val.len } }); for (val) |item_val| { try container.fieldArbitraryDepth(item_val, options); } - try container.finish(); + try container.end(); }, else => comptime unreachable, } @@ -767,19 +767,19 @@ pub fn Serializer(Writer: type) type { } /// Create a `Struct` for writing ZON structs field by field. - pub fn startStruct( + pub fn beginStruct( self: *Self, options: SerializeContainerOptions, ) Writer.Error!Struct { - return Struct.start(self, options); + return Struct.begin(self, options); } /// Creates a `Tuple` for writing ZON tuples field by field. - pub fn startTuple( + pub fn beginTuple( self: *Self, options: SerializeContainerOptions, ) Writer.Error!Tuple { - return Tuple.start(self, options); + return Tuple.begin(self, options); } fn indent(self: *Self) Writer.Error!void { @@ -812,17 +812,17 @@ pub fn Serializer(Writer: type) type { pub const Tuple = struct { container: Container, - fn start(parent: *Self, options: SerializeContainerOptions) Writer.Error!Tuple { + fn begin(parent: *Self, options: SerializeContainerOptions) Writer.Error!Tuple { return .{ - .container = try Container.start(parent, .anon, options), + .container = try Container.begin(parent, .anon, options), }; } /// Finishes serializing the tuple. /// /// Prints a trailing comma as configured when appropriate, and the closing bracket. - pub fn finish(self: *Tuple) Writer.Error!void { - try self.container.finish(); + pub fn end(self: *Tuple) Writer.Error!void { + try self.container.end(); self.* = undefined; } @@ -855,6 +855,24 @@ pub fn Serializer(Writer: type) type { try self.container.fieldArbitraryDepth(null, val, options); } + /// Starts a field with a struct as a value. Returns the struct. + pub fn beginStructField( + self: *Tuple, + options: SerializeContainerOptions, + ) Writer.Error!Struct { + try self.fieldPrefix(); + return self.container.serializer.beginStruct(options); + } + + /// Starts a field with a tuple as a value. Returns the tuple. + pub fn beginTupleField( + self: *Tuple, + options: SerializeContainerOptions, + ) Writer.Error!Tuple { + try self.fieldPrefix(); + return self.container.serializer.beginTuple(options); + } + /// Print a field prefix. This prints any necessary commas, and whitespace as /// configured. Useful if you want to serialize the field value yourself. pub fn fieldPrefix(self: *Tuple) Writer.Error!void { @@ -866,17 +884,17 @@ pub fn Serializer(Writer: type) type { pub const Struct = struct { container: Container, - fn start(parent: *Self, options: SerializeContainerOptions) Writer.Error!Struct { + fn begin(parent: *Self, options: SerializeContainerOptions) Writer.Error!Struct { return .{ - .container = try Container.start(parent, .named, options), + .container = try Container.begin(parent, .named, options), }; } /// Finishes serializing the struct. /// /// Prints a trailing comma as configured when appropriate, and the closing bracket. - pub fn finish(self: *Struct) Writer.Error!void { - try self.container.finish(); + pub fn end(self: *Struct) Writer.Error!void { + try self.container.end(); self.* = undefined; } @@ -912,6 +930,26 @@ pub fn Serializer(Writer: type) type { try self.container.fieldArbitraryDepth(name, val, options); } + /// Starts a field with a struct as a value. Returns the struct. + pub fn beginStructField( + self: *Struct, + name: []const u8, + options: SerializeContainerOptions, + ) Writer.Error!Struct { + try self.fieldPrefix(name); + return self.container.serializer.beginStruct(options); + } + + /// Starts a field with a tuple as a value. Returns the tuple. + pub fn beginTupleField( + self: *Struct, + name: []const u8, + options: SerializeContainerOptions, + ) Writer.Error!Tuple { + try self.fieldPrefix(name); + return self.container.serializer.beginTuple(options); + } + /// Print a field prefix. This prints any necessary commas, the field name (escaped if /// necessary) and whitespace as configured. Useful if you want to serialize the field /// value yourself. @@ -928,7 +966,7 @@ pub fn Serializer(Writer: type) type { options: SerializeContainerOptions, empty: bool, - fn start( + fn begin( sz: *Self, field_style: FieldStyle, options: SerializeContainerOptions, @@ -943,7 +981,7 @@ pub fn Serializer(Writer: type) type { }; } - fn finish(self: *Container) Writer.Error!void { + fn end(self: *Container) Writer.Error!void { if (self.options.shouldWrap()) self.serializer.indent_level -|= 1; if (!self.empty) { if (self.options.shouldWrap()) { @@ -1139,52 +1177,52 @@ test "std.zon stringify whitespace, low level API" { // Empty containers { - var container = try sz.startStruct(.{}); - try container.finish(); + var container = try sz.beginStruct(.{}); + try container.end(); try std.testing.expectEqualStrings(".{}", buf.items); buf.clearRetainingCapacity(); } { - var container = try sz.startTuple(.{}); - try container.finish(); + var container = try sz.beginTuple(.{}); + try container.end(); try std.testing.expectEqualStrings(".{}", buf.items); buf.clearRetainingCapacity(); } { - var container = try sz.startStruct(.{ .whitespace_style = .{ .wrap = false } }); - try container.finish(); + var container = try sz.beginStruct(.{ .whitespace_style = .{ .wrap = false } }); + try container.end(); try std.testing.expectEqualStrings(".{}", buf.items); buf.clearRetainingCapacity(); } { - var container = try sz.startTuple(.{ .whitespace_style = .{ .wrap = false } }); - try container.finish(); + var container = try sz.beginTuple(.{ .whitespace_style = .{ .wrap = false } }); + try container.end(); try std.testing.expectEqualStrings(".{}", buf.items); buf.clearRetainingCapacity(); } { - var container = try sz.startStruct(.{ .whitespace_style = .{ .fields = 0 } }); - try container.finish(); + var container = try sz.beginStruct(.{ .whitespace_style = .{ .fields = 0 } }); + try container.end(); try std.testing.expectEqualStrings(".{}", buf.items); buf.clearRetainingCapacity(); } { - var container = try sz.startTuple(.{ .whitespace_style = .{ .fields = 0 } }); - try container.finish(); + var container = try sz.beginTuple(.{ .whitespace_style = .{ .fields = 0 } }); + try container.end(); try std.testing.expectEqualStrings(".{}", buf.items); buf.clearRetainingCapacity(); } // Size 1 { - var container = try sz.startStruct(.{}); + var container = try sz.beginStruct(.{}); try container.field("a", 1, .{}); - try container.finish(); + try container.end(); if (whitespace) { try std.testing.expectEqualStrings( \\.{ @@ -1198,9 +1236,9 @@ test "std.zon stringify whitespace, low level API" { } { - var container = try sz.startTuple(.{}); + var container = try sz.beginTuple(.{}); try container.field(1, .{}); - try container.finish(); + try container.end(); if (whitespace) { try std.testing.expectEqualStrings( \\.{ @@ -1214,9 +1252,9 @@ test "std.zon stringify whitespace, low level API" { } { - var container = try sz.startStruct(.{ .whitespace_style = .{ .wrap = false } }); + var container = try sz.beginStruct(.{ .whitespace_style = .{ .wrap = false } }); try container.field("a", 1, .{}); - try container.finish(); + try container.end(); if (whitespace) { try std.testing.expectEqualStrings(".{ .a = 1 }", buf.items); } else { @@ -1228,9 +1266,9 @@ test "std.zon stringify whitespace, low level API" { { // We get extra spaces here, since we didn't know up front that there would only be one // field. - var container = try sz.startTuple(.{ .whitespace_style = .{ .wrap = false } }); + var container = try sz.beginTuple(.{ .whitespace_style = .{ .wrap = false } }); try container.field(1, .{}); - try container.finish(); + try container.end(); if (whitespace) { try std.testing.expectEqualStrings(".{ 1 }", buf.items); } else { @@ -1240,9 +1278,9 @@ test "std.zon stringify whitespace, low level API" { } { - var container = try sz.startStruct(.{ .whitespace_style = .{ .fields = 1 } }); + var container = try sz.beginStruct(.{ .whitespace_style = .{ .fields = 1 } }); try container.field("a", 1, .{}); - try container.finish(); + try container.end(); if (whitespace) { try std.testing.expectEqualStrings(".{ .a = 1 }", buf.items); } else { @@ -1252,19 +1290,19 @@ test "std.zon stringify whitespace, low level API" { } { - var container = try sz.startTuple(.{ .whitespace_style = .{ .fields = 1 } }); + var container = try sz.beginTuple(.{ .whitespace_style = .{ .fields = 1 } }); try container.field(1, .{}); - try container.finish(); + try container.end(); try std.testing.expectEqualStrings(".{1}", buf.items); buf.clearRetainingCapacity(); } // Size 2 { - var container = try sz.startStruct(.{}); + var container = try sz.beginStruct(.{}); try container.field("a", 1, .{}); try container.field("b", 2, .{}); - try container.finish(); + try container.end(); if (whitespace) { try std.testing.expectEqualStrings( \\.{ @@ -1279,10 +1317,10 @@ test "std.zon stringify whitespace, low level API" { } { - var container = try sz.startTuple(.{}); + var container = try sz.beginTuple(.{}); try container.field(1, .{}); try container.field(2, .{}); - try container.finish(); + try container.end(); if (whitespace) { try std.testing.expectEqualStrings( \\.{ @@ -1297,10 +1335,10 @@ test "std.zon stringify whitespace, low level API" { } { - var container = try sz.startStruct(.{ .whitespace_style = .{ .wrap = false } }); + var container = try sz.beginStruct(.{ .whitespace_style = .{ .wrap = false } }); try container.field("a", 1, .{}); try container.field("b", 2, .{}); - try container.finish(); + try container.end(); if (whitespace) { try std.testing.expectEqualStrings(".{ .a = 1, .b = 2 }", buf.items); } else { @@ -1310,10 +1348,10 @@ test "std.zon stringify whitespace, low level API" { } { - var container = try sz.startTuple(.{ .whitespace_style = .{ .wrap = false } }); + var container = try sz.beginTuple(.{ .whitespace_style = .{ .wrap = false } }); try container.field(1, .{}); try container.field(2, .{}); - try container.finish(); + try container.end(); if (whitespace) { try std.testing.expectEqualStrings(".{ 1, 2 }", buf.items); } else { @@ -1323,10 +1361,10 @@ test "std.zon stringify whitespace, low level API" { } { - var container = try sz.startStruct(.{ .whitespace_style = .{ .fields = 2 } }); + var container = try sz.beginStruct(.{ .whitespace_style = .{ .fields = 2 } }); try container.field("a", 1, .{}); try container.field("b", 2, .{}); - try container.finish(); + try container.end(); if (whitespace) { try std.testing.expectEqualStrings(".{ .a = 1, .b = 2 }", buf.items); } else { @@ -1336,10 +1374,10 @@ test "std.zon stringify whitespace, low level API" { } { - var container = try sz.startTuple(.{ .whitespace_style = .{ .fields = 2 } }); + var container = try sz.beginTuple(.{ .whitespace_style = .{ .fields = 2 } }); try container.field(1, .{}); try container.field(2, .{}); - try container.finish(); + try container.end(); if (whitespace) { try std.testing.expectEqualStrings(".{ 1, 2 }", buf.items); } else { @@ -1350,11 +1388,11 @@ test "std.zon stringify whitespace, low level API" { // Size 3 { - var container = try sz.startStruct(.{}); + var container = try sz.beginStruct(.{}); try container.field("a", 1, .{}); try container.field("b", 2, .{}); try container.field("c", 3, .{}); - try container.finish(); + try container.end(); if (whitespace) { try std.testing.expectEqualStrings( \\.{ @@ -1370,11 +1408,11 @@ test "std.zon stringify whitespace, low level API" { } { - var container = try sz.startTuple(.{}); + var container = try sz.beginTuple(.{}); try container.field(1, .{}); try container.field(2, .{}); try container.field(3, .{}); - try container.finish(); + try container.end(); if (whitespace) { try std.testing.expectEqualStrings( \\.{ @@ -1390,11 +1428,11 @@ test "std.zon stringify whitespace, low level API" { } { - var container = try sz.startStruct(.{ .whitespace_style = .{ .wrap = false } }); + var container = try sz.beginStruct(.{ .whitespace_style = .{ .wrap = false } }); try container.field("a", 1, .{}); try container.field("b", 2, .{}); try container.field("c", 3, .{}); - try container.finish(); + try container.end(); if (whitespace) { try std.testing.expectEqualStrings(".{ .a = 1, .b = 2, .c = 3 }", buf.items); } else { @@ -1404,11 +1442,11 @@ test "std.zon stringify whitespace, low level API" { } { - var container = try sz.startTuple(.{ .whitespace_style = .{ .wrap = false } }); + var container = try sz.beginTuple(.{ .whitespace_style = .{ .wrap = false } }); try container.field(1, .{}); try container.field(2, .{}); try container.field(3, .{}); - try container.finish(); + try container.end(); if (whitespace) { try std.testing.expectEqualStrings(".{ 1, 2, 3 }", buf.items); } else { @@ -1418,11 +1456,11 @@ test "std.zon stringify whitespace, low level API" { } { - var container = try sz.startStruct(.{ .whitespace_style = .{ .fields = 3 } }); + var container = try sz.beginStruct(.{ .whitespace_style = .{ .fields = 3 } }); try container.field("a", 1, .{}); try container.field("b", 2, .{}); try container.field("c", 3, .{}); - try container.finish(); + try container.end(); if (whitespace) { try std.testing.expectEqualStrings( \\.{ @@ -1438,11 +1476,11 @@ test "std.zon stringify whitespace, low level API" { } { - var container = try sz.startTuple(.{ .whitespace_style = .{ .fields = 3 } }); + var container = try sz.beginTuple(.{ .whitespace_style = .{ .fields = 3 } }); try container.field(1, .{}); try container.field(2, .{}); try container.field(3, .{}); - try container.finish(); + try container.end(); if (whitespace) { try std.testing.expectEqualStrings( \\.{ @@ -1459,10 +1497,10 @@ test "std.zon stringify whitespace, low level API" { // Nested objects where the outer container doesn't wrap but the inner containers do { - var container = try sz.startStruct(.{ .whitespace_style = .{ .wrap = false } }); + var container = try sz.beginStruct(.{ .whitespace_style = .{ .wrap = false } }); try container.field("first", .{ 1, 2, 3 }, .{}); try container.field("second", .{ 4, 5, 6 }, .{}); - try container.finish(); + try container.end(); if (whitespace) { try std.testing.expectEqualStrings( \\.{ .first = .{ @@ -2016,26 +2054,26 @@ test "std.zon depth limits" { try sz.value(3, .{}); try sz.valueArbitraryDepth(maybe_recurse, .{}); - var s = try sz.startStruct(.{}); + var s = try sz.beginStruct(.{}); try std.testing.expectError(error.ExceededMaxDepth, s.fieldMaxDepth("a", 1, .{}, 0)); try s.fieldMaxDepth("b", 4, .{}, 1); try s.field("c", 5, .{}); try s.fieldArbitraryDepth("d", maybe_recurse, .{}); - try s.finish(); + try s.end(); - var t = try sz.startTuple(.{}); + var t = try sz.beginTuple(.{}); try std.testing.expectError(error.ExceededMaxDepth, t.fieldMaxDepth(1, .{}, 0)); try t.fieldMaxDepth(6, .{}, 1); try t.field(7, .{}); try t.fieldArbitraryDepth(maybe_recurse, .{}); - try t.finish(); + try t.end(); - var a = try sz.startTuple(.{}); + var a = try sz.beginTuple(.{}); try std.testing.expectError(error.ExceededMaxDepth, a.fieldMaxDepth(1, .{}, 0)); try a.fieldMaxDepth(8, .{}, 1); try a.field(9, .{}); try a.fieldArbitraryDepth(maybe_recurse, .{}); - try a.finish(); + try a.end(); try std.testing.expectEqualStrings( \\23.{}.{ @@ -2315,3 +2353,73 @@ test "std.zon pointers" { , val, .{}); } } + +test "std.zon tuple/struct field" { + var buf = std.ArrayList(u8).init(std.testing.allocator); + defer buf.deinit(); + var sz = serializer(buf.writer(), .{}); + + // Test on structs + { + var root = try sz.beginStruct(.{}); + { + var tuple = try root.beginTupleField("foo", .{}); + try tuple.field(0, .{}); + try tuple.field(1, .{}); + try tuple.end(); + } + { + var strct = try root.beginStructField("bar", .{}); + try strct.field("a", 0, .{}); + try strct.field("b", 1, .{}); + try strct.end(); + } + try root.end(); + + try std.testing.expectEqualStrings( + \\.{ + \\ .foo = .{ + \\ 0, + \\ 1, + \\ }, + \\ .bar = .{ + \\ .a = 0, + \\ .b = 1, + \\ }, + \\} + , buf.items); + buf.clearRetainingCapacity(); + } + + // Test on tuples + { + var root = try sz.beginTuple(.{}); + { + var tuple = try root.beginTupleField(.{}); + try tuple.field(0, .{}); + try tuple.field(1, .{}); + try tuple.end(); + } + { + var strct = try root.beginStructField(.{}); + try strct.field("a", 0, .{}); + try strct.field("b", 1, .{}); + try strct.end(); + } + try root.end(); + + try std.testing.expectEqualStrings( + \\.{ + \\ .{ + \\ 0, + \\ 1, + \\ }, + \\ .{ + \\ .a = 0, + \\ .b = 1, + \\ }, + \\} + , buf.items); + buf.clearRetainingCapacity(); + } +} diff --git a/src/print_targets.zig b/src/print_targets.zig index 470f37c84f75..a00683255d34 100644 --- a/src/print_targets.zig +++ b/src/print_targets.zig @@ -40,121 +40,101 @@ pub fn cmdTargets( var bw = io.bufferedWriter(stdout); const w = bw.writer(); - var jws = std.json.writeStream(w, .{ .whitespace = .indent_1 }); + var sz = std.zon.stringify.serializer(w, .{}); - try jws.beginObject(); - - try jws.objectField("arch"); - try jws.beginArray(); - for (meta.fieldNames(Target.Cpu.Arch)) |field| { - try jws.write(field); - } - try jws.endArray(); + { + var root_obj = try sz.beginStruct(.{}); - try jws.objectField("os"); - try jws.beginArray(); - for (meta.fieldNames(Target.Os.Tag)) |field| { - try jws.write(field); - } - try jws.endArray(); + try root_obj.field("arch", meta.fieldNames(Target.Cpu.Arch), .{}); + try root_obj.field("os", meta.fieldNames(Target.Os.Tag), .{}); + try root_obj.field("abi", meta.fieldNames(Target.Abi), .{}); - try jws.objectField("abi"); - try jws.beginArray(); - for (meta.fieldNames(Target.Abi)) |field| { - try jws.write(field); - } - try jws.endArray(); - - try jws.objectField("libc"); - try jws.beginArray(); - for (std.zig.target.available_libcs) |libc| { - const tmp = try std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{ - @tagName(libc.arch), @tagName(libc.os), @tagName(libc.abi), - }); - defer allocator.free(tmp); - try jws.write(tmp); - } - try jws.endArray(); - - try jws.objectField("glibc"); - try jws.beginArray(); - for (glibc_abi.all_versions) |ver| { - const tmp = try std.fmt.allocPrint(allocator, "{}", .{ver}); - defer allocator.free(tmp); - try jws.write(tmp); - } - try jws.endArray(); - - try jws.objectField("cpus"); - try jws.beginObject(); - for (meta.tags(Target.Cpu.Arch)) |arch| { - try jws.objectField(@tagName(arch)); - try jws.beginObject(); - for (arch.allCpuModels()) |model| { - try jws.objectField(model.name); - try jws.beginArray(); - for (arch.allFeaturesList(), 0..) |feature, i_usize| { - const index = @as(Target.Cpu.Feature.Set.Index, @intCast(i_usize)); - if (model.features.isEnabled(index)) { - try jws.write(feature.name); - } + { + var libc_obj = try root_obj.beginTupleField("libc", .{}); + for (std.zig.target.available_libcs) |libc| { + const tmp = try std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{ + @tagName(libc.arch), @tagName(libc.os), @tagName(libc.abi), + }); + defer allocator.free(tmp); + try libc_obj.field(tmp, .{}); } - try jws.endArray(); + try libc_obj.end(); } - try jws.endObject(); - } - try jws.endObject(); - - try jws.objectField("cpuFeatures"); - try jws.beginObject(); - for (meta.tags(Target.Cpu.Arch)) |arch| { - try jws.objectField(@tagName(arch)); - try jws.beginArray(); - for (arch.allFeaturesList()) |feature| { - try jws.write(feature.name); + + { + var glibc_obj = try root_obj.beginTupleField("glibc", .{}); + for (glibc_abi.all_versions) |ver| { + const tmp = try std.fmt.allocPrint(allocator, "{}", .{ver}); + defer allocator.free(tmp); + try glibc_obj.field(tmp, .{}); + } + try glibc_obj.end(); } - try jws.endArray(); - } - try jws.endObject(); - try jws.objectField("native"); - try jws.beginObject(); - { - const triple = try native_target.zigTriple(allocator); - defer allocator.free(triple); - try jws.objectField("triple"); - try jws.write(triple); - } - { - try jws.objectField("cpu"); - try jws.beginObject(); - try jws.objectField("arch"); - try jws.write(@tagName(native_target.cpu.arch)); + { + var cpus_obj = try root_obj.beginStructField("cpus", .{}); + for (meta.tags(Target.Cpu.Arch)) |arch| { + var arch_obj = try cpus_obj.beginStructField(@tagName(arch), .{}); + for (arch.allCpuModels()) |model| { + var features = try arch_obj.beginTupleField(model.name, .{}); + for (arch.allFeaturesList(), 0..) |feature, i_usize| { + const index = @as(Target.Cpu.Feature.Set.Index, @intCast(i_usize)); + if (model.features.isEnabled(index)) { + try features.field(feature.name, .{}); + } + } + try features.end(); + } + try arch_obj.end(); + } + try cpus_obj.end(); + } - try jws.objectField("name"); - const cpu = native_target.cpu; - try jws.write(cpu.model.name); + { + var cpu_features_obj = try root_obj.beginStructField("cpu_features", .{}); + for (meta.tags(Target.Cpu.Arch)) |arch| { + var arch_features = try cpu_features_obj.beginTupleField(@tagName(arch), .{}); + for (arch.allFeaturesList()) |feature| { + try arch_features.field(feature.name, .{}); + } + try arch_features.end(); + } + try cpu_features_obj.end(); + } { - try jws.objectField("features"); - try jws.beginArray(); - for (native_target.cpu.arch.allFeaturesList(), 0..) |feature, i_usize| { - const index = @as(Target.Cpu.Feature.Set.Index, @intCast(i_usize)); - if (cpu.features.isEnabled(index)) { - try jws.write(feature.name); + var native_obj = try root_obj.beginStructField("native", .{}); + { + const triple = try native_target.zigTriple(allocator); + defer allocator.free(triple); + try native_obj.field("triple", triple, .{}); + } + { + var cpu_obj = try native_obj.beginStructField("cpu", .{}); + try cpu_obj.field("arch", @tagName(native_target.cpu.arch), .{}); + + try cpu_obj.field("name", native_target.cpu.model.name, .{}); + + { + var features = try native_obj.beginTupleField("features", .{}); + for (native_target.cpu.arch.allFeaturesList(), 0..) |feature, i_usize| { + const index = @as(Target.Cpu.Feature.Set.Index, @intCast(i_usize)); + if (native_target.cpu.features.isEnabled(index)) { + try features.field(feature.name, .{}); + } + } + try features.end(); } + try cpu_obj.end(); } - try jws.endArray(); + + try native_obj.field("os", @tagName(native_target.os.tag), .{}); + try native_obj.field("abi", @tagName(native_target.abi), .{}); + try native_obj.end(); } - try jws.endObject(); - } - try jws.objectField("os"); - try jws.write(@tagName(native_target.os.tag)); - try jws.objectField("abi"); - try jws.write(@tagName(native_target.abi)); - try jws.endObject(); - try jws.endObject(); + try root_obj.end(); + } try w.writeByte('\n'); return bw.flush();