consider 2 structs, Foo and Bar, like so:
struct Foo {
foo: String,
bar: String,
}
struct Bar {
bar: String,
baz: String,
}
and, by default, unknown fields are allowed by serde. anyway, one thing that's important to note here is that serde has the IgnoredAny optimization, so we can't just deserialize Foo and then deserialize Bar, because that eats data.
let's say we want
struct FooBar {
foo: String,
bar: String,
baz: String,
}
and let's say we have {"foo": "hello", "bar:" "hello", "baz": "hello"}
. let's trace (simplified) what happens if we try to do it the naive way, but checking for the types Foo
and Bar
instead of FooBar
(this isn't how you'd do it in practice, but there are other use-cases that depend on this feature.):
1. let x: FooBar = datafu::Pattern::compile(
"(:$Foo:$Bar->'foo')(->'bar')(->'baz')", ...
).deserialize(json)?;
2. FooBar::deserialize(datafu::Deserializer)
3. datafu::Deserializer::deserialize_struct (this just starts the whole thing)
4. Predicate (Foo)
5. Foo::deserialize(datafu::Deserializer)
6. datafu::Deserializer::deserialize_struct(FooVisitor)
7. json::Deserializer::deserialize_struct(datafu::Visitor)
8. datafu::Visitor::visit_map(json::MapAccess)
9. FooVisitor::visit_map(datafu::MapAccess)
10. now here's where it gets exciting because MapAccess is pull-based.
so our only option is to deserialize this one struct and store its results.
we can't go back to "another" MapAccess to yield from it.
one "obvious" solution is to only allow one predicate, but then you lose a bunch of flexibility you'd otherwise have. for example, maybe you're using an URL library which supports multiple representations for deserializing URLs, but you want to enforce strings? you could instead do :$str:$url
and it'd require it to be a string, instead of another representation. this ability to combine predicates is very much a must-have.
in the case of JSON, luckily we can just intercept IgnoredAny
/deserialize_ignored_any
and forward it to deserialize_any
, and get all the results that way, but we want this to be as general as we can make it.