| ... | @@ -1233,6 +1233,57 @@ pub const Value = union(enum) { | ... | @@ -1233,6 +1233,57 @@ pub const Value = union(enum) { |
| 1233 | Array: Array, | 1233 | Array: Array, |
| 1234 | Object: ObjectMap, | 1234 | Object: ObjectMap, |
| 1235 | | 1235 | |
| | 1236 | pub fn jsonStringify( |
| | 1237 | value: @This(), |
| | 1238 | options: StringifyOptions, |
| | 1239 | out_stream: var, |
| | 1240 | ) @TypeOf(out_stream).Error!void { |
| | 1241 | switch (value) { |
| | 1242 | .Null => try out_stream.writeAll("null"), |
| | 1243 | .Bool => |inner| try stringify(inner, options, out_stream), |
| | 1244 | .Integer => |inner| try stringify(inner, options, out_stream), |
| | 1245 | .Float => |inner| try stringify(inner, options, out_stream), |
| | 1246 | .String => |inner| try stringify(inner, options, out_stream), |
| | 1247 | .Array => |inner| try stringify(inner.span(), options, out_stream), |
| | 1248 | .Object => |inner| { |
| | 1249 | try out_stream.writeByte('{'); |
| | 1250 | var field_output = false; |
| | 1251 | var child_options = options; |
| | 1252 | if (child_options.whitespace) |*child_whitespace| { |
| | 1253 | child_whitespace.indent_level += 1; |
| | 1254 | } |
| | 1255 | var it = inner.iterator(); |
| | 1256 | while (it.next()) |entry| { |
| | 1257 | if (!field_output) { |
| | 1258 | field_output = true; |
| | 1259 | } else { |
| | 1260 | try out_stream.writeByte(','); |
| | 1261 | } |
| | 1262 | if (child_options.whitespace) |child_whitespace| { |
| | 1263 | try out_stream.writeByte('\n'); |
| | 1264 | try child_whitespace.outputIndent(out_stream); |
| | 1265 | } |
| | 1266 | |
| | 1267 | try stringify(entry.key, options, out_stream); |
| | 1268 | try out_stream.writeByte(':'); |
| | 1269 | if (child_options.whitespace) |child_whitespace| { |
| | 1270 | if (child_whitespace.separator) { |
| | 1271 | try out_stream.writeByte(' '); |
| | 1272 | } |
| | 1273 | } |
| | 1274 | try stringify(entry.value, child_options, out_stream); |
| | 1275 | } |
| | 1276 | if (field_output) { |
| | 1277 | if (options.whitespace) |whitespace| { |
| | 1278 | try out_stream.writeByte('\n'); |
| | 1279 | try whitespace.outputIndent(out_stream); |
| | 1280 | } |
| | 1281 | } |
| | 1282 | try out_stream.writeByte('}'); |
| | 1283 | }, |
| | 1284 | } |
| | 1285 | } |
| | 1286 | |
| 1236 | pub fn dump(self: Value) void { | 1287 | pub fn dump(self: Value) void { |
| 1237 | var held = std.debug.getStderrMutex().acquire(); | 1288 | var held = std.debug.getStderrMutex().acquire(); |
| 1238 | defer held.release(); | 1289 | defer held.release(); |
| ... | @@ -1270,6 +1321,60 @@ pub const Value = union(enum) { | ... | @@ -1270,6 +1321,60 @@ pub const Value = union(enum) { |
| 1270 | } | 1321 | } |
| 1271 | }; | 1322 | }; |
| 1272 | | 1323 | |
| | 1324 | test "Value.jsonStringify" { |
| | 1325 | { |
| | 1326 | var buffer: [10]u8 = undefined; |
| | 1327 | var fbs = std.io.fixedBufferStream(&buffer); |
| | 1328 | try @as(Value, .Null).jsonStringify(.{}, fbs.outStream()); |
| | 1329 | testing.expectEqualSlices(u8, fbs.getWritten(), "null"); |
| | 1330 | } |
| | 1331 | { |
| | 1332 | var buffer: [10]u8 = undefined; |
| | 1333 | var fbs = std.io.fixedBufferStream(&buffer); |
| | 1334 | try (Value{ .Bool = true }).jsonStringify(.{}, fbs.outStream()); |
| | 1335 | testing.expectEqualSlices(u8, fbs.getWritten(), "true"); |
| | 1336 | } |
| | 1337 | { |
| | 1338 | var buffer: [10]u8 = undefined; |
| | 1339 | var fbs = std.io.fixedBufferStream(&buffer); |
| | 1340 | try (Value{ .Integer = 42 }).jsonStringify(.{}, fbs.outStream()); |
| | 1341 | testing.expectEqualSlices(u8, fbs.getWritten(), "42"); |
| | 1342 | } |
| | 1343 | { |
| | 1344 | var buffer: [10]u8 = undefined; |
| | 1345 | var fbs = std.io.fixedBufferStream(&buffer); |
| | 1346 | try (Value{ .Float = 42 }).jsonStringify(.{}, fbs.outStream()); |
| | 1347 | testing.expectEqualSlices(u8, fbs.getWritten(), "4.2e+01"); |
| | 1348 | } |
| | 1349 | { |
| | 1350 | var buffer: [10]u8 = undefined; |
| | 1351 | var fbs = std.io.fixedBufferStream(&buffer); |
| | 1352 | try (Value{ .String = "weeee" }).jsonStringify(.{}, fbs.outStream()); |
| | 1353 | testing.expectEqualSlices(u8, fbs.getWritten(), "\"weeee\""); |
| | 1354 | } |
| | 1355 | { |
| | 1356 | var buffer: [10]u8 = undefined; |
| | 1357 | var fbs = std.io.fixedBufferStream(&buffer); |
| | 1358 | try (Value{ |
| | 1359 | .Array = Array.fromOwnedSlice(undefined, &[_]Value{ |
| | 1360 | .{ .Integer = 1 }, |
| | 1361 | .{ .Integer = 2 }, |
| | 1362 | .{ .Integer = 3 }, |
| | 1363 | }), |
| | 1364 | }).jsonStringify(.{}, fbs.outStream()); |
| | 1365 | testing.expectEqualSlices(u8, fbs.getWritten(), "[1,2,3]"); |
| | 1366 | } |
| | 1367 | { |
| | 1368 | var buffer: [10]u8 = undefined; |
| | 1369 | var fbs = std.io.fixedBufferStream(&buffer); |
| | 1370 | var obj = ObjectMap.init(testing.allocator); |
| | 1371 | defer obj.deinit(); |
| | 1372 | try obj.putNoClobber("a", .{ .String = "b" }); |
| | 1373 | try (Value{ .Object = obj }).jsonStringify(.{}, fbs.outStream()); |
| | 1374 | testing.expectEqualSlices(u8, fbs.getWritten(), "{\"a\":\"b\"}"); |
| | 1375 | } |
| | 1376 | } |
| | 1377 | |
| 1273 | pub const ParseOptions = struct { | 1378 | pub const ParseOptions = struct { |
| 1274 | allocator: ?*Allocator = null, | 1379 | allocator: ?*Allocator = null, |
| 1275 | | 1380 | |