serde_path_to_error/
path.rs

1use super::Chain;
2use alloc::borrow::ToOwned as _;
3use alloc::string::String;
4use alloc::vec::Vec;
5use core::fmt::{self, Display};
6use core::slice;
7
8/// Path to the error value in the input, like `dependencies.serde.typo1`.
9///
10/// Use `path.to_string()` to get a string representation of the path with
11/// segments separated by periods, or use `path.iter()` to iterate over
12/// individual segments of the path.
13#[derive(Clone, Debug)]
14pub struct Path {
15    segments: Vec<Segment>,
16}
17
18/// Single segment of a path.
19#[derive(Clone, Debug)]
20pub enum Segment {
21    Seq { index: usize },
22    Map { key: String },
23    Enum { variant: String },
24    Unknown,
25}
26
27impl Path {
28    /// Returns an iterator with element type [`&Segment`][Segment].
29    pub fn iter(&self) -> Segments {
30        Segments {
31            iter: self.segments.iter(),
32        }
33    }
34}
35
36impl<'a> IntoIterator for &'a Path {
37    type Item = &'a Segment;
38    type IntoIter = Segments<'a>;
39
40    fn into_iter(self) -> Self::IntoIter {
41        self.iter()
42    }
43}
44
45/// Iterator over segments of a path.
46pub struct Segments<'a> {
47    iter: slice::Iter<'a, Segment>,
48}
49
50impl<'a> Iterator for Segments<'a> {
51    type Item = &'a Segment;
52
53    fn next(&mut self) -> Option<Self::Item> {
54        self.iter.next()
55    }
56
57    fn size_hint(&self) -> (usize, Option<usize>) {
58        self.iter.size_hint()
59    }
60}
61
62impl<'a> DoubleEndedIterator for Segments<'a> {
63    fn next_back(&mut self) -> Option<Self::Item> {
64        self.iter.next_back()
65    }
66}
67
68impl<'a> ExactSizeIterator for Segments<'a> {
69    fn len(&self) -> usize {
70        self.iter.len()
71    }
72}
73
74impl Display for Path {
75    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
76        if self.segments.is_empty() {
77            return formatter.write_str(".");
78        }
79
80        let mut separator = "";
81        for segment in self {
82            if !matches!(segment, Segment::Seq { .. }) {
83                formatter.write_str(separator)?;
84            }
85            write!(formatter, "{}", segment)?;
86            separator = ".";
87        }
88
89        Ok(())
90    }
91}
92
93impl Path {
94    pub(crate) fn empty() -> Self {
95        Path {
96            segments: Vec::new(),
97        }
98    }
99
100    pub(crate) fn from_chain(mut chain: &Chain) -> Self {
101        let mut segments = Vec::new();
102        loop {
103            match chain {
104                Chain::Root => break,
105                Chain::Seq { parent, index } => {
106                    segments.push(Segment::Seq { index: *index });
107                    chain = parent;
108                }
109                Chain::Map { parent, key } => {
110                    segments.push(Segment::Map { key: key.clone() });
111                    chain = parent;
112                }
113                Chain::Struct { parent, key } => {
114                    let key = *key;
115                    segments.push(Segment::Map {
116                        key: key.to_owned(),
117                    });
118                    chain = parent;
119                }
120                Chain::Enum { parent, variant } => {
121                    segments.push(Segment::Enum {
122                        variant: variant.clone(),
123                    });
124                    chain = parent;
125                }
126                Chain::Some { parent }
127                | Chain::NewtypeStruct { parent }
128                | Chain::NewtypeVariant { parent } => {
129                    chain = parent;
130                }
131                Chain::NonStringKey { parent } => {
132                    segments.push(Segment::Unknown);
133                    chain = parent;
134                }
135            }
136        }
137        segments.reverse();
138        Path { segments }
139    }
140
141    pub(crate) fn is_only_unknown(&self) -> bool {
142        self.segments.iter().all(Segment::is_unknown)
143    }
144}
145
146impl Display for Segment {
147    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
148        match self {
149            Segment::Seq { index } => write!(formatter, "[{}]", index),
150            Segment::Map { key } | Segment::Enum { variant: key } => {
151                write!(formatter, "{}", key)
152            }
153            Segment::Unknown => formatter.write_str("?"),
154        }
155    }
156}
157
158impl Segment {
159    fn is_unknown(&self) -> bool {
160        matches!(self, Segment::Unknown)
161    }
162}