diff --git a/lib/std/json.zig b/lib/std/json.zig index 07916ff842..025cf28a70 100644 --- a/lib/std/json.zig +++ b/lib/std/json.zig @@ -1407,6 +1407,7 @@ test "json.parser.dynamic" { test "import more json tests" { _ = @import("json/test.zig"); + _ = @import("json/write_stream.zig"); } test "write json then parse it" { diff --git a/lib/std/json/write_stream.zig b/lib/std/json/write_stream.zig index c30f8ba8d8..0702a3e9f5 100644 --- a/lib/std/json/write_stream.zig +++ b/lib/std/json/write_stream.zig @@ -197,6 +197,34 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type { try self.stream.writeByte('"'); } + /// Writes the complete json into the output stream + pub fn emitJson(self: *Self, json: std.json.Value) Stream.Error!void { + switch (json) { + .Null => try self.emitNull(), + .Bool => |inner| try self.emitBool(inner), + .Integer => |inner| try self.emitNumber(inner), + .Float => |inner| try self.emitNumber(inner), + .String => |inner| try self.emitString(inner), + .Array => |inner| { + try self.beginArray(); + for (inner.toSliceConst()) |elem| { + try self.arrayElem(); + try self.emitJson(elem); + } + try self.endArray(); + }, + .Object => |inner| { + try self.beginObject(); + var it = inner.iterator(); + while (it.next()) |entry| { + try self.objectField(entry.key); + try self.emitJson(entry.value); + } + try self.endObject(); + }, + } + } + fn indent(self: *Self) !void { assert(self.state_index >= 1); try self.stream.write(self.newline); @@ -216,3 +244,61 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type { } }; } + +test "json write stream" { + var out_buf: [1024]u8 = undefined; + var slice_stream = std.io.SliceOutStream.init(&out_buf); + const out = &slice_stream.stream; + + var mem_buf: [1024 * 10]u8 = undefined; + const allocator = &std.heap.FixedBufferAllocator.init(&mem_buf).allocator; + + var w = std.json.WriteStream(@typeOf(out).Child, 10).init(out); + try w.emitJson(try getJson(allocator)); + + const result = slice_stream.getWritten(); + const expected = + \\{ + \\ "object": { + \\ "one": 1, + \\ "two": 2.0e+00 + \\ }, + \\ "string": "This is a string", + \\ "array": [ + \\ "Another string", + \\ 1, + \\ 3.14e+00 + \\ ], + \\ "int": 10, + \\ "float": 3.14e+00 + \\} + ; + std.testing.expect(std.mem.eql(u8, expected, result)); +} + +fn getJson(allocator: *std.mem.Allocator) !std.json.Value { + var value = std.json.Value{ .Object = std.json.ObjectMap.init(allocator) }; + _ = try value.Object.put("string", std.json.Value{ .String = "This is a string" }); + _ = try value.Object.put("int", std.json.Value{ .Integer = @intCast(i64, 10) }); + _ = try value.Object.put("float", std.json.Value{ .Float = 3.14 }); + _ = try value.Object.put("array", try getJsonArray(allocator)); + _ = try value.Object.put("object", try getJsonObject(allocator)); + return value; +} + +fn getJsonObject(allocator: *std.mem.Allocator) !std.json.Value { + var value = std.json.Value{ .Object = std.json.ObjectMap.init(allocator) }; + _ = try value.Object.put("one", std.json.Value{ .Integer = @intCast(i64, 1) }); + _ = try value.Object.put("two", std.json.Value{ .Float = 2.0 }); + return value; +} + +fn getJsonArray(allocator: *std.mem.Allocator) !std.json.Value { + var value = std.json.Value{ .Array = std.json.Array.init(allocator) }; + var array = &value.Array; + _ = try array.append(std.json.Value{ .String = "Another string" }); + _ = try array.append(std.json.Value{ .Integer = @intCast(i64, 1) }); + _ = try array.append(std.json.Value{ .Float = 3.14 }); + + return value; +}