fn deserialize_struct()

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())),
                ))
            }
        })))
    }