serde_path_to_error/
path.rs

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