in sources/api/datastore/src/deserialization/pairs.rs [220:367]
fn deserialize_struct<V>(
mut self,
name: &'static str,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
// On the first interaction for a struct, we won't have a prefix yet, unless the user called
// from_map_with_prefix and specified it. We can make the prefix from the struct name.
// (Recursive calls will have a path but no name, because we always treat nested structures
// as maps, because we don't need any nested struct names and it lets us use the nice
// MapDeserializer.)
if !name.is_empty() {
trace!("Path before name check: {:?}", self.path);
if self.path.is_none() {
self.path = Some(
// to_lowercase handles the discrepancy between key naming and struct naming;
// this initial 'path' creation is the only place we take the struct name from
// serde, per above comment.
Key::from_segments(KeyType::Data, &[name.to_lowercase()])
.context(error::InvalidPrefix { prefix: name })?,
);
}
trace!("Path after name check: {:?}", self.path);
}
if let Some(ref path) = self.path {
// Remove the known path from the beginning of the keys. serde doesn't care about the
// name of the top-level struct, just the fields inside, so we have to remove it before
// handing it to the MapDeserializer. (Our real customer is the one specifying the
// dotted keys, and we always use the struct name there for clarity.)
trace!("Keys before path strip: {:?}", self.keys);
let mut new_keys = HashSet::new();
for key in self.keys {
new_keys.insert(key.strip_prefix_segments(&path.segments()).context(
error::StripPrefix {
prefix: path.name(),
name: key.name(),
},
)?);
}
self.keys = new_keys;
trace!("Keys after path strip: {:?}", self.keys);
}
// We have to track which structs we've already handled and skip over them. This is
// because we could get keys like "a.b.c" and "a.b.d", so we'll see that "a" prefix
// twice at the top level, but by the time we see the second one we've already recursed
// and handled all of "a" from the first one.
let mut structs_done = HashSet::new();
// As mentioned above, MapDeserializer does a lot of nice work for us. We just need to
// give it an iterator that yields (key, deserializer) pairs. The nested deserializers
// have the appropriate 'path' and a subset of 'keys' so they can do their job.
visitor.visit_map(MapDeserializer::new(self.keys.iter().filter_map(|key| {
let mut segments: VecDeque<_> = key.segments().clone().into();
// Inside this filter_map closure, we can't return early from the outer function, so we
// log an error and skip the key. Errors in this path are generally logic errors
// rather than user errors, so this isn't so bad.
let struct_name = match segments.pop_front() {
Some(s) => s,
None => {
error!("Logic error - Key segments.pop_front failed, empty Key?");
return None;
}
};
trace!("Visiting key '{}', struct name '{}'", key, &struct_name);
// At the top level (None path) we start with struct_name as Key, otherwise append
// struct_name.
trace!("Old path: {:?}", &self.path);
let path = match self.path {
None => match Key::from_segments(KeyType::Data, &[&struct_name]) {
Ok(key) => key,
Err(e) => {
error!(
"Tried to construct invalid key from struct name '{}', skipping: {}",
&struct_name, e
);
return None;
}
},
Some(ref old_path) => match old_path.append_segments(&[&struct_name]) {
Ok(key) => key,
Err(e) => {
error!(
"Appending '{}' to existing key '{}' resulted in invalid key, skipping: {}",
old_path, &struct_name, e
);
return None;
}
}
};
trace!("New path: {}", &path);
if !segments.is_empty() {
if structs_done.contains(&struct_name) {
// We've handled this structure with a recursive call, so we're done.
trace!("Already handled struct '{}', skipping", &struct_name);
None
} else {
// Otherwise, mark it, and recurse.
structs_done.insert(struct_name.clone());
// Subset the keys so the recursive call knows what it needs to handle -
// only things starting with the new path.
let keys = self
.keys
.iter()
.filter(|new_key| new_key.starts_with_segments(&[&struct_name]))
// Remove the prefix - should always work, but log and skip the key otherwise
.filter_map(|new_key| new_key
.strip_prefix(&struct_name)
.map_err(|e| error!("Key starting with segment '{}' couldn't remove it as prefix: {}", &struct_name, e)).ok())
.collect();
// And here's what MapDeserializer expects, the key and deserializer for it
trace!(
"Recursing for struct '{}' with keys: {:?}",
&struct_name,
keys
);
Some((
struct_name.to_owned(),
ValueDeserializer::Compound(CompoundDeserializer::new(
self.map,
keys,
Some(path),
)),
))
}
} else {
// No dot, so we have a scalar; hand the data to a scalar deserializer.
trace!(
"Key '{}' is scalar, getting '{}' from input to deserialize",
struct_name,
path
);
let val = self.map.get(&path)?;
Some((
struct_name,
ValueDeserializer::Scalar(deserializer_for_scalar(val.as_ref())),
))
}
})))
}