#
cargo/util/context/
de.rs

    1//! Deserialization for converting [`ConfigValue`] instances to target types.
    2//!
    3//! The [`Deserializer`] type is the main driver of deserialization.
    4//! The workflow is roughly:
    5//!
    6//! 1. [`GlobalContext::get<T>()`] creates [`Deserializer`] and calls `T::deserialize()`
    7//! 2. Then call type-specific deserialize methods as in normal serde deserialization.
    8//!     - For primitives, `deserialize_*` methods look up [`ConfigValue`] instances
    9//!       in [`GlobalContext`] and convert.
    10//!     - Structs and maps are handled by [`ConfigMapAccess`].
    11//!     - Sequences are handled by [`ConfigSeqAccess`],
    12//!       which later uses [`ArrayItemDeserializer`] for each array item.
    13//!     - [`Value<T>`] is delegated to [`ValueDeserializer`] in `deserialize_struct`.
    14//!
    15//! The purpose of this workflow is to:
    16//!
    17//! - Retrieve the correct config value based on source location precedence
    18//! - Provide richer error context showing where a config is defined
    19//! - Provide a richer internal API to map to concrete config types
    20//!   without touching underlying [`ConfigValue`] directly
    21//!
    22//! [`ConfigValue`]: CV
    23
    24use crate::util::context::key::ArrayItemKeyPath;
    25use crate::util::context::value;
    26use crate::util::context::{ConfigError, ConfigKey, GlobalContext};
    27use crate::util::context::{ConfigValue as CV, Definition, Value};
    28use serde::{de, de::IntoDeserializer};
    29use std::collections::HashSet;
    30use std::vec;
    31
    32/// Serde deserializer used to convert config values to a target type using
    33/// [`GlobalContext::get`].
    34#[derive(Clone)]
    35pub(super) struct Deserializer<'gctx> {
    36    pub(super) gctx: &'gctx GlobalContext,
    37    /// The current key being deserialized.
    38    pub(super) key: ConfigKey,
    39    /// Whether or not this key part is allowed to be an inner table. For
    40    /// example, `profile.dev.build-override` needs to check if
    41    /// `CARGO_PROFILE_DEV_BUILD_OVERRIDE_` prefixes exist. But
    42    /// `CARGO_BUILD_TARGET` should not check for prefixes because it would
    43    /// collide with `CARGO_BUILD_TARGET_DIR`. See `ConfigMapAccess` for
    44    /// details.
    45    pub(super) env_prefix_ok: bool,
    46}
    47
    48macro_rules! deserialize_method {
    49    ($method:ident, $visit:ident, $getter:ident) => {
    50        fn $method<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    51        where
    52            V: de::Visitor<'de>,
    53        {
    54            let v = self
    55                .gctx
    56                .$getter(&self.key)?
    57                .ok_or_else(|| ConfigError::missing(&self.key))?;
    58            let Value { val, definition } = v;
    59            let res: Result<V::Value, ConfigError> = visitor.$visit(val);
    60            res.map_err(|e| e.with_key_context(&self.key, Some(definition)))
    61        }
    62    };
    63}
    64
    65impl<'de, 'gctx> de::Deserializer<'de> for Deserializer<'gctx> {
    66    type Error = ConfigError;
    67
    68    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    69    where
    70        V: de::Visitor<'de>,
    71    {
    72        let cv = self.gctx.get_cv_with_env(&self.key)?;
    73        if let Some(cv) = cv {
    74            let res: (Result<V::Value, ConfigError>, Definition) = match cv {
    75                CV::Integer(i, def) => (visitor.visit_i64(i), def),
    76                CV::String(s, def) => (visitor.visit_string(s), def),
    77                CV::List(_, def) => (visitor.visit_seq(ConfigSeqAccess::new(self.clone())?), def),
    78                CV::Table(_, def) => (
    79                    visitor.visit_map(ConfigMapAccess::new_map(self.clone())?),
    80                    def,
    81                ),
    82                CV::Boolean(b, def) => (visitor.visit_bool(b), def),
    83            };
    84            let (res, def) = res;
    85            return res.map_err(|e| e.with_key_context(&self.key, Some(def)));
    86        }
    87
    88        // The effect here is the same as in `deserialize_option`.
    89        if self.gctx.has_key(&self.key, self.env_prefix_ok)? {
    90            return visitor.visit_some(self);
    91        }
    92
    93        Err(ConfigError::missing(&self.key))
    94    }
    95
    96    deserialize_method!(deserialize_bool, visit_bool, get_bool);
    97    deserialize_method!(deserialize_i8, visit_i64, get_integer);
    98    deserialize_method!(deserialize_i16, visit_i64, get_integer);
    99    deserialize_method!(deserialize_i32, visit_i64, get_integer);
    100    deserialize_method!(deserialize_i64, visit_i64, get_integer);
    101    deserialize_method!(deserialize_u8, visit_i64, get_integer);
    102    deserialize_method!(deserialize_u16, visit_i64, get_integer);
    103    deserialize_method!(deserialize_u32, visit_i64, get_integer);
    104    deserialize_method!(deserialize_u64, visit_i64, get_integer);
    105    deserialize_method!(deserialize_string, visit_string, get_string_priv);
    106
    107    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    108    where
    109        V: de::Visitor<'de>,
    110    {
    111        if self.gctx.has_key(&self.key, self.env_prefix_ok)? {
    112            visitor.visit_some(self)
    113        } else {
    114            // Treat missing values as `None`.
    115            visitor.visit_none()
    116        }
    117    }
    118
    119    fn deserialize_struct<V>(
    120        self,
    121        name: &'static str,
    122        fields: &'static [&'static str],
    123        visitor: V,
    124    ) -> Result<V::Value, Self::Error>
    125    where
    126        V: de::Visitor<'de>,
    127    {
    128        // Match on the magical struct name/field names that are passed in to
    129        // detect when we're deserializing `Value<T>`.
    130        //
    131        // See more comments in `value.rs` for the protocol used here.
    132        if name == value::NAME && fields == value::FIELDS {
    133            let source = ValueSource::with_deserializer(self)?;
    134            return visitor.visit_map(ValueDeserializer::new(source));
    135        }
    136        visitor.visit_map(ConfigMapAccess::new_struct(self, fields)?)
    137    }
    138
    139    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    140    where
    141        V: de::Visitor<'de>,
    142    {
    143        visitor.visit_map(ConfigMapAccess::new_map(self)?)
    144    }
    145
    146    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    147    where
    148        V: de::Visitor<'de>,
    149    {
    150        visitor.visit_seq(ConfigSeqAccess::new(self)?)
    151    }
    152
    153    fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
    154    where
    155        V: de::Visitor<'de>,
    156    {
    157        visitor.visit_seq(ConfigSeqAccess::new(self)?)
    158    }
    159
    160    fn deserialize_tuple_struct<V>(
    161        self,
    162        _name: &'static str,
    163        _len: usize,
    164        visitor: V,
    165    ) -> Result<V::Value, Self::Error>
    166    where
    167        V: de::Visitor<'de>,
    168    {
    169        visitor.visit_seq(ConfigSeqAccess::new(self)?)
    170    }
    171
    172    fn deserialize_newtype_struct<V>(
    173        self,
    174        name: &'static str,
    175        visitor: V,
    176    ) -> Result<V::Value, Self::Error>
    177    where
    178        V: de::Visitor<'de>,
    179    {
    180        if name == "StringList" {
    181            let mut res = Vec::new();
    182
    183            match self.gctx.get_cv(&self.key)? {
    184                Some(CV::List(val, _def)) => res.extend(val),
    185                Some(CV::String(val, def)) => {
    186                    let split_vs = val
    187                        .split_whitespace()
    188                        .map(|s| CV::String(s.to_string(), def.clone()));
    189                    res.extend(split_vs);
    190                }
    191                Some(val) => {
    192                    self.gctx
    193                        .expected("string or array of strings", &self.key, &val)?;
    194                }
    195                None => {}
    196            }
    197
    198            self.gctx.get_env_list(&self.key, &mut res)?;
    199
    200            let vals: Vec<String> = res
    201                .into_iter()
    202                .map(|val| match val {
    203                    CV::String(s, _definition) => Ok(s),
    204                    other => Err(ConfigError::expected(&self.key, "string", &other)),
    205                })
    206                .collect::<Result<_, _>>()?;
    207            visitor.visit_newtype_struct(vals.into_deserializer())
    208        } else {
    209            visitor.visit_newtype_struct(self)
    210        }
    211    }
    212
    213    fn deserialize_enum<V>(
    214        self,
    215        _name: &'static str,
    216        _variants: &'static [&'static str],
    217        visitor: V,
    218    ) -> Result<V::Value, Self::Error>
    219    where
    220        V: de::Visitor<'de>,
    221    {
    222        let value = self
    223            .gctx
    224            .get_string_priv(&self.key)?
    225            .ok_or_else(|| ConfigError::missing(&self.key))?;
    226
    227        let Value { val, definition } = value;
    228        visitor
    229            .visit_enum(val.into_deserializer())
    230            .map_err(|e: ConfigError| e.with_key_context(&self.key, Some(definition)))
    231    }
    232
    233    // These aren't really supported, yet.
    234    serde::forward_to_deserialize_any! {
    235        f32 f64 char str bytes
    236        byte_buf unit unit_struct
    237        identifier ignored_any
    238    }
    239}
    240
    241struct ConfigMapAccess<'gctx> {
    242    de: Deserializer<'gctx>,
    243    /// The fields that this map should deserialize.
    244    fields: Vec<KeyKind>,
    245    /// Current field being deserialized.
    246    field_index: usize,
    247}
    248
    249#[derive(Debug, PartialEq, Eq, Hash)]
    250enum KeyKind {
    251    Normal(String),
    252    CaseSensitive(String),
    253}
    254
    255impl<'gctx> ConfigMapAccess<'gctx> {
    256    fn new_map(de: Deserializer<'gctx>) -> Result<ConfigMapAccess<'gctx>, ConfigError> {
    257        let mut fields = Vec::new();
    258        if let Some(mut v) = de.gctx.get_table(&de.key)? {
    259            // `v: Value<HashMap<String, CV>>`
    260            for (key, _value) in v.val.drain() {
    261                fields.push(KeyKind::CaseSensitive(key));
    262            }
    263        }
    264        if de.gctx.cli_unstable().advanced_env {
    265            // `CARGO_PROFILE_DEV_PACKAGE_`
    266            let env_prefix = format!("{}_", de.key.as_env_key());
    267            for env_key in de.gctx.env_keys() {
    268                // `CARGO_PROFILE_DEV_PACKAGE_bar_OPT_LEVEL = 3`
    269                if let Some(rest) = env_key.strip_prefix(&env_prefix) {
    270                    // `rest = bar_OPT_LEVEL`
    271                    let part = rest.splitn(2, '_').next().unwrap();
    272                    // `part = "bar"`
    273                    fields.push(KeyKind::CaseSensitive(part.to_string()));
    274                }
    275            }
    276        }
    277        Ok(ConfigMapAccess {
    278            de,
    279            fields,
    280            field_index: 0,
    281        })
    282    }
    283
    284    fn new_struct(
    285        de: Deserializer<'gctx>,
    286        given_fields: &'static [&'static str],
    287    ) -> Result<ConfigMapAccess<'gctx>, ConfigError> {
    288        let table = de.gctx.get_table(&de.key)?;
    289
    290        // Assume that if we're deserializing a struct it exhaustively lists all
    291        // possible fields on this key that we're *supposed* to use, so take
    292        // this opportunity to warn about any keys that aren't recognized as
    293        // fields and warn about them.
    294        if let Some(v) = table.as_ref() {
    295            let unused_keys = v
    296                .val
    297                .iter()
    298                .filter(|(k, _v)| !given_fields.iter().any(|gk| gk == k));
    299            for (unused_key, unused_value) in unused_keys {
    300                de.gctx.shell().warn(format!(
    301                    "unused config key `{}.{}` in `{}`",
    302                    de.key,
    303                    unused_key,
    304                    unused_value.definition()
    305                ))?;
    306            }
    307        }
    308
    309        let mut fields = HashSet::new();
    310
    311        // If the caller is interested in a field which we can provide from
    312        // the environment, get it from there.
    313        for field in given_fields {
    314            let mut field_key = de.key.clone();
    315            field_key.push(field);
    316            for env_key in de.gctx.env_keys() {
    317                let Some(nested_field) = env_key.strip_prefix(field_key.as_env_key()) else {
    318                    continue;
    319                };
    320                // This distinguishes fields that share the same prefix.
    321                // For example, when env_key is UNSTABLE_GITOXIDE_FETCH
    322                // and field_key is UNSTABLE_GIT, the field shouldn't be
    323                // added because `unstable.gitoxide.fetch` doesn't
    324                // belong to `unstable.git` struct.
    325                if nested_field.is_empty() || nested_field.starts_with('_') {
    326                    fields.insert(KeyKind::Normal(field.to_string()));
    327                }
    328            }
    329        }
    330
    331        // Add everything from the config table we're interested in that we
    332        // haven't already provided via an environment variable
    333        if let Some(v) = table {
    334            for key in v.val.keys() {
    335                fields.insert(KeyKind::Normal(key.clone()));
    336            }
    337        }
    338
    339        Ok(ConfigMapAccess {
    340            de,
    341            fields: fields.into_iter().collect(),
    342            field_index: 0,
    343        })
    344    }
    345}
    346
    347impl<'de, 'gctx> de::MapAccess<'de> for ConfigMapAccess<'gctx> {
    348    type Error = ConfigError;
    349
    350    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
    351    where
    352        K: de::DeserializeSeed<'de>,
    353    {
    354        if self.field_index >= self.fields.len() {
    355            return Ok(None);
    356        }
    357        let field = match &self.fields[self.field_index] {
    358            KeyKind::Normal(s) | KeyKind::CaseSensitive(s) => s.as_str(),
    359        };
    360        seed.deserialize(field.into_deserializer()).map(Some)
    361    }
    362
    363    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
    364    where
    365        V: de::DeserializeSeed<'de>,
    366    {
    367        let field = &self.fields[self.field_index];
    368        self.field_index += 1;
    369        // Set this as the current key in the deserializer.
    370        let field = match field {
    371            KeyKind::Normal(field) => {
    372                self.de.key.push(field);
    373                field
    374            }
    375            KeyKind::CaseSensitive(field) => {
    376                self.de.key.push_sensitive(field);
    377                field
    378            }
    379        };
    380        // Env vars that are a prefix of another with a dash/underscore cannot
    381        // be supported by our serde implementation, so check for them here.
    382        // Example:
    383        //     CARGO_BUILD_TARGET
    384        //     CARGO_BUILD_TARGET_DIR
    385        // or
    386        //     CARGO_PROFILE_DEV_DEBUG
    387        //     CARGO_PROFILE_DEV_DEBUG_ASSERTIONS
    388        // The `deserialize_option` method does not know the type of the field.
    389        // If the type is an Option<struct> (like
    390        // `profile.dev.build-override`), then it needs to check for env vars
    391        // starting with CARGO_FOO_BAR_. This is a problem for keys like
    392        // CARGO_BUILD_TARGET because checking for a prefix would incorrectly
    393        // match CARGO_BUILD_TARGET_DIR. `deserialize_option` would have no
    394        // choice but to call `visit_some()` which would then fail if
    395        // CARGO_BUILD_TARGET isn't set. So we check for these prefixes and
    396        // disallow them here.
    397        let env_prefix = format!("{}_", field).replace('-', "_");
    398        let env_prefix_ok = !self.fields.iter().any(|field| {
    399            let field = match field {
    400                KeyKind::Normal(s) | KeyKind::CaseSensitive(s) => s.as_str(),
    401            };
    402            field.replace('-', "_").starts_with(&env_prefix)
    403        });
    404
    405        let result = seed
    406            .deserialize(Deserializer {
    407                gctx: self.de.gctx,
    408                key: self.de.key.clone(),
    409                env_prefix_ok,
    410            })
    411            .map_err(|e| {
    412                if !e.is_missing_field() {
    413                    return e;
    414                }
    415                e.with_key_context(
    416                    &self.de.key,
    417                    self.de
    418                        .gctx
    419                        .get_cv_with_env(&self.de.key)
    420                        .ok()
    421                        .and_then(|cv| cv.map(|cv| cv.definition().clone())),
    422                )
    423            });
    424        self.de.key.pop();
    425        result
    426    }
    427}
    428
    429struct ConfigSeqAccess<'gctx> {
    430    de: Deserializer<'gctx>,
    431    list_iter: std::iter::Enumerate<vec::IntoIter<CV>>,
    432}
    433
    434impl ConfigSeqAccess<'_> {
    435    fn new(de: Deserializer<'_>) -> Result<ConfigSeqAccess<'_>, ConfigError> {
    436        let mut res = Vec::new();
    437
    438        match de.gctx.get_cv(&de.key)? {
    439            Some(CV::List(val, _definition)) => {
    440                res.extend(val);
    441            }
    442            Some(val) => {
    443                de.gctx.expected("list", &de.key, &val)?;
    444            }
    445            None => {}
    446        }
    447
    448        de.gctx.get_env_list(&de.key, &mut res)?;
    449
    450        Ok(ConfigSeqAccess {
    451            de,
    452            list_iter: res.into_iter().enumerate(),
    453        })
    454    }
    455}
    456
    457impl<'de, 'gctx> de::SeqAccess<'de> for ConfigSeqAccess<'gctx> {
    458    type Error = ConfigError;
    459
    460    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
    461    where
    462        T: de::DeserializeSeed<'de>,
    463    {
    464        let Some((i, cv)) = self.list_iter.next() else {
    465            return Ok(None);
    466        };
    467
    468        let mut key_path = ArrayItemKeyPath::new(self.de.key.clone());
    469        let definition = Some(cv.definition().clone());
    470        let de = ArrayItemDeserializer {
    471            cv,
    472            key_path: &mut key_path,
    473        };
    474        seed.deserialize(de)
    475            .map_err(|e| {
    476                // This along with ArrayItemKeyPath provide a better error context of the
    477                // ConfigValue definition + the key path within an array item that native
    478                // TOML key path can't express. For example, `foo.bar[3].baz`.
    479                key_path.push_index(i);
    480                e.with_array_item_key_context(&key_path, definition)
    481            })
    482            .map(Some)
    483    }
    484}
    485
    486/// Source of data for [`ValueDeserializer`]
    487enum ValueSource<'gctx, 'err> {
    488    /// The deserializer used to actually deserialize a Value struct.
    489    Deserializer {
    490        de: Deserializer<'gctx>,
    491        definition: Definition,
    492    },
    493    /// A [`ConfigValue`](CV).
    494    ///
    495    /// This is used for situations where you can't address type via a TOML key,
    496    /// such as a value inside an array.
    497    /// The [`ConfigSeqAccess`] doesn't know what type it should deserialize to
    498    /// so [`ArrayItemDeserializer`] needs to be able to handle all of them.
    499    ConfigValue {
    500        cv: CV,
    501        key_path: &'err mut ArrayItemKeyPath,
    502    },
    503}
    504
    505impl<'gctx, 'err> ValueSource<'gctx, 'err> {
    506    fn with_deserializer(de: Deserializer<'gctx>) -> Result<ValueSource<'gctx, 'err>, ConfigError> {
    507        // Figure out where this key is defined.
    508        let definition = {
    509            let env = de.key.as_env_key();
    510            let env_def = Definition::Environment(env.to_string());
    511            match (de.gctx.env.contains_key(env), de.gctx.get_cv(&de.key)?) {
    512                (true, Some(cv)) => {
    513                    // Both, pick highest priority.
    514                    if env_def.is_higher_priority(cv.definition()) {
    515                        env_def
    516                    } else {
    517                        cv.definition().clone()
    518                    }
    519                }
    520                (false, Some(cv)) => cv.definition().clone(),
    521                // Assume it is an environment, even if the key is not set.
    522                // This can happen for intermediate tables, like
    523                // CARGO_FOO_BAR_* where `CARGO_FOO_BAR` is not set.
    524                (_, None) => env_def,
    525            }
    526        };
    527
    528        Ok(Self::Deserializer { de, definition })
    529    }
    530
    531    fn with_cv(cv: CV, key_path: &'err mut ArrayItemKeyPath) -> ValueSource<'gctx, 'err> {
    532        ValueSource::ConfigValue { cv, key_path }
    533    }
    534}
    535
    536/// This is a deserializer that deserializes into a `Value<T>` for
    537/// configuration.
    538///
    539/// This is a special deserializer because it deserializes one of its struct
    540/// fields into the location that this configuration value was defined in.
    541///
    542/// See more comments in `value.rs` for the protocol used here.
    543struct ValueDeserializer<'gctx, 'err> {
    544    hits: u32,
    545    source: ValueSource<'gctx, 'err>,
    546}
    547
    548impl<'gctx, 'err> ValueDeserializer<'gctx, 'err> {
    549    fn new(source: ValueSource<'gctx, 'err>) -> ValueDeserializer<'gctx, 'err> {
    550        Self { hits: 0, source }
    551    }
    552
    553    fn definition(&self) -> &Definition {
    554        match &self.source {
    555            ValueSource::Deserializer { definition, .. } => definition,
    556            ValueSource::ConfigValue { cv, .. } => cv.definition(),
    557        }
    558    }
    559}
    560
    561impl<'de, 'gctx, 'err> de::MapAccess<'de> for ValueDeserializer<'gctx, 'err> {
    562    type Error = ConfigError;
    563
    564    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
    565    where
    566        K: de::DeserializeSeed<'de>,
    567    {
    568        self.hits += 1;
    569        match self.hits {
    570            1 => seed
    571                .deserialize(value::VALUE_FIELD.into_deserializer())
    572                .map(Some),
    573            2 => seed
    574                .deserialize(value::DEFINITION_FIELD.into_deserializer())
    575                .map(Some),
    576            _ => Ok(None),
    577        }
    578    }
    579
    580    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
    581    where
    582        V: de::DeserializeSeed<'de>,
    583    {
    584        // If this is the first time around we deserialize the `value` field
    585        // which is the actual deserializer
    586        if self.hits == 1 {
    587            return match &mut self.source {
    588                ValueSource::Deserializer { de, definition } => seed
    589                    .deserialize(de.clone())
    590                    .map_err(|e| e.with_key_context(&de.key, Some(definition.clone()))),
    591                ValueSource::ConfigValue { cv, key_path } => {
    592                    let de = ArrayItemDeserializer {
    593                        cv: cv.clone(),
    594                        key_path,
    595                    };
    596                    seed.deserialize(de)
    597                }
    598            };
    599        }
    600
    601        // ... otherwise we're deserializing the `definition` field, so we need
    602        // to figure out where the field we just deserialized was defined at.
    603        match self.definition() {
    604            Definition::BuiltIn => seed.deserialize(0.into_deserializer()),
    605            Definition::Path(path) => {
    606                seed.deserialize(Tuple2Deserializer(1i32, path.to_string_lossy()))
    607            }
    608            Definition::Environment(env) => {
    609                seed.deserialize(Tuple2Deserializer(2i32, env.as_str()))
    610            }
    611            Definition::Cli(path) => {
    612                let s = path
    613                    .as_ref()
    614                    .map(|p| p.to_string_lossy())
    615                    .unwrap_or_default();
    616                seed.deserialize(Tuple2Deserializer(3i32, s))
    617            }
    618        }
    619    }
    620}
    621
    622/// A deserializer for individual [`ConfigValue`](CV) items in arrays
    623///
    624/// It is implemented to handle any types inside a sequence, like `Vec<String>`,
    625/// `Vec<Value<i32>>`, or even `Vev<HashMap<String, Vec<bool>>>`.
    626struct ArrayItemDeserializer<'err> {
    627    cv: CV,
    628    key_path: &'err mut ArrayItemKeyPath,
    629}
    630
    631impl<'de, 'err> de::Deserializer<'de> for ArrayItemDeserializer<'err> {
    632    type Error = ConfigError;
    633
    634    fn deserialize_struct<V>(
    635        self,
    636        name: &'static str,
    637        fields: &'static [&'static str],
    638        visitor: V,
    639    ) -> Result<V::Value, Self::Error>
    640    where
    641        V: de::Visitor<'de>,
    642    {
    643        // Match on the magical struct name/field names that are passed in to
    644        // detect when we're deserializing `Value<T>`.
    645        //
    646        // See more comments in `value.rs` for the protocol used here.
    647        if name == value::NAME && fields == value::FIELDS {
    648            let source = ValueSource::with_cv(self.cv, self.key_path);
    649            return visitor.visit_map(ValueDeserializer::new(source));
    650        }
    651        visitor.visit_map(ArrayItemMapAccess::with_struct(
    652            self.cv,
    653            fields,
    654            self.key_path,
    655        ))
    656    }
    657
    658    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    659    where
    660        V: de::Visitor<'de>,
    661    {
    662        match self.cv {
    663            CV::String(s, _) => visitor.visit_string(s),
    664            CV::Integer(i, _) => visitor.visit_i64(i),
    665            CV::Boolean(b, _) => visitor.visit_bool(b),
    666            l @ CV::List(_, _) => visitor.visit_seq(ArrayItemSeqAccess::new(l, self.key_path)),
    667            t @ CV::Table(_, _) => visitor.visit_map(ArrayItemMapAccess::new(t, self.key_path)),
    668        }
    669    }
    670
    671    // Forward everything to deserialize_any
    672    serde::forward_to_deserialize_any! {
    673        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
    674        bytes byte_buf map option unit newtype_struct
    675        ignored_any unit_struct tuple_struct tuple enum identifier
    676    }
    677}
    678
    679/// Sequence access for nested arrays within [`ArrayItemDeserializer`]
    680struct ArrayItemSeqAccess<'err> {
    681    items: std::iter::Enumerate<vec::IntoIter<CV>>,
    682    key_path: &'err mut ArrayItemKeyPath,
    683}
    684
    685impl<'err> ArrayItemSeqAccess<'err> {
    686    fn new(cv: CV, key_path: &'err mut ArrayItemKeyPath) -> ArrayItemSeqAccess<'err> {
    687        let items = match cv {
    688            CV::List(list, _) => list.into_iter().enumerate(),
    689            _ => unreachable!("must be a list"),
    690        };
    691        Self { items, key_path }
    692    }
    693}
    694
    695impl<'de, 'err> de::SeqAccess<'de> for ArrayItemSeqAccess<'err> {
    696    type Error = ConfigError;
    697
    698    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
    699    where
    700        T: de::DeserializeSeed<'de>,
    701    {
    702        match self.items.next() {
    703            Some((i, cv)) => {
    704                let de = ArrayItemDeserializer {
    705                    cv,
    706                    key_path: self.key_path,
    707                };
    708                seed.deserialize(de)
    709                    .inspect_err(|_| self.key_path.push_index(i))
    710                    .map(Some)
    711            }
    712            None => Ok(None),
    713        }
    714    }
    715}
    716
    717/// Map access for nested tables within [`ArrayItemDeserializer`]
    718struct ArrayItemMapAccess<'err> {
    719    cv: CV,
    720    keys: vec::IntoIter<String>,
    721    current_key: Option<String>,
    722    key_path: &'err mut ArrayItemKeyPath,
    723}
    724
    725impl<'err> ArrayItemMapAccess<'err> {
    726    fn new(cv: CV, key_path: &'err mut ArrayItemKeyPath) -> Self {
    727        let keys = match &cv {
    728            CV::Table(map, _) => map.keys().cloned().collect::<Vec<_>>().into_iter(),
    729            _ => unreachable!("must be a map"),
    730        };
    731        Self {
    732            cv,
    733            keys,
    734            current_key: None,
    735            key_path,
    736        }
    737    }
    738
    739    fn with_struct(cv: CV, given_fields: &[&str], key_path: &'err mut ArrayItemKeyPath) -> Self {
    740        // TODO: We might want to warn unused fields,
    741        // like what we did in ConfigMapAccess::new_struct
    742        let keys = given_fields
    743            .into_iter()
    744            .map(|s| s.to_string())
    745            .collect::<Vec<_>>()
    746            .into_iter();
    747        Self {
    748            cv,
    749            keys,
    750            current_key: None,
    751            key_path,
    752        }
    753    }
    754}
    755
    756impl<'de, 'err> de::MapAccess<'de> for ArrayItemMapAccess<'err> {
    757    type Error = ConfigError;
    758
    759    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
    760    where
    761        K: de::DeserializeSeed<'de>,
    762    {
    763        match self.keys.next() {
    764            Some(key) => {
    765                self.current_key = Some(key.clone());
    766                seed.deserialize(key.into_deserializer()).map(Some)
    767            }
    768            None => Ok(None),
    769        }
    770    }
    771
    772    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
    773    where
    774        V: de::DeserializeSeed<'de>,
    775    {
    776        let key = self.current_key.take().unwrap();
    777        match &self.cv {
    778            CV::Table(map, _) => {
    779                if let Some(cv) = map.get(&key) {
    780                    let de = ArrayItemDeserializer {
    781                        cv: cv.clone(),
    782                        key_path: self.key_path,
    783                    };
    784                    seed.deserialize(de)
    785                        .inspect_err(|_| self.key_path.push_key(key))
    786                } else {
    787                    Err(ConfigError::new(
    788                        format!("missing config key `{key}`"),
    789                        self.cv.definition().clone(),
    790                    ))
    791                }
    792            }
    793            _ => Err(ConfigError::new(
    794                "expected table".to_string(),
    795                self.cv.definition().clone(),
    796            )),
    797        }
    798    }
    799}
    800
    801/// A deserializer which takes two values and deserializes into a tuple of those
    802/// two values. This is similar to types like `StrDeserializer` in upstream
    803/// serde itself.
    804struct Tuple2Deserializer<T, U>(T, U);
    805
    806impl<'de, T, U> de::Deserializer<'de> for Tuple2Deserializer<T, U>
    807where
    808    T: IntoDeserializer<'de, ConfigError>,
    809    U: IntoDeserializer<'de, ConfigError>,
    810{
    811    type Error = ConfigError;
    812
    813    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, ConfigError>
    814    where
    815        V: de::Visitor<'de>,
    816    {
    817        struct SeqVisitor<T, U> {
    818            first: Option<T>,
    819            second: Option<U>,
    820        }
    821        impl<'de, T, U> de::SeqAccess<'de> for SeqVisitor<T, U>
    822        where
    823            T: IntoDeserializer<'de, ConfigError>,
    824            U: IntoDeserializer<'de, ConfigError>,
    825        {
    826            type Error = ConfigError;
    827            fn next_element_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
    828            where
    829                K: de::DeserializeSeed<'de>,
    830            {
    831                if let Some(first) = self.first.take() {
    832                    return seed.deserialize(first.into_deserializer()).map(Some);
    833                }
    834                if let Some(second) = self.second.take() {
    835                    return seed.deserialize(second.into_deserializer()).map(Some);
    836                }
    837                Ok(None)
    838            }
    839        }
    840
    841        visitor.visit_seq(SeqVisitor {
    842            first: Some(self.0),
    843            second: Some(self.1),
    844        })
    845    }
    846
    847    serde::forward_to_deserialize_any! {
    848        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
    849        bytes byte_buf map struct option unit newtype_struct
    850        ignored_any unit_struct tuple_struct tuple enum identifier
    851    }
    852}