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}