Skip to content

Commit

Permalink
de: Add ignore_unknown_fields attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
Jason Phan committed Nov 26, 2022
1 parent f6abd4b commit fec1e50
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 10 deletions.
6 changes: 3 additions & 3 deletions src/attributes.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions src/de.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
8 changes: 4 additions & 4 deletions src/de/impls/ignored.zig
Original file line number Diff line number Diff line change
@@ -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(
Expand Down
22 changes: 20 additions & 2 deletions src/de/impls/visitor/struct.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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,
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/de/interfaces/deserializer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down

0 comments on commit fec1e50

Please sign in to comment.