json0_rs/
path.rs

1use std::{cmp::Ordering, fmt::Display};
2
3use serde_json::Value;
4
5use crate::error::{JsonError, Result};
6
7#[derive(Debug, Clone, PartialEq)]
8pub enum PathElement {
9    Index(usize),
10    Key(String),
11}
12
13impl PartialOrd for PathElement {
14    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
15        match self {
16            // only index can compare
17            PathElement::Index(a) => match other {
18                PathElement::Index(b) => a.partial_cmp(b),
19                PathElement::Key(_) => None,
20            },
21            PathElement::Key(a) => match other {
22                PathElement::Index(_) => None,
23                PathElement::Key(b) => {
24                    if a == b {
25                        Some(Ordering::Equal)
26                    } else {
27                        None
28                    }
29                }
30            },
31        }
32    }
33}
34
35impl From<usize> for PathElement {
36    fn from(i: usize) -> Self {
37        PathElement::Index(i)
38    }
39}
40
41impl From<String> for PathElement {
42    fn from(k: String) -> Self {
43        PathElement::Key(k)
44    }
45}
46
47impl Display for PathElement {
48    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49        match self {
50            PathElement::Index(i) => f.write_fmt(format_args!("{}", i)),
51            PathElement::Key(k) => f.write_fmt(format_args!("\"{}\"", k)),
52        }
53    }
54}
55
56#[derive(Debug, Clone, PartialEq)]
57pub struct Path {
58    paths: Vec<PathElement>,
59}
60
61impl Path {
62    pub fn first_key_path(&self) -> Option<&String> {
63        self.get_key_at(0)
64    }
65
66    pub fn first_index_path(&self) -> Option<&usize> {
67        self.get_index_at(0)
68    }
69
70    pub fn get(&self, index: usize) -> Option<&PathElement> {
71        self.paths.get(index)
72    }
73
74    pub fn get_elements(&self) -> &Vec<PathElement> {
75        &self.paths
76    }
77
78    pub fn get_mut_elements(&mut self) -> &mut Vec<PathElement> {
79        &mut self.paths
80    }
81
82    pub fn get_key_at(&self, index: usize) -> Option<&String> {
83        let first_path = self.paths.get(index)?;
84
85        match first_path {
86            PathElement::Index(_) => None,
87            PathElement::Key(k) => Some(k),
88        }
89    }
90
91    pub fn get_index_at(&self, index: usize) -> Option<&usize> {
92        let first_path = self.paths.get(index)?;
93
94        match first_path {
95            PathElement::Index(i) => Some(i),
96            PathElement::Key(_) => None,
97        }
98    }
99
100    pub fn last(&self) -> Option<&PathElement> {
101        self.get(self.len() - 1)
102    }
103
104    pub fn replace(&mut self, index: usize, path_elem: PathElement) -> Option<PathElement> {
105        if self.paths.get(index).is_some() {
106            let o = std::mem::replace(&mut self.paths[index], path_elem);
107            return Some(o);
108        }
109        None
110    }
111
112    pub fn increase_index(&mut self, index: usize) -> bool {
113        if let Some(PathElement::Index(i)) = self.paths.get(index) {
114            self.replace(index, PathElement::Index(i + 1));
115            return true;
116        }
117        false
118    }
119
120    pub fn decrease_index(&mut self, index: usize) -> bool {
121        if let Some(PathElement::Index(i)) = self.paths.get(index) {
122            self.replace(index, PathElement::Index(i - 1));
123            return true;
124        }
125        false
126    }
127
128    pub fn split_at(&self, mid: usize) -> (Path, Path) {
129        let (left, right) = self.paths.split_at(mid);
130        (
131            Path {
132                paths: left.to_vec(),
133            },
134            Path {
135                paths: right.to_vec(),
136            },
137        )
138    }
139
140    pub fn max_common_path(&self, path: &Path) -> Path {
141        let mut common_p = vec![];
142        for (i, pa) in path.get_elements().iter().enumerate() {
143            if let Some(pb) = self.get(i) {
144                if pa.eq(pb) {
145                    common_p.push(pb.clone());
146                    continue;
147                }
148            }
149            break;
150        }
151        Path { paths: common_p }
152    }
153
154    pub fn common_path_prefix(&self, path: &Path) -> Path {
155        let mut common_p = vec![];
156        for (i, pa) in path.get_elements().iter().enumerate() {
157            if let Some(pb) = path.get(i) {
158                if pa.eq(pb) {
159                    common_p.push(pb.clone());
160                    continue;
161                }
162            }
163            break;
164        }
165        Path { paths: common_p }
166    }
167
168    pub fn is_empty(&self) -> bool {
169        self.paths.is_empty()
170    }
171
172    pub fn is_prefix_of(&self, path: &Path) -> bool {
173        for (i, p) in self.paths.iter().enumerate() {
174            if let Some(p2) = path.paths.get(i) {
175                if p != p2 {
176                    return false;
177                }
178            } else {
179                return false;
180            }
181        }
182        true
183    }
184
185    pub fn len(&self) -> usize {
186        self.paths.len()
187    }
188
189    pub fn next_level(&self) -> Path {
190        Path {
191            paths: self.paths[1..].to_vec(),
192        }
193    }
194}
195
196impl Display for Path {
197    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198        f.write_fmt(format_args!(
199            "[{}]",
200            self.paths
201                .iter()
202                .map(|p| format!("{}", p))
203                .collect::<Vec<String>>()
204                .join(", ")
205        ))?;
206        Ok(())
207    }
208}
209
210impl TryFrom<&str> for Path {
211    type Error = JsonError;
212
213    fn try_from(input: &str) -> std::result::Result<Self, Self::Error> {
214        if let Ok(value) = serde_json::from_str::<Value>(input) {
215            return Path::try_from(&value);
216        }
217        Err(JsonError::InvalidPathFormat)
218    }
219}
220
221impl TryFrom<&Value> for Path {
222    type Error = JsonError;
223
224    fn try_from(value: &Value) -> std::result::Result<Self, Self::Error> {
225        match value {
226            Value::Array(arr) => {
227                if arr.is_empty() {
228                    Err(JsonError::InvalidPathFormat)
229                } else {
230                    let paths = arr
231                        .iter()
232                        .map(|pe| match pe {
233                            Value::Number(n) => {
234                                if let Some(i) = n.as_u64() {
235                                    Ok(PathElement::Index(i as usize))
236                                } else {
237                                    Err(JsonError::InvalidPathElement(pe.to_string()))
238                                }
239                            }
240                            Value::String(k) => Ok(PathElement::Key(k.to_string())),
241                            _ => Err(JsonError::InvalidPathElement(pe.to_string())),
242                        })
243                        .collect::<Result<Vec<PathElement>>>()?;
244                    Ok(Path { paths })
245                }
246            }
247            _ => Err(JsonError::InvalidPathFormat),
248        }
249    }
250}
251
252#[cfg(test)]
253mod tests {
254    use super::*;
255    use test_log::test;
256
257    #[test]
258    fn test_parse_invalid_path() {
259        assert_matches!(
260            Path::try_from("]").unwrap_err(),
261            JsonError::InvalidPathFormat
262        );
263        assert_matches!(
264            Path::try_from("[").unwrap_err(),
265            JsonError::InvalidPathFormat
266        );
267        assert_matches!(
268            Path::try_from("").unwrap_err(),
269            JsonError::InvalidPathFormat
270        );
271        assert_matches!(
272            Path::try_from("[]").unwrap_err(),
273            JsonError::InvalidPathFormat
274        );
275        assert_matches!(
276            Path::try_from("hello").unwrap_err(),
277            JsonError::InvalidPathFormat
278        );
279        assert_matches!(
280            Path::try_from("[hello]").unwrap_err(),
281            JsonError::InvalidPathFormat
282        );
283    }
284
285    #[test]
286    fn test_parse_index_path() {
287        let paths = Path::try_from("[1]").unwrap();
288        assert_eq!(1, paths.len());
289        assert_eq!(1, *paths.first_index_path().unwrap());
290        let paths = Path::try_from("[2, 3, 4]").unwrap();
291        assert_eq!(3, paths.len());
292        assert_eq!(2, *paths.first_index_path().unwrap());
293        let paths = paths.next_level();
294        assert_eq!(2, paths.len());
295        assert_eq!(3, *paths.first_index_path().unwrap());
296        let paths = paths.next_level();
297        assert_eq!(1, paths.len());
298        assert_eq!(4, *paths.first_index_path().unwrap());
299        let paths = paths.next_level();
300        assert!(paths.is_empty());
301    }
302
303    #[test]
304    fn test_parse_key_path() {
305        let paths = Path::try_from("[\"hello\"]").unwrap();
306        assert_eq!(1, paths.len());
307        assert_eq!("hello", paths.first_key_path().unwrap());
308        let paths = Path::try_from("[\"hello\", \"word\", \"hello\"]").unwrap();
309        assert_eq!(3, paths.len());
310        assert_eq!("hello", paths.first_key_path().unwrap());
311        let paths = paths.next_level();
312        assert_eq!(2, paths.len());
313        assert_eq!("word", paths.first_key_path().unwrap());
314        let paths = paths.next_level();
315        assert_eq!(1, paths.len());
316        assert_eq!("hello", paths.first_key_path().unwrap());
317        let paths = paths.next_level();
318        assert!(paths.is_empty());
319    }
320
321    #[test]
322    fn test_parse_path_with_blanks() {
323        let paths = Path::try_from("[ \"hello \"  ,  1,  \"  world \",  4  ]").unwrap();
324        assert_eq!(4, paths.len());
325        assert_eq!("hello ", paths.first_key_path().unwrap());
326        let paths = paths.next_level();
327        assert_eq!(3, paths.len());
328        assert_eq!(1, *paths.first_index_path().unwrap());
329        let paths = paths.next_level();
330        assert_eq!(2, paths.len());
331        assert_eq!("  world ", paths.first_key_path().unwrap());
332        let paths = paths.next_level();
333        assert_eq!(4, *paths.first_index_path().unwrap());
334        let paths = paths.next_level();
335        assert!(paths.is_empty());
336    }
337
338    #[test]
339    fn test_increase_decrease_path() {
340        let mut paths = Path::try_from("[ \"hello \"  ,  1,  \"  world \",  4  ]").unwrap();
341        assert!(paths.increase_index(1));
342        assert_eq!(2, *paths.get_index_at(1).unwrap());
343        assert!(paths.increase_index(3));
344        assert_eq!(5, *paths.get_index_at(3).unwrap());
345        assert!(paths.decrease_index(1));
346        assert_eq!(1, *paths.get_index_at(1).unwrap());
347        assert!(paths.decrease_index(3));
348        assert_eq!(4, *paths.get_index_at(3).unwrap());
349
350        assert!(!paths.decrease_index(0));
351        assert!(!paths.increase_index(0));
352    }
353}