1use std::ops::Index;
2
3use serde::de;
4
5use crate::de::PathDeserializer;
6use crate::{Resource, ResourcePath};
7
8#[derive(Debug, Clone)]
9pub(super) enum PathItem {
10 Static(&'static str),
11 Segment(String),
12 IdxSegment(u16, u16),
13}
14
15#[derive(Debug)]
19pub struct Path<T> {
20 resource: T,
21 pub(super) skip: u16,
22 pub(super) segments: Vec<(&'static str, PathItem)>,
23}
24
25impl<T: Default> Default for Path<T> {
26 fn default() -> Self {
27 Path {
28 resource: T::default(),
29 skip: 0,
30 segments: Vec::new(),
31 }
32 }
33}
34
35impl<T: Clone> Clone for Path<T> {
36 fn clone(&self) -> Self {
37 Path {
38 resource: self.resource.clone(),
39 skip: self.skip,
40 segments: self.segments.clone(),
41 }
42 }
43}
44
45impl<T: ResourcePath> Path<T> {
46 pub fn new(resource: T) -> Path<T> {
47 Path {
48 resource,
49 skip: 0,
50 segments: Vec::new(),
51 }
52 }
53
54 #[inline]
55 pub fn get_ref(&self) -> &T {
57 &self.resource
58 }
59
60 #[inline]
61 pub fn get_mut(&mut self) -> &mut T {
63 &mut self.resource
64 }
65
66 #[inline]
67 pub fn path(&self) -> &str {
69 let skip = self.skip as usize;
70 let path = self.resource.path();
71 if skip <= path.len() { &path[skip..] } else { "" }
72 }
73
74 #[inline]
75 pub fn set(&mut self, resource: T) {
77 self.skip = 0;
78 self.resource = resource;
79 self.segments.clear();
80 }
81
82 #[inline]
83 pub fn reset(&mut self) {
85 self.skip = 0;
86 self.segments.clear();
87 }
88
89 #[inline]
90 pub fn skip(&mut self, n: u16) {
92 self.skip += n;
93 }
94
95 #[doc(hidden)]
100 pub fn add_static(&mut self, name: &'static str, value: &'static str) {
101 self.segments.push((name, PathItem::Static(value)));
102 }
103
104 #[inline]
105 pub fn is_empty(&self) -> bool {
107 self.segments.is_empty()
108 }
109
110 #[inline]
111 pub fn len(&self) -> usize {
113 self.segments.len()
114 }
115
116 pub fn get(&self, key: &str) -> Option<&str> {
118 for item in &self.segments {
119 if key == item.0 {
120 return match item.1 {
121 PathItem::Static(s) => Some(s),
122 PathItem::Segment(ref s) => Some(s),
123 PathItem::IdxSegment(s, e) => {
124 Some(&self.resource.path()[(s as usize)..(e as usize)])
125 }
126 };
127 }
128 }
129 if key == "tail" {
130 Some(&self.resource.path()[(self.skip as usize)..])
131 } else {
132 None
133 }
134 }
135
136 pub fn unprocessed(&self) -> &str {
138 &self.resource.path()[(self.skip as usize)..]
139 }
140
141 pub fn query(&self, key: &str) -> &str {
146 self.get(key).unwrap_or_default()
147 }
148
149 pub fn iter(&self) -> PathIter<'_, T> {
151 PathIter {
152 idx: 0,
153 params: self,
154 }
155 }
156
157 pub fn load<'de, U: serde::Deserialize<'de>>(&'de self) -> Result<U, de::value::Error> {
159 de::Deserialize::deserialize(PathDeserializer::new(self))
160 }
161}
162
163#[derive(Debug)]
165pub struct PathIter<'a, T> {
166 idx: usize,
167 params: &'a Path<T>,
168}
169
170impl<'a, T: ResourcePath> Iterator for PathIter<'a, T> {
171 type Item = (&'a str, &'a str);
172
173 #[inline]
174 fn next(&mut self) -> Option<(&'a str, &'a str)> {
175 if self.idx < self.params.len() {
176 let idx = self.idx;
177 let res = match self.params.segments[idx].1 {
178 PathItem::Static(s) => s,
179 PathItem::Segment(ref s) => s.as_str(),
180 PathItem::IdxSegment(s, e) => {
181 &self.params.resource.path()[(s as usize)..(e as usize)]
182 }
183 };
184 self.idx += 1;
185 return Some((self.params.segments[idx].0, res));
186 }
187 None
188 }
189}
190
191impl<'a, T: ResourcePath> Index<&'a str> for Path<T> {
192 type Output = str;
193
194 fn index(&self, name: &'a str) -> &str {
195 self.get(name)
196 .expect("Value for parameter is not available")
197 }
198}
199
200impl<T: ResourcePath> Index<usize> for Path<T> {
201 type Output = str;
202
203 fn index(&self, idx: usize) -> &str {
204 match self.segments[idx].1 {
205 PathItem::Static(s) => s,
206 PathItem::Segment(ref s) => s,
207 PathItem::IdxSegment(s, e) => &self.resource.path()[(s as usize)..(e as usize)],
208 }
209 }
210}
211
212impl<T: ResourcePath> Resource<T> for Path<T> {
213 fn path(&self) -> &str {
214 self.path()
215 }
216
217 fn resource_path(&mut self) -> &mut Path<T> {
218 self
219 }
220}
221
222#[cfg(test)]
223mod tests {
224 use super::*;
225
226 #[test]
227 fn test_path() {
228 let mut p: Path<String> = Path::default();
229 assert_eq!(p.get_ref(), &String::new());
230 p.get_mut().push_str("test");
231 assert_eq!(p.get_ref().as_str(), "test");
232 let p2 = p.clone();
233 assert_eq!(p2.get_ref().as_str(), "test");
234
235 p.skip(2);
236 assert_eq!(p.get("tail").unwrap(), "st");
237 assert_eq!(p.get("unknown"), None);
238 assert_eq!(p.query("tail"), "st");
239 assert_eq!(p.query("unknown"), "");
240 assert_eq!(p.unprocessed(), "st");
241
242 p.reset();
243 assert_eq!(p.unprocessed(), "test");
244
245 p.segments.push(("k1", PathItem::IdxSegment(0, 2)));
246 assert_eq!(p.get("k1").unwrap(), "te");
247 }
248}