From 5c5f23eb2676cc0a55d5f82a887765452ec567c7 Mon Sep 17 00:00:00 2001 From: Emil Lerch Date: Mon, 23 Aug 2021 10:16:22 -0700 Subject: [PATCH] skip value of field when field is unused (ported in from zig master) --- src/aws.zig | 36 ++++++++++++++++++++++++++++++++++++ src/json.zig | 18 ++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/aws.zig b/src/aws.zig index ce6da9d..01b6602 100644 --- a/src/aws.zig +++ b/src/aws.zig @@ -485,6 +485,42 @@ test "basic json request serialization" { \\} , buffer.items); } +test "layer object only" { + const TestResponse = struct { + arn: ?[]const u8 = null, + // uncompressed_code_size: ?i64 = null, + + pub fn jsonFieldNameFor(_: @This(), comptime field_name: []const u8) []const u8 { + const mappings = .{ + .arn = "Arn", + }; + return @field(mappings, field_name); + } + }; + const response = + \\ { + \\ "UncompressedCodeSize": 2, + \\ "Arn": "blah" + \\ } + ; + // const response = + // \\ { + // \\ "UncompressedCodeSize": 22599541, + // \\ "Arn": "arn:aws:lambda:us-west-2:550620852718:layer:PollyNotes-lib:4" + // \\ } + // ; + const allocator = std.testing.allocator; + var stream = json.TokenStream.init(response); + const parser_options = json.ParseOptions{ + .allocator = allocator, + .allow_camel_case_conversion = true, // new option + .allow_snake_case_conversion = true, // new option + .allow_unknown_fields = true, // new option. Cannot yet handle non-struct fields though + .allow_missing_fields = false, // new option. Cannot yet handle non-struct fields though + }; + const r = try json.parse(TestResponse, &stream, parser_options); + json.parseFree(TestResponse, r, parser_options); +} // Use for debugging json responses of specific requests // test "dummy request" { // const allocator = std.testing.allocator; diff --git a/src/json.zig b/src/json.zig index d6399f3..41e0015 100644 --- a/src/json.zig +++ b/src/json.zig @@ -1136,6 +1136,9 @@ pub const TokenStream = struct { return error.UnexpectedEndOfJson; } } + fn stackUsed(self: *TokenStream) u8 { + return self.parser.stack_used + if (self.token != null) @as(u8, 1) else 0; + } }; fn checkNext(p: *TokenStream, id: std.meta.Tag(Token)) !void { @@ -1532,6 +1535,20 @@ fn snakeCaseComp(field: []const u8, key: []const u8, options: ParseOptions) !boo return std.mem.eql(u8, comp_field, normalized_key); } +const SkipValueError = error{UnexpectedJsonDepth} || TokenStream.Error; + +fn skipValue(tokens: *TokenStream) SkipValueError!void { + const original_depth = tokens.stackUsed(); + + // Return an error if no value is found + _ = try tokens.next(); + if (tokens.stackUsed() < original_depth) return error.UnexpectedJsonDepth; + if (tokens.stackUsed() == original_depth) return; + + while (try tokens.next()) |_| { + if (tokens.stackUsed() == original_depth) return; + } +} fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options: ParseOptions) !T { switch (@typeInfo(T)) { @@ -1675,6 +1692,7 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options: } } if (!found and !options.allow_unknown_fields) return error.UnknownField; + if (!found) try skipValue(tokens); }, .ObjectBegin => { if (!options.allow_unknown_fields) return error.UnknownField;