1use jsonptr::{EncodingError, Pointer, PointerBuf, Token};
2use std::cmp::Ordering;
3use std::fmt::Display;
4use std::ops::{Deref, DerefMut};
5use std::sync::Arc;
6
7use crate::serde::{Serialize, Serializer};
8
9#[derive(Clone, Default, PartialEq, Eq, Debug)]
10pub struct Path(PointerBuf);
11
12impl Serialize for Path {
13 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
14 where
15 S: Serializer,
16 {
17 self.0.serialize(serializer)
18 }
19}
20
21impl PartialOrd for Path {
22 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
23 Some(self.cmp(other))
24 }
25}
26
27impl Ord for Path {
28 fn cmp(&self, other: &Self) -> Ordering {
29 self.0
33 .count()
34 .cmp(&other.0.count())
35 .then(self.0.cmp(&other.0))
37 }
38}
39impl Path {
40 pub fn new(pointer: &Pointer) -> Self {
41 Self(pointer.to_buf())
42 }
43
44 pub fn from_static(s: &'static str) -> Self {
50 Path(Pointer::from_static(s).to_buf())
51 }
52
53 pub fn as_str(&self) -> &str {
55 self.0.as_str()
56 }
57
58 pub fn is_prefix_of(&self, other: &Path) -> bool {
62 let self_tokens: Vec<_> = self.0.tokens().collect();
63 let other_tokens: Vec<_> = other.0.tokens().collect();
64
65 if self_tokens.is_empty() {
67 return true;
68 }
69
70 if self_tokens.len() > other_tokens.len() {
72 return false;
73 }
74
75 self_tokens
77 .iter()
78 .zip(other_tokens.iter())
79 .all(|(a, b)| a == b)
80 }
81}
82
83impl Display for Path {
84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 write!(f, "{}", self.0)
86 }
87}
88
89impl From<Path> for String {
90 fn from(path: Path) -> String {
91 path.0.to_string()
92 }
93}
94
95impl From<Path> for PointerBuf {
96 fn from(path: Path) -> Self {
97 path.0
98 }
99}
100
101impl AsRef<Pointer> for Path {
102 fn as_ref(&self) -> &Pointer {
103 &self.0
104 }
105}
106
107impl Deref for Path {
108 type Target = str;
109
110 fn deref(&self) -> &Self::Target {
111 self.as_str()
112 }
113}
114
115#[derive(Clone, Default, Debug, PartialEq, Eq)]
118pub struct PathArgs(Vec<(Arc<str>, String)>);
119
120impl PathArgs {
121 pub fn insert(&mut self, key: impl AsRef<str>, value: impl Into<String>) -> Option<String> {
122 let existing = self.0.iter_mut().find(|(k, _)| k.as_ref() == key.as_ref());
123 if let Some((_, v)) = existing {
124 let old = v.clone();
125 *v = value.into();
126 return Some(old);
127 } else {
128 self.0.push((Arc::from(key.as_ref()), value.into()))
129 }
130 None
131 }
132
133 pub fn contains_key(&self, key: impl AsRef<str>) -> bool {
134 self.0.iter().any(|(k, _)| k.as_ref() == key.as_ref())
135 }
136
137 pub fn try_as_decoded(&self) -> Result<PathArgs, EncodingError> {
139 let items: Result<Vec<(&str, String)>, EncodingError> = self
140 .iter()
141 .map(|(key, value)| {
142 let decoded = Token::from_encoded(value)?.decoded().to_string();
143 Ok((key.as_ref(), decoded))
144 })
145 .collect();
146
147 items.map(PathArgs::from)
148 }
149}
150
151impl Display for PathArgs {
152 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153 let entries = self
154 .0
155 .iter()
156 .map(|(key, value)| format!("\"{key}\": \"{value}\""))
157 .collect::<Vec<_>>()
158 .join(", ");
159
160 write!(f, "{{{entries}}}")
161 }
162}
163
164impl Deref for PathArgs {
165 type Target = Vec<(Arc<str>, String)>;
166
167 fn deref(&self) -> &Self::Target {
168 &self.0
169 }
170}
171
172impl DerefMut for PathArgs {
173 fn deref_mut(&mut self) -> &mut Self::Target {
174 &mut self.0
175 }
176}
177
178impl From<matchit::Params<'_, '_>> for PathArgs {
179 fn from(params: matchit::Params) -> PathArgs {
180 let params: Vec<(Arc<str>, String)> = params
181 .iter()
182 .map(|(k, v)| (Arc::from(k), String::from(v)))
183 .collect();
184
185 PathArgs(params)
186 }
187}
188
189impl<K: AsRef<str>, V: Into<String>> From<Vec<(K, V)>> for PathArgs {
190 fn from(args: Vec<(K, V)>) -> Self {
191 PathArgs(
192 args.into_iter()
193 .map(|(k, v)| (Arc::from(k.as_ref()), v.into()))
194 .collect(),
195 )
196 }
197}
198
199#[cfg(test)]
200mod tests {
201 use super::*;
202
203 #[test]
204 fn it_sorts_path_by_length_and_then_lexicographically() {
205 let mut paths = vec![
206 Path::from_static("/a/b/c"),
207 Path::from_static(""),
208 Path::from_static("/a/b"),
209 Path::from_static("/"),
210 Path::from_static("/a/f"),
211 Path::from_static("/x"),
212 Path::from_static("/a/b/d"),
213 ];
214
215 paths.sort();
216 assert_eq!(
217 paths,
218 vec![
219 Path::from_static(""),
220 Path::from_static("/"),
221 Path::from_static("/x"),
222 Path::from_static("/a/b"),
223 Path::from_static("/a/f"),
224 Path::from_static("/a/b/c"),
225 Path::from_static("/a/b/d"),
226 ]
227 )
228 }
229
230 #[test]
231 fn it_converts_a_path_to_string() {
232 assert_eq!(Path::from_static("/a/b/c").to_string(), "/a/b/c");
233 assert_eq!(Path::from_static("/").to_string(), "/");
234 assert_eq!(Path::from_static("").to_string(), "");
235 }
236
237 #[test]
238 fn it_converts_a_str_to_a_path() {
239 let path = Path::from_static("/a/b/c");
240 assert_eq!(String::from(path), "/a/b/c");
241 }
242
243 #[test]
244 #[should_panic]
245 fn it_panics_on_an_invalid_path() {
246 Path::from_static("a/b/c");
247 }
248
249 #[test]
250 fn it_replaces_existing_key_with_insert() {
251 let mut args = PathArgs::default();
252 args.insert("one", "a");
253 args.insert("two", "b");
254
255 assert_eq!(
256 args.0,
257 vec![
258 (Arc::from("one"), "a".to_string()),
259 (Arc::from("two"), "b".to_string())
260 ]
261 );
262
263 let old = args.insert("one", "c");
265 assert_eq!(
266 args.0,
267 vec![
268 (Arc::from("one"), "c".to_string()),
269 (Arc::from("two"), "b".to_string())
270 ]
271 );
272 assert_eq!(old, Some("a".to_string()))
273 }
274
275 #[test]
276 fn test_is_prefix_of() {
277 let path_a = Path::from_static("/a");
279 let path_a_b = Path::from_static("/a/b");
280 let path_a_b_c = Path::from_static("/a/b/c");
281 let path_aa = Path::from_static("/aa");
282 let path_b = Path::from_static("/b");
283 let root = Path::from_static("");
284
285 assert!(path_a.is_prefix_of(&path_a_b));
287 assert!(path_a.is_prefix_of(&path_a_b_c));
288 assert!(path_a_b.is_prefix_of(&path_a_b_c));
289 assert!(root.is_prefix_of(&path_a));
290 assert!(root.is_prefix_of(&path_a_b));
291 assert!(path_a.is_prefix_of(&path_a)); assert!(!path_a.is_prefix_of(&path_aa)); assert!(!path_a.is_prefix_of(&path_b));
296 assert!(!path_a_b.is_prefix_of(&path_a)); assert!(!path_aa.is_prefix_of(&path_a));
298 }
299}