Module tor_config::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 appropriatePortion
. (We must store the value as aserde_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’sDeserialize
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 U
s, and go back to T
.
Other possibilities that seemed worse:
-
Use threads. We could spawn a thread for each of
T
andU
, 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
andU
’s deserialisation, discard the partially-deserialisedT
andU
and restart them each time (with cloned copies of theValue
s). This is O(n^2) and involves much boxing.
§References
-
Tickets against
serde-ignored
: https://github.com/dtolnay/serde-ignored/issues/17 https://github.com/dtolnay/serde-ignored/issues/10 -
Workaround with
HashMap
that doesn’t quite work right: https://github.com/dtolnay/serde-ignored/issues/10#issuecomment-1044058310 https://github.com/serde-rs/serde/issues/2176 -
Discussion in Tor Project gitlab re Arti configuration: https://gitlab.torproject.org/tpo/core/arti/-/merge_requests/1599#note_2944510
Macros§
- call_any 🔒Implement
deserialize_$what
as a call todeserialize_any
. - Implement most
deserialize_*
as calls todeserialize_any
.
Structs§
- Stunt “data format” which we use for extracting fields for derived
Flattenable
impls - Error resulting from successful operation of a
FieldExtractor
- Helper for flattening deserialisation, compatible with
serde_ignored
de::Visitor
forFlatten
- Key 🔒Wrapper for a field name, impls
de::Deserializer
- Portion 🔒The keys and values we are to direct to a particular child
Traits§
- Types that can be used with
Flatten
Functions§
- Extract fields of a struct, as viewed by
serde
Type Aliases§
- List of fields, appears in several APIs here
- Type alias for reified error