diff --git a/json.zig b/json.zig index 6b9ff440740cf66e8149de0fa7706fa0ae541031..5095e3e9a00cae298de48d5d6546d8a210c2bd32 100644 --- a/json.zig +++ b/json.zig @@ -415,6 +415,12 @@ pub const Document = struct { _ = options; return std.fmt.format(writer, "{}", .{this.root}); } + + pub fn stringify(this: *const Document, writer: anytype, space: Space, indent: u8) @TypeOf(writer).Error!void { + const fill = space.fill(); + for (0..indent) |_| try writer.writeAll(fill); + return @errorCast(this.root.stringify(writer, space, indent)); + } }; pub const ValueIndex = enum(u32) { @@ -433,6 +439,10 @@ pub const ValueIndex = enum(u32) { return std.fmt.format(writer, "{}", .{this.v()}); } + fn stringify(this: ValueIndex, writer: anytype, space: Space, indent: u8) !void { + return this.v().stringify(writer, space, indent); + } + pub fn v(this: ValueIndex) Value { std.debug.assert(this != .zero); std.debug.assert(doc != null); // make sure to call Document.acquire() @@ -493,6 +503,17 @@ pub const Value = union(enum(u8)) { inline .object, .array, .string, .number => |t| std.fmt.format(writer, "{}", .{t}), }; } + + fn stringify(this: Value, writer: anytype, space: Space, indent: u8) anyerror!void { + return switch (this) { + .zero => unreachable, + .null => writer.writeAll("null"), + .true => writer.writeAll("true"), + .false => writer.writeAll("false"), + inline .object, .array => |t| t.stringify(writer, space, indent), + inline .string, .number => |t| t.stringify(writer), + }; + } }; pub const Array = []align(1) const ValueIndex; @@ -508,6 +529,12 @@ pub const StringIndex = enum(u32) { try writer.writeAll("\""); } + fn stringify(this: StringIndex, writer: anytype) anyerror!void { + try writer.writeAll("\""); + try writer.writeAll(this.to()); + try writer.writeAll("\""); + } + pub fn to(this: StringIndex) []const u8 { var d = doc.?.extras.ptr[@intFromEnum(this)..]; std.debug.assert(@as(Value.Tag, @enumFromInt(d[0])) == .string); @@ -532,6 +559,21 @@ pub const ArrayIndex = enum(u32) { try writer.writeAll("]"); } + fn stringify(this: ArrayIndex, writer: anytype, space: Space, indent: u8) anyerror!void { + const fill = space.fill(); + const items = this.to(); + try writer.writeAll("["); + for (items, 0..) |item, i| { + if (i > 0) try writer.writeAll(","); + if (fill.len > 0) try writer.writeAll("\n"); + for (0..indent + 1) |_| try writer.writeAll(fill); + try item.stringify(writer, space, indent + 1); + } + if (fill.len > 0) try writer.writeAll("\n"); + for (0..indent) |_| try writer.writeAll(fill); + try writer.writeAll("]"); + } + pub fn to(this: ArrayIndex) Array { var d = doc.?.extras.ptr[@intFromEnum(this)..]; std.debug.assert(@as(Value.Tag, @enumFromInt(d[0])) == .array); @@ -558,6 +600,23 @@ pub const ObjectIndex = enum(u32) { try writer.writeAll("}"); } + fn stringify(this: ObjectIndex, writer: anytype, space: Space, indent: u8) anyerror!void { + const fill = space.fill(); + const keys, const values = this.to(); + try writer.writeAll("{"); + for (keys, values, 0..) |k, v, i| { + if (i > 0) try writer.writeAll(","); + if (fill.len > 0) try writer.writeAll("\n"); + for (0..indent + 1) |_| try writer.writeAll(fill); + try k.stringify(writer); + try writer.writeAll(":"); + try v.stringify(writer, space, indent + 1); + } + if (fill.len > 0) try writer.writeAll("\n"); + for (0..indent) |_| try writer.writeAll(fill); + try writer.writeAll("}"); + } + pub fn to(this: ObjectIndex) struct { []align(1) const StringIndex, Array } { var d = doc.?.extras.ptr[@intFromEnum(this)..]; std.debug.assert(@as(Value.Tag, @enumFromInt(d[0])) == .object); @@ -614,6 +673,10 @@ pub const NumberIndex = enum(u32) { try writer.writeAll(this.to()); } + fn stringify(this: NumberIndex, writer: anytype) anyerror!void { + try writer.writeAll(this.to()); + } + pub fn to(this: NumberIndex) []const u8 { var d = doc.?.extras.ptr[@intFromEnum(this)..]; std.debug.assert(@as(Value.Tag, @enumFromInt(d[0])) == .number); @@ -629,3 +692,15 @@ pub const NumberIndex = enum(u32) { }; } }; + +const Space = union(enum) { + count: u8, + custom: []const u8, + + pub fn fill(s: Space) []const u8 { + return switch (s) { + .count => |c| " "[0..@min(c, 10)], + .custom => |f| f[0..@min(f.len, 10)], + }; + } +};