1use std::{
2 borrow::Cow,
3 ops::{DerefMut, Index},
4};
5
6use serde::{de, Deserialize};
7
8use crate::{de::PathDeserializer, Resource, ResourcePath};
9
10#[derive(Debug, Clone)]
11pub(crate) enum PathItem {
12 Static(Cow<'static, str>),
13 Segment(u16, u16),
14}
15
16impl Default for PathItem {
17 fn default() -> Self {
18 Self::Static(Cow::Borrowed(""))
19 }
20}
21
22#[derive(Debug, Clone, Default)]
26pub struct Path<T> {
27 path: T,
29
30 pub(crate) skip: u16,
32
33 pub(crate) segments: Vec<(Cow<'static, str>, PathItem)>,
35}
36
37impl<T: ResourcePath> Path<T> {
38 pub fn new(path: T) -> Path<T> {
39 Path {
40 path,
41 skip: 0,
42 segments: Vec::new(),
43 }
44 }
45
46 #[inline]
48 pub fn get_ref(&self) -> &T {
49 &self.path
50 }
51
52 #[inline]
54 pub fn get_mut(&mut self) -> &mut T {
55 &mut self.path
56 }
57
58 #[inline]
60 pub fn as_str(&self) -> &str {
61 self.path.path()
62 }
63
64 #[inline]
68 pub fn unprocessed(&self) -> &str {
69 let skip = (self.skip as usize).min(self.as_str().len());
71 &self.path.path()[skip..]
72 }
73
74 #[doc(hidden)]
76 #[deprecated(since = "0.6.0", note = "Use `.as_str()` or `.unprocessed()`.")]
77 #[inline]
78 pub fn path(&self) -> &str {
79 let skip = self.skip as usize;
80 let path = self.path.path();
81 if skip <= path.len() {
82 &path[skip..]
83 } else {
84 ""
85 }
86 }
87
88 #[inline]
90 pub fn set(&mut self, path: T) {
91 self.path = path;
92 self.skip = 0;
93 self.segments.clear();
94 }
95
96 #[inline]
98 pub fn reset(&mut self) {
99 self.skip = 0;
100 self.segments.clear();
101 }
102
103 #[inline]
105 pub fn skip(&mut self, n: u16) {
106 self.skip += n;
107 }
108
109 pub(crate) fn add(&mut self, name: impl Into<Cow<'static, str>>, value: PathItem) {
110 match value {
111 PathItem::Static(seg) => self.segments.push((name.into(), PathItem::Static(seg))),
112 PathItem::Segment(begin, end) => self.segments.push((
113 name.into(),
114 PathItem::Segment(self.skip + begin, self.skip + end),
115 )),
116 }
117 }
118
119 #[doc(hidden)]
120 pub fn add_static(
121 &mut self,
122 name: impl Into<Cow<'static, str>>,
123 value: impl Into<Cow<'static, str>>,
124 ) {
125 self.segments
126 .push((name.into(), PathItem::Static(value.into())));
127 }
128
129 #[inline]
131 pub fn is_empty(&self) -> bool {
132 self.segments.is_empty()
133 }
134
135 #[inline]
137 pub fn segment_count(&self) -> usize {
138 self.segments.len()
139 }
140
141 pub fn get(&self, name: &str) -> Option<&str> {
143 for (seg_name, val) in self.segments.iter() {
144 if name == seg_name {
145 return match val {
146 PathItem::Static(ref s) => Some(s),
147 PathItem::Segment(s, e) => {
148 Some(&self.path.path()[(*s as usize)..(*e as usize)])
149 }
150 };
151 }
152 }
153
154 None
155 }
156
157 pub fn query(&self, key: &str) -> &str {
161 self.get(key).unwrap_or_default()
162 }
163
164 pub fn iter(&self) -> PathIter<'_, T> {
166 PathIter {
167 idx: 0,
168 params: self,
169 }
170 }
171
172 pub fn load<'de, U: Deserialize<'de>>(&'de self) -> Result<U, de::value::Error> {
178 Deserialize::deserialize(PathDeserializer::new(self))
179 }
180}
181
182#[derive(Debug)]
183pub struct PathIter<'a, T> {
184 idx: usize,
185 params: &'a Path<T>,
186}
187
188impl<'a, T: ResourcePath> Iterator for PathIter<'a, T> {
189 type Item = (&'a str, &'a str);
190
191 #[inline]
192 fn next(&mut self) -> Option<(&'a str, &'a str)> {
193 if self.idx < self.params.segment_count() {
194 let idx = self.idx;
195 let res = match self.params.segments[idx].1 {
196 PathItem::Static(ref s) => s,
197 PathItem::Segment(s, e) => &self.params.path.path()[(s as usize)..(e as usize)],
198 };
199 self.idx += 1;
200 return Some((&self.params.segments[idx].0, res));
201 }
202 None
203 }
204}
205
206impl<'a, T: ResourcePath> Index<&'a str> for Path<T> {
207 type Output = str;
208
209 fn index(&self, name: &'a str) -> &str {
210 self.get(name)
211 .expect("Value for parameter is not available")
212 }
213}
214
215impl<T: ResourcePath> Index<usize> for Path<T> {
216 type Output = str;
217
218 fn index(&self, idx: usize) -> &str {
219 match self.segments[idx].1 {
220 PathItem::Static(ref s) => s,
221 PathItem::Segment(s, e) => &self.path.path()[(s as usize)..(e as usize)],
222 }
223 }
224}
225
226impl<T: ResourcePath> Resource for Path<T> {
227 type Path = T;
228
229 fn resource_path(&mut self) -> &mut Path<Self::Path> {
230 self
231 }
232}
233
234impl<T, P> Resource for T
235where
236 T: DerefMut<Target = Path<P>>,
237 P: ResourcePath,
238{
239 type Path = P;
240
241 fn resource_path(&mut self) -> &mut Path<Self::Path> {
242 &mut *self
243 }
244}
245
246#[cfg(test)]
247mod tests {
248 use std::cell::RefCell;
249
250 use super::*;
251
252 #[allow(clippy::needless_borrow)]
253 #[test]
254 fn deref_impls() {
255 let mut foo = Path::new("/foo");
256 let _ = (&mut foo).resource_path();
257
258 let foo = RefCell::new(foo);
259 let _ = foo.borrow_mut().resource_path();
260 }
261}