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 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}