-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
std: Support user-provided jsonParse method. Unify json.Parser and json.parse* #15705
Conversation
The broken |
is it possible to keep function 'json.parseFree', so that the parsed objects can be free handly. |
Use an arena, as mentioned |
d78a023
to
847f2e0
Compare
@thejoshwolfe great work on this and your previous PR (streaming support is awesome!). One place I am using the old union behaviour is here:
You can see e.g. the Do you think adding a |
You could do something like this: var dynamic = try json.parseFromSliceLeaky(json.Value, arena.allocator(), s, .{});
const type = parsed.value.object.get("type").?;
if (mem.eql(u8, type, "module")) {
const module = try json.parseFromSliceLeaky(Module, arena.allocator(), s, .{});
} else if (mem.eql(...)) {
...
} It would be cool if there were a |
I can also imagine exposing the parsing of the fields of a struct not counting the If the Another very different idea is to make a super struct, rather than a union of structs, that has all possible fields, and most of them default to This is all just brainstorming, and I concede that the regression in #15602 does make your use case harder to support. But I don't think complete program is significantly more complex with these application-side implementation options. In my opinion, the old union parsing code was very complex, and (as mentioned in the previous PR) simply didn't work in a streaming context. The worst case scenario is that you could copy the old |
This really sounds like some kind of |
With allocators now required, does json parsing still work at comptime?
I don't think we should ever assume or even encourage this: json fields are unordered and anything that depends on order is going to break when someone does some valid reformatting. |
Ah, the ambiguity of the json spec. I generally agree that "json" in it's purest most abstract form has no guarantees of field order, but then it also has no guarantees of field uniqueness, or even any schema for that matter. I'm working on a project that does make assumptions about field order, because I know the code that produces it will always order things in a predictable way: https://clang.llvm.org/doxygen/JSONNodeDumper_8cpp_source.html https://clang.llvm.org/doxygen/JSONNodeDumper_8h_source.html thejoshwolfe/find-unused#1 (search for All that to say, I'm pushing back on the concept of "valid json" or "valid reformatting" in general. When json is used for communication between two or more parties, it's up to the parties involved to decide what assumptions and guarantees are to be made about the json, usually including at least field names and types of the values, but it could also include field order, number precision, heck even whitespace usage. Json itself is just a syntax and doesn't assign meaning to anything (unlike protobuf for example). All that philosophical wandering about to say: the general-purpose json package in the zig std lib should be designed with the most options feasibly possible for the user of the library. Making assumptions about field order is useful in some situations and not in others. This package allows you to care about field order or not care according to your use case. This package does not allow you to care about whitespace when parsing, but I think that's a reasonable limitation; we still do want to be motivated by real-world use cases after all. |
It might work with a fixed buffer allocator maybe. Do you have a link to a use case for this? |
Allocators currently can't be used at comptime due to some restrictions of the comptime memory model - see #14931. That probably won't be solved for a while, since it's a pretty hard problem. The Zig homepage actually uses JSON parsing at comptime as the first example a potential user ever sees of comptime - I suspect this is because JSON parsing is an easily understandable task, but is complex enough that it's "impressive" to see it done at comptime. However, I'm skeptical of whether this is actually useful in practice. If we drop this support, we should make sure someone changes the example on that page! Note that if you do want to preserve this functionality (due to seeing a convincing use case or otherwise), the new |
@thejoshwolfe ah, an example would be https://github.com/malcolmstill/zware/blob/master/test/testsuite-generated/br.json, and I think these files happen to consistently be generated with the |
847f2e0
to
2d63972
Compare
@malcolmstill take a look at #15981 . Does that kind of strategy solve your problem? |
0669bef
to
b934176
Compare
b934176
to
b6b6a90
Compare
@thejoshwolfe that worked a treat, thanks! |
This PR combines the dynamic
json.Parser
and the staticjson.parse*()
. The bundled arena strategy fromParseTree
is now available for all parsing viajson.parseFrom*()
. The old behavior is still available atjson.parseFrom*Leaky()
(name bikeshedding welcome on that one).The
parseFree()
function is gone in favor of deinitting an arena instead. The main motivation for this was to allow customizablejsonParse()
methods, and it was too hard to get customizablejsonParseFree()
methods to work.Breaking changes in this specific PR
Uses of
parseFromSlice
orparseFromTokenStream
(introduced in #15602 ) need to change.parse*Leaky
instead.defer parsed.deinit();
.parseFree()
.See also below:
Breaking changes since 0.10
json.Parser
replaced byjson.parseFromSlice(json.Value, ...)
The dynamically typed use case previously supported by:
Now accomplished like this:
json.parse
andjson.parseFree
replaced byjson.parseFromSlice
You no longer get the value directly; it's now wrapped in a
json.Parsed(T)
. Instead of callingjson.parseFree
on the value,defer parsed.deinit();
instead.Implement
jsonParse
in your classThe old
union
parsing behavior can possibly be accomplished by implementing a custom parse function. Seetools/spirv/grammar.zig
for a string-vs-int implementation of parsing into a union.Potential improvements
The
jsonParse
customization could be better documented and sanity checked. For example asserting the stack height before and after calling a user-supplied function would be nice.