bluejay_validator/
path.rs1use 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}