bluejay_validator/
path.rs

1use std::rc::Rc;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub enum PathElement<'a> {
5    Key(&'a str),
6    Index(usize),
7}
8
9impl<'a> From<&'a str> for PathElement<'a> {
10    fn from(s: &'a str) -> Self {
11        Self::Key(s)
12    }
13}
14
15impl From<usize> for PathElement<'_> {
16    fn from(i: usize) -> Self {
17        Self::Index(i)
18    }
19}
20
21impl std::fmt::Display for PathElement<'_> {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        match self {
24            PathElement::Key(s) => write!(f, "{}", s),
25            PathElement::Index(i) => write!(f, "{}", i),
26        }
27    }
28}
29
30impl From<PathElement<'_>> for String {
31    fn from(value: PathElement<'_>) -> Self {
32        value.to_string()
33    }
34}
35
36#[derive(Debug, PartialEq)]
37struct PathInner<'a> {
38    element: PathElement<'a>,
39    parent: Option<Rc<Self>>,
40}
41
42impl<'a> PathInner<'a> {
43    fn new(element: impl Into<PathElement<'a>>) -> Self {
44        Self {
45            element: element.into(),
46            parent: None,
47        }
48    }
49
50    fn push(rc_self: Rc<Self>, element: impl Into<PathElement<'a>>) -> Rc<Self> {
51        Rc::new(Self {
52            element: element.into(),
53            parent: Some(rc_self),
54        })
55    }
56
57    fn len(&self) -> usize {
58        1 + self.parent.as_ref().map_or(0, |p| p.len())
59    }
60
61    fn append_to_vec<T: From<PathElement<'a>>>(&self, vec: &mut Vec<T>) {
62        if let Some(parent) = &self.parent {
63            parent.append_to_vec(vec);
64        }
65
66        vec.push(self.element.into());
67    }
68}
69
70#[derive(Clone, Default, Debug, PartialEq)]
71pub struct Path<'a>(Option<Rc<PathInner<'a>>>);
72
73impl<'a> Path<'a> {
74    pub fn new(element: impl Into<PathElement<'a>>) -> Self {
75        Self(Some(Rc::new(PathInner::new(element))))
76    }
77
78    pub fn push(&self, element: impl Into<PathElement<'a>>) -> Self {
79        match &self.0 {
80            Some(inner) => Self(Some(PathInner::push(inner.clone(), element))),
81            None => Self(Some(Rc::new(PathInner::new(element)))),
82        }
83    }
84
85    fn len(&self) -> usize {
86        self.0.as_ref().map_or(0, |i| i.len())
87    }
88
89    pub fn to_vec<T: From<PathElement<'a>>>(&self) -> Vec<T> {
90        let mut vec = Vec::with_capacity(self.len());
91
92        if let Some(inner) = &self.0 {
93            inner.append_to_vec(&mut vec);
94        }
95
96        vec
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::{Path, PathElement};
103
104    #[test]
105    fn test_len() {
106        assert_eq!(0, Path::default().len());
107        assert_eq!(1, Path::new("key").len());
108        assert_eq!(2, Path::new("key").push("nested_key").len());
109    }
110
111    #[test]
112    fn test_to_vec() {
113        assert_eq!(Vec::<PathElement>::new(), Path::default().to_vec());
114        assert_eq!(vec![PathElement::Key("key")], Path::new("key").to_vec());
115        assert_eq!(
116            vec![PathElement::Key("key"), PathElement::Key("nested_key")],
117            Path::new("key").push("nested_key").to_vec(),
118        );
119    }
120
121    #[test]
122    fn test_partial_eq() {
123        assert_ne!(Path::new("key").push("nested_key"), Path::new("nested_key"));
124        assert_ne!(Path::new("key").push("nested_key"), Path::new("key"));
125        assert_eq!(
126            Path::new("key").push("nested_key"),
127            Path::new("key").push("nested_key"),
128        );
129    }
130}