From fec1e508330d7956dfee6d998dc247a711dfd91b Mon Sep 17 00:00:00 2001 From: Jason Phan Date: Fri, 25 Nov 2022 20:34:16 -0600 Subject: [PATCH] de: Add ignore_unknown_fields attribute --- src/attributes.zig | 6 +++--- src/de.zig | 2 ++ src/de/impls/ignored.zig | 8 ++++---- src/de/impls/visitor/struct.zig | 22 ++++++++++++++++++++-- src/de/interfaces/deserializer.zig | 2 +- 5 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/attributes.zig b/src/attributes.zig index 9cf9855c..01ce4071 100644 --- a/src/attributes.zig +++ b/src/attributes.zig @@ -18,7 +18,7 @@ const ContainerAttributes = struct { // Always error during deserialization when encountering unknown fields. // // This attribute isn't compatible with `flatten`. - //deny_unknown_fields: bool = false, + ignore_unknown_fields: bool = false, // Deserialize this type by deserializing into the given type, then // converting. @@ -71,8 +71,8 @@ const FieldAttributes = struct { // Flatten the contents of this field into the container it is // defined in. // - // This attribute is not compatible with the - // deny_unknown_fields attribute. + // This attribute is not compatible with the ignore_unknown_fields + // attribute. //flatten: bool = false, // Serialize and deserialize this field with the given name diff --git a/src/de.zig b/src/de.zig index 3cf2f039..90ec21c4 100644 --- a/src/de.zig +++ b/src/de.zig @@ -74,6 +74,8 @@ pub const de = struct { pub const Seed = @import("de/interfaces/seed.zig").Seed; pub const DefaultSeed = @import("de/impls/seed/default.zig").DefaultSeed; + pub const Ignored = @import("de/impls/ignored.zig").Ignored; + /// Frees resources allocated during Getty deserialization. /// /// Values that cannot be deallocated, such as `bool` values, are ignored. diff --git a/src/de/impls/ignored.zig b/src/de/impls/ignored.zig index f7ced968..62bc1a1c 100644 --- a/src/de/impls/ignored.zig +++ b/src/de/impls/ignored.zig @@ -1,19 +1,19 @@ const std = @import("std"); -const de = @import("../../../de.zig"); +const de = @import("../../de.zig").de; /// Default `getty.de.Seed` implementation. -const Ignored = struct { +pub const Ignored = struct { const Value = void; - pub usingnamespace de.de.Seed( + pub usingnamespace de.Seed( Ignored, Value, .{ .deserialize = deserialize }, ); fn deserialize(i: Ignored, allocator: ?std.mem.Allocator, deserializer: anytype) @TypeOf(deserializer).Error!Value { - return try deserializer.deserializeIgnored(allocator, i); + return try deserializer.deserializeIgnored(allocator, i.visitor()); } pub usingnamespace de.Visitor( diff --git a/src/de/impls/visitor/struct.zig b/src/de/impls/visitor/struct.zig index 44cd424d..16d66e63 100644 --- a/src/de/impls/visitor/struct.zig +++ b/src/de/impls/visitor/struct.zig @@ -31,6 +31,20 @@ pub fn Visitor(comptime Struct: type) type { } } + const ignore_unknown_fields = comptime blk: { + if (attributes) |attrs| { + if (@hasField(@TypeOf(attrs), "Container")) { + const attr = attrs.Container; + + if (@hasField(@TypeOf(attr), "ignore_unknown_fields") and attr.ignore_unknown_fields) { + break :blk true; + } + } + } + + break :blk false; + }; + key_loop: while (try map.nextKey(allocator, []const u8)) |key| { var found = false; @@ -75,9 +89,10 @@ pub fn Visitor(comptime Struct: type) type { } } + // Deserialize and assign value to field. switch (field.is_comptime) { - true => @compileError("TODO"), false => @field(structure, field.name) = try map.nextValue(allocator, field.field_type), + true => @compileError("TODO"), } seen[i] = true; @@ -88,7 +103,10 @@ pub fn Visitor(comptime Struct: type) type { } if (!found) { - return error.UnknownField; + switch (ignore_unknown_fields) { + true => _ = try map.nextValueSeed(allocator, (de.Ignored{}).seed()), + false => return error.UnknownField, + } } } diff --git a/src/de/interfaces/deserializer.zig b/src/de/interfaces/deserializer.zig index 1140bab0..afd309c2 100644 --- a/src/de/interfaces/deserializer.zig +++ b/src/de/interfaces/deserializer.zig @@ -164,7 +164,7 @@ pub fn Deserializer( @compileError("deserializeFloat is not implemented by type: " ++ @typeName(Context)); } - /// Hint that the value being deserialized into is expecting to + /// Hint that the type being deserialized into is expecting to /// deserialize a value whose type does not matter because it is /// ignored. pub fn deserializeIgnored(self: Self, allocator: ?std.mem.Allocator, visitor: anytype) Return(@TypeOf(visitor)) {