diff options
| author | Josh Wolfe <thejoshwolfe@gmail.com> | 2023-06-19 11:21:37 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-06-19 11:21:37 -0400 |
| commit | 32cb9462ffa0a9df7a080d67eaf3a5762173f742 (patch) | |
| tree | b3d25551b9cfed2e0b21f12864bcc33cae9d6739 /lib/std/json.zig | |
| parent | 423d7b848b1953173df99fde1f83166dc68c2a2c (diff) | |
| download | zig-32cb9462ffa0a9df7a080d67eaf3a5762173f742.tar.gz zig-32cb9462ffa0a9df7a080d67eaf3a5762173f742.zip | |
std: Support user-provided jsonParse method. Unify json.Parser and json.parse* (#15705)
Diffstat (limited to 'lib/std/json.zig')
| -rw-r--r-- | lib/std/json.zig | 73 |
1 files changed, 66 insertions, 7 deletions
diff --git a/lib/std/json.zig b/lib/std/json.zig index 10449cdace..2a12023c76 100644 --- a/lib/std/json.zig +++ b/lib/std/json.zig @@ -1,19 +1,73 @@ //! JSON parsing and stringification conforming to RFC 8259. https://datatracker.ietf.org/doc/html/rfc8259 //! -//! The low-level `Scanner` API reads from an input slice or successive slices of inputs, +//! The low-level `Scanner` API produces `Token`s from an input slice or successive slices of inputs, //! The `Reader` API connects a `std.io.Reader` to a `Scanner`. //! -//! The high-level `parseFromSlice` and `parseFromTokenSource` deserializes a JSON document into a Zig type. -//! The high-level `Parser` parses any JSON document into a dynamically typed `ValueTree` that has its own memory arena. +//! The high-level `parseFromSlice` and `parseFromTokenSource` deserialize a JSON document into a Zig type. +//! Parse into a dynamically-typed `Value` to load any JSON value for runtime inspection. //! //! The low-level `writeStream` emits syntax-conformant JSON tokens to a `std.io.Writer`. -//! The high-level `stringify` serializes a Zig type into JSON. +//! The high-level `stringify` serializes a Zig or `Value` type into JSON. + +const testing = @import("std").testing; +const ArrayList = @import("std").ArrayList; + +test Scanner { + var scanner = Scanner.initCompleteInput(testing.allocator, "{\"foo\": 123}\n"); + defer scanner.deinit(); + try testing.expectEqual(Token.object_begin, try scanner.next()); + try testing.expectEqualSlices(u8, "foo", (try scanner.next()).string); + try testing.expectEqualSlices(u8, "123", (try scanner.next()).number); + try testing.expectEqual(Token.object_end, try scanner.next()); + try testing.expectEqual(Token.end_of_document, try scanner.next()); +} + +test parseFromSlice { + var parsed_str = try parseFromSlice([]const u8, testing.allocator, "\"a\\u0020b\"", .{}); + defer parsed_str.deinit(); + try testing.expectEqualSlices(u8, "a b", parsed_str.value); + + const T = struct { a: i32 = -1, b: [2]u8 }; + var parsed_struct = try parseFromSlice(T, testing.allocator, "{\"b\":\"xy\"}", .{}); + defer parsed_struct.deinit(); + try testing.expectEqual(@as(i32, -1), parsed_struct.value.a); // default value + try testing.expectEqualSlices(u8, "xy", parsed_struct.value.b[0..]); +} + +test Value { + var parsed = try parseFromSlice(Value, testing.allocator, "{\"anything\": \"goes\"}", .{}); + defer parsed.deinit(); + try testing.expectEqualSlices(u8, "goes", parsed.value.object.get("anything").?.string); +} + +test writeStream { + var out = ArrayList(u8).init(testing.allocator); + defer out.deinit(); + var write_stream = writeStream(out.writer(), 99); + try write_stream.beginObject(); + try write_stream.objectField("foo"); + try write_stream.emitNumber(123); + try write_stream.endObject(); + const expected = + \\{ + \\ "foo": 123 + \\} + ; + try testing.expectEqualSlices(u8, expected, out.items); +} + +test stringify { + var out = ArrayList(u8).init(testing.allocator); + defer out.deinit(); + + const T = struct { a: i32, b: []const u8 }; + try stringify(T{ .a = 123, .b = "xy" }, .{}, out.writer()); + try testing.expectEqualSlices(u8, "{\"a\":123,\"b\":\"xy\"}", out.items); +} -pub const ValueTree = @import("json/dynamic.zig").ValueTree; pub const ObjectMap = @import("json/dynamic.zig").ObjectMap; pub const Array = @import("json/dynamic.zig").Array; pub const Value = @import("json/dynamic.zig").Value; -pub const Parser = @import("json/dynamic.zig").Parser; pub const validate = @import("json/scanner.zig").validate; pub const Error = @import("json/scanner.zig").Error; @@ -30,9 +84,11 @@ pub const isNumberFormattedLikeAnInteger = @import("json/scanner.zig").isNumberF pub const ParseOptions = @import("json/static.zig").ParseOptions; pub const parseFromSlice = @import("json/static.zig").parseFromSlice; +pub const parseFromSliceLeaky = @import("json/static.zig").parseFromSliceLeaky; pub const parseFromTokenSource = @import("json/static.zig").parseFromTokenSource; +pub const parseFromTokenSourceLeaky = @import("json/static.zig").parseFromTokenSourceLeaky; pub const ParseError = @import("json/static.zig").ParseError; -pub const parseFree = @import("json/static.zig").parseFree; +pub const Parsed = @import("json/static.zig").Parsed; pub const StringifyOptions = @import("json/stringify.zig").StringifyOptions; pub const encodeJsonString = @import("json/stringify.zig").encodeJsonString; @@ -45,6 +101,9 @@ pub const writeStream = @import("json/write_stream.zig").writeStream; // Deprecations pub const parse = @compileError("Deprecated; use parseFromSlice() or parseFromTokenSource() instead."); +pub const parseFree = @compileError("Deprecated; call Parsed(T).deinit() instead."); +pub const Parser = @compileError("Deprecated; use parseFromSlice(Value) or parseFromTokenSource(Value) instead."); +pub const ValueTree = @compileError("Deprecated; use Parsed(Value) instead."); pub const StreamingParser = @compileError("Deprecated; use json.Scanner or json.Reader instead."); pub const TokenStream = @compileError("Deprecated; use json.Scanner or json.Reader instead."); |
