Module flatten

Source
Expand description

Similar to #[serde(flatten)] but works with serde_ignored

Our approach to deserialize a Flatten is as follows:

  • We tell the input data format (underlying deserializer) that we want a map.
  • In our visitor, we visit each key in the map in order
  • For each key, we consult Flattenable::has_field to find out which child it’s in (fields in T shadow fields in U, as with serde), and store the key and the value in the appropriate Portion. (We must store the value as a serde_value::Value since we don’t know what type it should be, and can’t know until we are ready to enter T and U’s Deserialize impls.)
  • If it’s in neither T nor U, we explicitly ignore the value
  • When we’ve processed all the fields, we call the actual deserialisers for T and U: we take on the role of the data format, giving each of T and U a map.

From the point of view of T and U, we each offer them a subset of the fields, having already rendered the keys to strings and the values to Value.

From the point of view of the data format (which might be a serde_ignored proxy) we consume the union of the fields, and ignore the rest.

§Rationale and alternatives

The key difficulty is this: we want to call Deserializer::deserialize_ignored_any on our input data format for precisely the fields which neither T nor U want. We must achieve this somehow using information from T or U. If we tried to use only the Deserialize impls, the only way to detect this is to call their deserialize methods and watch to see if they in turn call deserialize_ignored_any. But we need to be asking each of T and U this question for each field: the shape of MapAccess puts the data structure in charge of sequencing. So we would need to somehow suspend T’s deserialisation, and call U’s, and then suspend Us, and go back to T.

Other possibilities that seemed worse:

  • Use threads. We could spawn a thread for each of T and U, allowing us to run them in parallel and control their execution flow.

  • Use coroutines eg. corosensei (by Amanieu, author of hashbrown etc.)

  • Instead of suspending and restarting T and U’s deserialisation, discard the partially-deserialised T and U and restart them each time (with cloned copies of the Values). This is O(n^2) and involves much boxing.

§References

Macros§

call_any 🔒
Implement deserialize_$what as a call to deserialize_any.
call_any_for_rest 🔒
Implement most deserialize_* as calls to deserialize_any.
derive_deftly_driver_Flatten 🔒

Structs§

FieldExtractor 🔒
Stunt “data format” which we use for extracting fields for derived Flattenable impls
FieldExtractorSuccess 🔒
Error resulting from successful operation of a FieldExtractor
Flatten
Helper for flattening deserialisation, compatible with serde_ignored
FlattenVisitor 🔒
de::Visitor for Flatten
Key 🔒
Wrapper for a field name, impls de::Deserializer
Portion 🔒
The keys and values we are to direct to a particular child

Traits§

Flattenable
Types that can be used with Flatten

Functions§

flattenable_extract_fields
Extract fields of a struct, as viewed by serde

Type Aliases§

FieldList 🔒
List of fields, appears in several APIs here
FlattenError 🔒
Type alias for reified error