Skip to main content

dre_core/config/
de.rs

1//! Typed config read from a [`Node`] tree with serde, keeping each value's location.
2//!
3//! Config structs derive `Deserialize` (and `JsonSchema`, which generates `docs/schemas/`) and are
4//! read with [`from_node`]. Three wrappers carry what plain serde loses:
5//!
6//! - [`Located<T>`]: the value with the line and column it was written at.
7//! - [`Loose<T>`]: the value, or, when it has the wrong shape, what was found and where, so the
8//!   loader reports DRE's own message and carries on with the rest of the file instead of
9//!   stopping at the first problem.
10//! - [`OneOf<A, B>`]: an `A`, else a `B` (a query given by name or as a map), keeping both
11//!   readings' locations, which serde's untagged enums lose.
12//! - [`UnknownKeys`]: in a struct field named [`UNKNOWN`], the keys the struct doesn't define,
13//!   with their lines. A struct without that field ignores unknown keys. The field can also be a
14//!   [`Map`], to read the other keys' values (folder config: folder names next to `+` keys).
15
16use std::fmt;
17use std::marker::PhantomData;
18
19use schemars::JsonSchema;
20use serde::de::{
21    self, Deserialize, DeserializeSeed, Deserializer, IntoDeserializer, MapAccess, SeqAccess, Visitor,
22};
23
24use super::node::{Key, Kind, Node};
25
26/// The field name that collects a struct's unknown keys: `#[serde(rename = "$unknown", default)]`.
27pub const UNKNOWN: &str = "$unknown";
28const LOCATED: &str = "$dre::Located";
29const LOOSE: &str = "$dre::Loose";
30const ONE_OF: &str = "$dre::OneOf";
31
32/// A config value of type `T` from `node`. Fails only where no [`Loose`] catches the problem.
33pub fn from_node<'a, T: Deserialize<'a>>(node: &'a Node) -> Result<T, Error> {
34    T::deserialize(NodeDe(node, node.line))
35}
36
37/// A problem reading typed config: the message, and the line of the value it's about.
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct Error {
40    pub line: Option<usize>,
41    pub message: String,
42}
43
44impl fmt::Display for Error {
45    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
46        f.write_str(&self.message)
47    }
48}
49
50impl std::error::Error for Error {}
51
52impl de::Error for Error {
53    fn custom<T: fmt::Display>(msg: T) -> Self {
54        Error {
55            line: None,
56            message: msg.to_string(),
57        }
58    }
59}
60
61impl Error {
62    fn at(mut self, line: usize) -> Self {
63        if self.line.is_none() && line > 0 {
64            self.line = Some(line);
65        }
66        self
67    }
68}
69
70/// A value and where it was written: for a map entry, the line of its key (where a diagnostic
71/// about it points); for a list item, the item's own line.
72#[derive(Debug, Clone, PartialEq)]
73pub struct Located<T> {
74    pub value: T,
75    pub line: usize,
76    pub column: usize,
77}
78
79impl<T> Located<T> {
80    /// The same location with another value.
81    pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Located<U> {
82        Located {
83            value: f(self.value),
84            line: self.line,
85            column: self.column,
86        }
87    }
88
89    /// The line, `None` when unknown.
90    pub fn line(&self) -> Option<usize> {
91        (self.line > 0).then_some(self.line)
92    }
93}
94
95impl<'de, T: Deserialize<'de>> Deserialize<'de> for Located<T> {
96    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
97        struct V<T>(PhantomData<T>);
98        impl<'de, T: Deserialize<'de>> Visitor<'de> for V<T> {
99            type Value = Located<T>;
100            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
101                f.write_str("a located value")
102            }
103            fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
104                let line = seq.next_element()?.unwrap_or(0);
105                let column = seq.next_element()?.unwrap_or(0);
106                let value = seq
107                    .next_element()?
108                    .ok_or_else(|| de::Error::custom("a located value without a value"))?;
109                Ok(Located { value, line, column })
110            }
111        }
112        d.deserialize_newtype_struct(LOCATED, V(PhantomData))
113    }
114}
115
116impl<T: JsonSchema> JsonSchema for Located<T> {
117    fn schema_name() -> std::borrow::Cow<'static, str> {
118        T::schema_name()
119    }
120    fn json_schema(g: &mut schemars::SchemaGenerator) -> schemars::Schema {
121        T::json_schema(g)
122    }
123    fn inline_schema() -> bool {
124        T::inline_schema()
125    }
126}
127
128/// A value of type `T`, or what was found instead.
129#[derive(Debug, Clone, PartialEq)]
130pub enum Loose<T> {
131    Ok(T),
132    Bad(Found),
133}
134
135/// A value that didn't have the expected shape.
136#[derive(Debug, Clone, PartialEq, Eq)]
137pub struct Found {
138    /// What it was: `a map`, `a list`, `a string`, ... (see [`Kind::name`]).
139    pub kind: &'static str,
140    pub line: usize,
141    /// serde's description of the problem, for messages without a DRE wording.
142    pub problem: String,
143}
144
145impl<T> Loose<T> {
146    pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Loose<U> {
147        match self {
148            Loose::Ok(v) => Loose::Ok(f(v)),
149            Loose::Bad(b) => Loose::Bad(b),
150        }
151    }
152
153    pub fn ok(&self) -> Option<&T> {
154        match self {
155            Loose::Ok(v) => Some(v),
156            Loose::Bad(_) => None,
157        }
158    }
159}
160
161impl<'de, T: Deserialize<'de>> Deserialize<'de> for Loose<T> {
162    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
163        struct V<T>(PhantomData<T>);
164        impl<'de, T: Deserialize<'de>> Visitor<'de> for V<T> {
165            type Value = Loose<T>;
166            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
167                f.write_str("a value")
168            }
169            fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
170                match seq.next_element::<T>() {
171                    Ok(Some(v)) => Ok(Loose::Ok(v)),
172                    Ok(None) => Err(de::Error::custom("a loose value without a value")),
173                    Err(e) => {
174                        let line = seq.next_element::<usize>()?.unwrap_or(0);
175                        let kind = seq.next_element::<String>()?.unwrap_or_default();
176                        Ok(Loose::Bad(Found {
177                            kind: kind_name(&kind),
178                            line,
179                            problem: e.to_string(),
180                        }))
181                    }
182                }
183            }
184        }
185        d.deserialize_newtype_struct(LOOSE, V(PhantomData))
186    }
187}
188
189fn kind_name(name: &str) -> &'static str {
190    ["nothing", "a boolean", "a number", "a string", "a list", "a map"]
191        .into_iter()
192        .find(|k| *k == name)
193        .unwrap_or("a value")
194}
195
196impl<T: JsonSchema> JsonSchema for Loose<T> {
197    fn schema_name() -> std::borrow::Cow<'static, str> {
198        T::schema_name()
199    }
200    fn json_schema(g: &mut schemars::SchemaGenerator) -> schemars::Schema {
201        T::json_schema(g)
202    }
203    fn inline_schema() -> bool {
204        T::inline_schema()
205    }
206}
207
208/// A key that may be absent, unlike `Option`, which also reads `key: null` as absent. Use with
209/// `#[serde(default)]`.
210#[derive(Debug, Clone, Default, PartialEq)]
211pub enum Maybe<T> {
212    #[default]
213    Absent,
214    Given(T),
215}
216
217impl<'de, T: Deserialize<'de>> Deserialize<'de> for Maybe<T> {
218    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
219        T::deserialize(d).map(Maybe::Given)
220    }
221}
222
223impl<T: JsonSchema> JsonSchema for Maybe<T> {
224    fn schema_name() -> std::borrow::Cow<'static, str> {
225        T::schema_name()
226    }
227    fn json_schema(g: &mut schemars::SchemaGenerator) -> schemars::Schema {
228        T::json_schema(g)
229    }
230    fn inline_schema() -> bool {
231        T::inline_schema()
232    }
233}
234
235/// A scalar read as text: a string, or a number or boolean as written (`schema: 2024`).
236#[derive(Debug, Clone, PartialEq, Eq)]
237pub struct Text(pub String);
238
239impl<'de> Deserialize<'de> for Text {
240    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
241        struct V;
242        impl Visitor<'_> for V {
243            type Value = Text;
244            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
245                f.write_str("a string")
246            }
247            fn visit_str<E>(self, v: &str) -> Result<Text, E> {
248                Ok(Text(v.to_string()))
249            }
250            fn visit_bool<E>(self, v: bool) -> Result<Text, E> {
251                Ok(Text(v.to_string()))
252            }
253            fn visit_i64<E>(self, v: i64) -> Result<Text, E> {
254                Ok(Text(v.to_string()))
255            }
256            fn visit_u64<E>(self, v: u64) -> Result<Text, E> {
257                Ok(Text(v.to_string()))
258            }
259            fn visit_f64<E>(self, v: f64) -> Result<Text, E> {
260                Ok(Text(v.to_string()))
261            }
262        }
263        d.deserialize_any(V)
264    }
265}
266
267impl JsonSchema for Text {
268    fn schema_name() -> std::borrow::Cow<'static, str> {
269        "String".into()
270    }
271    fn json_schema(g: &mut schemars::SchemaGenerator) -> schemars::Schema {
272        String::json_schema(g)
273    }
274    fn inline_schema() -> bool {
275        true
276    }
277}
278
279/// An `A`, else a `B`, read from the same value.
280#[derive(Debug, Clone, PartialEq)]
281pub enum OneOf<A, B> {
282    A(A),
283    B(B),
284}
285
286impl<'de, A: Deserialize<'de>, B: Deserialize<'de>> Deserialize<'de> for OneOf<A, B> {
287    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
288        struct V<A, B>(PhantomData<(A, B)>);
289        impl<'de, A: Deserialize<'de>, B: Deserialize<'de>> Visitor<'de> for V<A, B> {
290            type Value = OneOf<A, B>;
291            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
292                f.write_str("one of two shapes")
293            }
294            fn visit_seq<S: SeqAccess<'de>>(self, mut seq: S) -> Result<Self::Value, S::Error> {
295                if let Ok(Some(a)) = seq.next_element::<A>() {
296                    return Ok(OneOf::A(a));
297                }
298                match seq.next_element::<B>()? {
299                    Some(b) => Ok(OneOf::B(b)),
300                    None => Err(de::Error::custom("one of two shapes without a value")),
301                }
302            }
303        }
304        d.deserialize_newtype_struct(ONE_OF, V(PhantomData))
305    }
306}
307
308impl<A: JsonSchema, B: JsonSchema> JsonSchema for OneOf<A, B> {
309    fn schema_name() -> std::borrow::Cow<'static, str> {
310        format!("OneOf_{}_{}", A::schema_name(), B::schema_name()).into()
311    }
312    fn json_schema(g: &mut schemars::SchemaGenerator) -> schemars::Schema {
313        // `OneOf<A, OneOf<B, C>>` is one list of three alternatives.
314        let mut alternatives = Vec::new();
315        for s in [g.subschema_for::<A>(), g.subschema_for::<B>()] {
316            match s.as_object() {
317                Some(o) if o.len() == 1 && o.contains_key("oneOf") => {
318                    alternatives.extend(o["oneOf"].as_array().into_iter().flatten().cloned());
319                }
320                _ => alternatives.push(s.to_value()),
321            }
322        }
323        schemars::json_schema!({"oneOf": alternatives})
324    }
325    fn inline_schema() -> bool {
326        true
327    }
328}
329
330/// The keys of a map that its struct doesn't define, in the file's order.
331#[derive(Debug, Clone, Default, PartialEq, Eq)]
332pub struct UnknownKeys(pub Vec<Key>);
333
334impl<'de> Deserialize<'de> for UnknownKeys {
335    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
336        struct V;
337        impl<'de> Visitor<'de> for V {
338            type Value = UnknownKeys;
339            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
340                f.write_str("unknown keys")
341            }
342            fn visit_map<A: MapAccess<'de>>(self, mut m: A) -> Result<UnknownKeys, A::Error> {
343                let mut keys = Vec::new();
344                while let Some((k, _)) = m.next_entry::<Located<String>, de::IgnoredAny>()? {
345                    keys.push(Key {
346                        name: k.value,
347                        line: k.line,
348                    });
349                }
350                Ok(UnknownKeys(keys))
351            }
352        }
353        d.deserialize_map(V)
354    }
355}
356
357/// A map in the file's order, each key with its line: `Map<V>` for a YAML map of names.
358#[derive(Debug, Clone, PartialEq)]
359pub struct Map<V>(pub Vec<(Located<String>, V)>);
360
361impl<V> Default for Map<V> {
362    fn default() -> Self {
363        Map(Vec::new())
364    }
365}
366
367impl<V> Map<V> {
368    pub fn iter(&self) -> impl Iterator<Item = (&Located<String>, &V)> {
369        self.0.iter().map(|(k, v)| (k, v))
370    }
371    pub fn get(&self, key: &str) -> Option<&V> {
372        self.0.iter().find(|(k, _)| k.value == key).map(|(_, v)| v)
373    }
374    pub fn contains_key(&self, key: &str) -> bool {
375        self.get(key).is_some()
376    }
377    pub fn len(&self) -> usize {
378        self.0.len()
379    }
380    pub fn is_empty(&self) -> bool {
381        self.0.is_empty()
382    }
383}
384
385impl<'de, V: Deserialize<'de>> Deserialize<'de> for Map<V> {
386    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
387        struct Vis<V>(PhantomData<V>);
388        impl<'de, V: Deserialize<'de>> Visitor<'de> for Vis<V> {
389            type Value = Map<V>;
390            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
391                f.write_str("a map")
392            }
393            fn visit_unit<E>(self) -> Result<Map<V>, E> {
394                Ok(Map(Vec::new()))
395            }
396            fn visit_map<A: MapAccess<'de>>(self, mut m: A) -> Result<Map<V>, A::Error> {
397                let mut entries = Vec::new();
398                while let Some(e) = m.next_entry()? {
399                    entries.push(e);
400                }
401                Ok(Map(entries))
402            }
403        }
404        d.deserialize_map(Vis(PhantomData))
405    }
406}
407
408impl<V: JsonSchema> JsonSchema for Map<V> {
409    fn schema_name() -> std::borrow::Cow<'static, str> {
410        format!("Map_of_{}", V::schema_name()).into()
411    }
412    fn json_schema(g: &mut schemars::SchemaGenerator) -> schemars::Schema {
413        schemars::json_schema!({"type": "object", "additionalProperties": g.subschema_for::<V>()})
414    }
415    fn inline_schema() -> bool {
416        true
417    }
418}
419
420/// Reads a map key: a string, or a [`Located`] string with the key's line.
421struct KeyDe<'a>(&'a Key);
422
423impl<'de> Deserializer<'de> for KeyDe<'de> {
424    type Error = Error;
425    fn deserialize_any<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Error> {
426        v.visit_borrowed_str(&self.0.name)
427    }
428    fn deserialize_newtype_struct<V: Visitor<'de>>(
429        self,
430        name: &'static str,
431        v: V,
432    ) -> Result<V::Value, Error> {
433        if name == LOCATED {
434            v.visit_seq(KeySeq { key: self.0, at: 0 })
435        } else {
436            v.visit_newtype_struct(self)
437        }
438    }
439    serde::forward_to_deserialize_any! {
440        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes byte_buf option
441        unit unit_struct seq tuple tuple_struct map struct enum identifier ignored_any
442    }
443}
444
445struct KeySeq<'a> {
446    key: &'a Key,
447    at: usize,
448}
449
450impl<'a> SeqAccess<'a> for KeySeq<'a> {
451    type Error = Error;
452    fn next_element_seed<T: DeserializeSeed<'a>>(&mut self, seed: T) -> Result<Option<T::Value>, Error> {
453        self.at += 1;
454        match self.at {
455            1 => seed.deserialize(self.key.line.into_deserializer()).map(Some),
456            2 => seed.deserialize(0usize.into_deserializer()).map(Some),
457            3 => seed.deserialize(KeyDe(self.key)).map(Some),
458            _ => Ok(None),
459        }
460    }
461}
462
463/// Reads typed values from a node; `.1` is the line its entry was written at (its key's line in
464/// a map).
465#[derive(Clone, Copy)]
466struct NodeDe<'a>(&'a Node, usize);
467
468impl<'a> NodeDe<'a> {
469    fn err(&self, msg: impl fmt::Display) -> Error {
470        Error {
471            line: (self.1 > 0).then_some(self.1),
472            message: msg.to_string(),
473        }
474    }
475
476    fn mismatch(&self, expected: &str) -> Error {
477        self.err(format!("expected {expected}, found {}", self.0.kind.name()))
478    }
479}
480
481macro_rules! via_any {
482    ($($m:ident)*) => {$(
483        fn $m<V: Visitor<'a>>(self, v: V) -> Result<V::Value, Error> {
484            self.deserialize_any(v)
485        }
486    )*};
487}
488
489impl<'a> Deserializer<'a> for NodeDe<'a> {
490    type Error = Error;
491
492    fn deserialize_any<V: Visitor<'a>>(self, v: V) -> Result<V::Value, Error> {
493        let line = self.0.line;
494        match &self.0.kind {
495            Kind::Null => v.visit_unit(),
496            Kind::Bool(b) => v.visit_bool(*b),
497            Kind::Int(i) => v.visit_i64(*i),
498            Kind::UInt(u) => v.visit_u64(*u),
499            Kind::Float(f) => v.visit_f64(*f),
500            Kind::Str(s) => v.visit_borrowed_str(s),
501            Kind::Seq(items) => v.visit_seq(Items(items.iter())),
502            Kind::Map(entries) => v.visit_map(Entries {
503                entries: entries.iter(),
504                value: None,
505                fields: None,
506                unknown: Vec::new(),
507                unknown_done: true,
508            }),
509        }
510        .map_err(|e| e.at(line))
511    }
512
513    via_any!(deserialize_bool deserialize_i8 deserialize_i16 deserialize_i32 deserialize_i64
514        deserialize_u8 deserialize_u16 deserialize_u32 deserialize_u64 deserialize_f32
515        deserialize_f64 deserialize_char deserialize_bytes deserialize_byte_buf
516        deserialize_unit deserialize_identifier deserialize_ignored_any);
517
518    fn deserialize_str<V: Visitor<'a>>(self, v: V) -> Result<V::Value, Error> {
519        match &self.0.kind {
520            Kind::Str(s) => v.visit_borrowed_str(s),
521            _ => Err(self.mismatch("a string")),
522        }
523    }
524
525    fn deserialize_string<V: Visitor<'a>>(self, v: V) -> Result<V::Value, Error> {
526        self.deserialize_str(v)
527    }
528
529    fn deserialize_option<V: Visitor<'a>>(self, v: V) -> Result<V::Value, Error> {
530        match self.0.kind {
531            Kind::Null => v.visit_none(),
532            _ => v.visit_some(self),
533        }
534    }
535
536    fn deserialize_unit_struct<V: Visitor<'a>>(self, _: &'static str, v: V) -> Result<V::Value, Error> {
537        self.deserialize_unit(v)
538    }
539
540    fn deserialize_newtype_struct<V: Visitor<'a>>(self, name: &'static str, v: V) -> Result<V::Value, Error> {
541        match name {
542            LOCATED => v.visit_seq(LocatedSeq {
543                node: self.0,
544                line: self.1,
545                at: 0,
546            }),
547            LOOSE => v.visit_seq(LooseSeq {
548                node: self.0,
549                line: self.1,
550                at: 0,
551            }),
552            ONE_OF => v.visit_seq(OneOfSeq {
553                node: self.0,
554                line: self.1,
555                at: 0,
556            }),
557            _ => v.visit_newtype_struct(self),
558        }
559    }
560
561    fn deserialize_seq<V: Visitor<'a>>(self, v: V) -> Result<V::Value, Error> {
562        match &self.0.kind {
563            Kind::Seq(items) => v.visit_seq(Items(items.iter())).map_err(|e| e.at(self.0.line)),
564            _ => Err(self.mismatch("a list")),
565        }
566    }
567
568    fn deserialize_tuple<V: Visitor<'a>>(self, _: usize, v: V) -> Result<V::Value, Error> {
569        self.deserialize_seq(v)
570    }
571
572    fn deserialize_tuple_struct<V: Visitor<'a>>(
573        self,
574        _: &'static str,
575        _: usize,
576        v: V,
577    ) -> Result<V::Value, Error> {
578        self.deserialize_seq(v)
579    }
580
581    fn deserialize_map<V: Visitor<'a>>(self, v: V) -> Result<V::Value, Error> {
582        match &self.0.kind {
583            Kind::Map(_) => self.deserialize_any(v),
584            _ => Err(self.mismatch("a map")),
585        }
586    }
587
588    fn deserialize_struct<V: Visitor<'a>>(
589        self,
590        _: &'static str,
591        fields: &'static [&'static str],
592        v: V,
593    ) -> Result<V::Value, Error> {
594        let Kind::Map(entries) = &self.0.kind else {
595            return Err(self.mismatch("a map"));
596        };
597        let collects = fields.contains(&UNKNOWN);
598        v.visit_map(Entries {
599            entries: entries.iter(),
600            value: None,
601            fields: Some(fields),
602            unknown: Vec::new(),
603            unknown_done: !collects,
604        })
605        .map_err(|e| e.at(self.0.line))
606    }
607
608    fn deserialize_enum<V: Visitor<'a>>(
609        self,
610        _: &'static str,
611        _: &'static [&'static str],
612        v: V,
613    ) -> Result<V::Value, Error> {
614        match &self.0.kind {
615            Kind::Str(s) => v.visit_enum(s.as_str().into_deserializer()),
616            _ => Err(self.mismatch("a name")),
617        }
618    }
619}
620
621struct Items<'a>(std::slice::Iter<'a, Node>);
622
623impl<'a> SeqAccess<'a> for Items<'a> {
624    type Error = Error;
625    fn next_element_seed<T: DeserializeSeed<'a>>(&mut self, seed: T) -> Result<Option<T::Value>, Error> {
626        self.0
627            .next()
628            .map(|n| seed.deserialize(NodeDe(n, n.line)))
629            .transpose()
630    }
631    fn size_hint(&self) -> Option<usize> {
632        Some(self.0.len())
633    }
634}
635
636struct Entries<'a> {
637    entries: std::slice::Iter<'a, (Key, Node)>,
638    value: Option<(&'a Node, usize)>,
639    /// A struct's fields: other keys are skipped (and collected when it has [`UNKNOWN`]).
640    fields: Option<&'static [&'static str]>,
641    unknown: Vec<&'a (Key, Node)>,
642    unknown_done: bool,
643}
644
645enum Pending<'a> {
646    Node(&'a Node, usize),
647    Unknown(Vec<&'a (Key, Node)>),
648}
649
650impl<'a> MapAccess<'a> for Entries<'a> {
651    type Error = Error;
652
653    fn next_key_seed<K: DeserializeSeed<'a>>(&mut self, seed: K) -> Result<Option<K::Value>, Error> {
654        for entry in self.entries.by_ref() {
655            let (k, v) = entry;
656            if let Some(fields) = self.fields
657                && (!fields.contains(&k.name.as_str()) || k.name == UNKNOWN)
658            {
659                self.unknown.push(entry);
660                continue;
661            }
662            self.value = Some((v, k.line));
663            return seed.deserialize(KeyDe(k)).map(Some);
664        }
665        if !self.unknown_done {
666            self.unknown_done = true;
667            self.value = None;
668            return seed.deserialize(UNKNOWN.into_deserializer()).map(Some);
669        }
670        Ok(None)
671    }
672
673    fn next_value_seed<V: DeserializeSeed<'a>>(&mut self, seed: V) -> Result<V::Value, Error> {
674        let pending = match self.value.take() {
675            Some((n, line)) => Pending::Node(n, line),
676            None => Pending::Unknown(std::mem::take(&mut self.unknown)),
677        };
678        match pending {
679            Pending::Node(n, line) => seed.deserialize(NodeDe(n, line)),
680            Pending::Unknown(entries) => seed.deserialize(Rest(entries)),
681        }
682    }
683}
684
685/// The entries a struct doesn't define, for its [`UNKNOWN`] field: a map of them.
686struct Rest<'a>(Vec<&'a (Key, Node)>);
687
688impl<'de> Deserializer<'de> for Rest<'de> {
689    type Error = Error;
690    fn deserialize_any<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Error> {
691        v.visit_map(RestEntries {
692            entries: self.0.into_iter(),
693            value: None,
694        })
695    }
696    serde::forward_to_deserialize_any! {
697        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes byte_buf option
698        unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier ignored_any
699    }
700}
701
702struct RestEntries<'a> {
703    entries: std::vec::IntoIter<&'a (Key, Node)>,
704    value: Option<&'a (Key, Node)>,
705}
706
707impl<'de> MapAccess<'de> for RestEntries<'de> {
708    type Error = Error;
709    fn next_key_seed<K: DeserializeSeed<'de>>(&mut self, seed: K) -> Result<Option<K::Value>, Error> {
710        let Some(entry) = self.entries.next() else {
711            return Ok(None);
712        };
713        self.value = Some(entry);
714        seed.deserialize(KeyDe(&entry.0)).map(Some)
715    }
716    fn next_value_seed<V: DeserializeSeed<'de>>(&mut self, seed: V) -> Result<V::Value, Error> {
717        let (k, v) = self.value.take().expect("a value follows its key");
718        seed.deserialize(NodeDe(v, k.line))
719    }
720}
721
722/// `[A, B]` for [`OneOf`]: the same value, read twice.
723struct OneOfSeq<'a> {
724    node: &'a Node,
725    line: usize,
726    at: usize,
727}
728
729impl<'a> SeqAccess<'a> for OneOfSeq<'a> {
730    type Error = Error;
731    fn next_element_seed<T: DeserializeSeed<'a>>(&mut self, seed: T) -> Result<Option<T::Value>, Error> {
732        self.at += 1;
733        match self.at {
734            1 | 2 => seed.deserialize(NodeDe(self.node, self.line)).map(Some),
735            _ => Ok(None),
736        }
737    }
738}
739
740/// `[line, column, value]` for [`Located`].
741struct LocatedSeq<'a> {
742    node: &'a Node,
743    line: usize,
744    at: usize,
745}
746
747impl<'a> SeqAccess<'a> for LocatedSeq<'a> {
748    type Error = Error;
749    fn next_element_seed<T: DeserializeSeed<'a>>(&mut self, seed: T) -> Result<Option<T::Value>, Error> {
750        self.at += 1;
751        match self.at {
752            1 => seed.deserialize(self.line.into_deserializer()).map(Some),
753            2 => seed.deserialize(self.node.column.into_deserializer()).map(Some),
754            3 => seed.deserialize(NodeDe(self.node, self.line)).map(Some),
755            _ => Ok(None),
756        }
757    }
758}
759
760/// `[value, line, kind]` for [`Loose`]: the line and kind are read only when the value fails.
761struct LooseSeq<'a> {
762    node: &'a Node,
763    line: usize,
764    at: usize,
765}
766
767impl<'a> SeqAccess<'a> for LooseSeq<'a> {
768    type Error = Error;
769    fn next_element_seed<T: DeserializeSeed<'a>>(&mut self, seed: T) -> Result<Option<T::Value>, Error> {
770        self.at += 1;
771        match self.at {
772            1 => seed.deserialize(NodeDe(self.node, self.line)).map(Some),
773            2 => seed.deserialize(self.line.into_deserializer()).map(Some),
774            3 => seed
775                .deserialize(self.node.kind.name().into_deserializer())
776                .map(Some),
777            _ => Ok(None),
778        }
779    }
780}
781
782#[cfg(test)]
783mod tests {
784    use std::collections::BTreeMap;
785
786    use serde::Deserialize;
787
788    use super::*;
789    use crate::config::node::parse;
790
791    #[derive(Debug, Deserialize)]
792    struct Profile {
793        target: Option<Located<Loose<String>>>,
794        targets: Option<Loose<BTreeMap<String, Located<serde_json::Value>>>>,
795        #[serde(rename = "$unknown", default)]
796        unknown: UnknownKeys,
797    }
798
799    #[test]
800    fn values_keep_their_lines_and_unknown_keys_are_collected() {
801        let n = parse("target: prod\nwat: 1\ntargets:\n  dev: {type: duckdb}\nalso: 2\n").unwrap();
802        let p: Profile = from_node(&n).unwrap();
803        let t = p.target.unwrap();
804        assert_eq!((t.value.ok().map(String::as_str), t.line), (Some("prod"), 1));
805        let targets = p.targets.unwrap();
806        let dev = &targets.ok().unwrap()["dev"];
807        assert_eq!(dev.line, 4);
808        assert_eq!(dev.value["type"], "duckdb");
809        let unknown: Vec<_> = p.unknown.0.iter().map(|k| (k.name.as_str(), k.line)).collect();
810        assert_eq!(unknown, [("wat", 2), ("also", 5)]);
811    }
812
813    #[test]
814    fn a_wrong_shape_is_kept_with_its_line_and_the_rest_still_reads() {
815        let n = parse("target: [a]\ntargets: x\n").unwrap();
816        let p: Profile = from_node(&n).unwrap();
817        let Loose::Bad(f) = p.target.unwrap().value else {
818            panic!()
819        };
820        assert_eq!((f.kind, f.line), ("a list", 1));
821        let Loose::Bad(f) = p.targets.unwrap() else {
822            panic!()
823        };
824        assert_eq!((f.kind, f.line), ("a string", 2));
825    }
826
827    #[test]
828    fn the_unknown_field_can_read_the_other_keys_values() {
829        #[derive(Debug, Deserialize)]
830        struct Folder {
831            #[serde(rename = "+tags", default)]
832            tags: Vec<String>,
833            #[serde(rename = "$unknown", default)]
834            folders: Map<Folder>,
835        }
836        let n = parse("+tags: [a]\nsales:\n  +tags: [b]\n  eu: {}\n").unwrap();
837        let f: Folder = from_node(&n).unwrap();
838        let (name, sales) = f.folders.iter().next().unwrap();
839        assert_eq!(
840            (name.value.as_str(), name.line, &sales.tags[..]),
841            ("sales", 2, &["b".to_string()][..])
842        );
843        assert_eq!(sales.folders.iter().next().unwrap().0.value, "eu");
844        assert_eq!(f.tags, ["a"]);
845    }
846
847    #[test]
848    fn one_of_reads_either_shape_and_keeps_lines() {
849        #[derive(Debug, Deserialize)]
850        struct Entry {
851            query: Located<String>,
852            #[serde(rename = "$unknown", default)]
853            unknown: UnknownKeys,
854        }
855        let n = parse("- a\n- {query: b, x: 1}\n- [c]\n").unwrap();
856        let items: Vec<Loose<OneOf<String, Entry>>> = from_node(&n).unwrap();
857        assert!(
858            matches!(&items[0], Loose::Ok(OneOf::A(s)) if s == "a"),
859            "{:?}",
860            items[0]
861        );
862        let Loose::Ok(OneOf::B(e)) = &items[1] else {
863            panic!()
864        };
865        assert_eq!(
866            (e.query.value.as_str(), e.query.line, e.unknown.0[0].name.as_str()),
867            ("b", 2, "x")
868        );
869        assert!(matches!(&items[2], Loose::Bad(f) if f.kind == "a list" && f.line == 3));
870    }
871
872    #[test]
873    fn maps_keep_the_file_order_and_each_keys_line() {
874        let n = parse("b: 1\na: 2\n").unwrap();
875        let m: Map<u32> = from_node(&n).unwrap();
876        let got: Vec<_> = m.iter().map(|(k, v)| (k.value.as_str(), k.line, *v)).collect();
877        assert_eq!(got, [("b", 1, 1), ("a", 2, 2)]);
878    }
879
880    #[test]
881    fn errors_outside_loose_values_have_a_line() {
882        #[derive(Debug, Deserialize)]
883        #[allow(dead_code)]
884        struct S {
885            n: u32,
886        }
887        let n = parse("n: lots\n").unwrap();
888        let e = from_node::<S>(&n).unwrap_err();
889        assert_eq!(e.line, Some(1));
890    }
891
892    #[test]
893    fn a_struct_without_the_unknown_field_ignores_other_keys() {
894        #[derive(Debug, Deserialize)]
895        struct S {
896            a: u32,
897        }
898        let n = parse("a: 1\nb: 2\n").unwrap();
899        assert_eq!(from_node::<S>(&n).unwrap().a, 1);
900    }
901}