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 #[doc(hidden)]
101 pub fn update_with_reindex<F>(&mut self, path: T, mut reindex: F)
102 where
103 F: FnMut(u16) -> u16,
104 {
105 self.skip = reindex(self.skip);
106
107 for (_, item) in &mut self.segments {
108 if let PathItem::Segment(start, end) = item {
109 *start = reindex(*start);
110 *end = reindex(*end);
111
112 if *start > *end {
113 *start = *end;
114 }
115 }
116 }
117
118 self.path = path;
119 let path = self.path.path();
120
121 self.skip = clamp_to_char_boundary(path, self.skip);
122
123 for (_, item) in &mut self.segments {
124 if let PathItem::Segment(start, end) = item {
125 *start = clamp_to_char_boundary(path, *start);
126 *end = clamp_to_char_boundary(path, *end);
127
128 if *start > *end {
129 *start = *end;
130 }
131 }
132 }
133 }
134
135 #[inline]
137 pub fn reset(&mut self) {
138 self.skip = 0;
139 self.segments.clear();
140 }
141
142 #[inline]
144 pub fn skip(&mut self, n: u16) {
145 self.skip += n;
146 }
147
148 pub(crate) fn add(&mut self, name: impl Into<Cow<'static, str>>, value: PathItem) {
149 match value {
150 PathItem::Static(seg) => self.segments.push((name.into(), PathItem::Static(seg))),
151 PathItem::Segment(begin, end) => self.segments.push((
152 name.into(),
153 PathItem::Segment(self.skip + begin, self.skip + end),
154 )),
155 }
156 }
157
158 #[doc(hidden)]
159 pub fn add_static(
160 &mut self,
161 name: impl Into<Cow<'static, str>>,
162 value: impl Into<Cow<'static, str>>,
163 ) {
164 self.segments
165 .push((name.into(), PathItem::Static(value.into())));
166 }
167
168 #[inline]
170 pub fn is_empty(&self) -> bool {
171 self.segments.is_empty()
172 }
173
174 #[inline]
176 pub fn segment_count(&self) -> usize {
177 self.segments.len()
178 }
179
180 pub fn get(&self, name: &str) -> Option<&str> {
182 for (seg_name, val) in self.segments.iter() {
183 if name == seg_name {
184 return match val {
185 PathItem::Static(ref seg) => Some(seg),
186 PathItem::Segment(start, end) => {
187 Some(&self.path.path()[(*start as usize)..(*end as usize)])
188 }
189 };
190 }
191 }
192
193 None
194 }
195
196 pub fn query(&self, key: &str) -> &str {
200 self.get(key).unwrap_or_default()
201 }
202
203 pub fn iter(&self) -> PathIter<'_, T> {
205 PathIter {
206 idx: 0,
207 params: self,
208 }
209 }
210
211 pub fn load<'de, U: Deserialize<'de>>(&'de self) -> Result<U, de::value::Error> {
217 Deserialize::deserialize(PathDeserializer::new(self))
218 }
219}
220
221fn clamp_to_char_boundary(path: &str, idx: u16) -> u16 {
222 let mut idx = usize::from(idx).min(path.len());
223
224 while idx > 0 && !path.is_char_boundary(idx) {
225 idx -= 1;
226 }
227
228 idx as u16
229}
230
231#[derive(Debug)]
232pub struct PathIter<'a, T> {
233 idx: usize,
234 params: &'a Path<T>,
235}
236
237impl<'a, T: ResourcePath> Iterator for PathIter<'a, T> {
238 type Item = (&'a str, &'a str);
239
240 #[inline]
241 fn next(&mut self) -> Option<(&'a str, &'a str)> {
242 if self.idx < self.params.segment_count() {
243 let idx = self.idx;
244 let res = match self.params.segments[idx].1 {
245 PathItem::Static(ref seg) => seg,
246 PathItem::Segment(start, end) => {
247 &self.params.path.path()[(start as usize)..(end as usize)]
248 }
249 };
250 self.idx += 1;
251 return Some((&self.params.segments[idx].0, res));
252 }
253 None
254 }
255}
256
257impl<'a, T: ResourcePath> Index<&'a str> for Path<T> {
258 type Output = str;
259
260 fn index(&self, name: &'a str) -> &str {
261 self.get(name)
262 .expect("Value for parameter is not available")
263 }
264}
265
266impl<T: ResourcePath> Index<usize> for Path<T> {
267 type Output = str;
268
269 fn index(&self, idx: usize) -> &str {
270 match self.segments[idx].1 {
271 PathItem::Static(ref seg) => seg,
272 PathItem::Segment(start, end) => &self.path.path()[(start as usize)..(end as usize)],
273 }
274 }
275}
276
277impl<T: ResourcePath> Resource for Path<T> {
278 type Path = T;
279
280 fn resource_path(&mut self) -> &mut Path<Self::Path> {
281 self
282 }
283}
284
285impl<T, P> Resource for T
286where
287 T: DerefMut<Target = Path<P>>,
288 P: ResourcePath,
289{
290 type Path = P;
291
292 fn resource_path(&mut self) -> &mut Path<Self::Path> {
293 &mut *self
294 }
295}
296
297#[cfg(test)]
298mod tests {
299 use std::cell::RefCell;
300
301 use super::*;
302
303 #[allow(clippy::needless_borrow)]
304 #[test]
305 fn deref_impls() {
306 let mut foo = Path::new("/foo");
307 let _ = (&mut foo).resource_path();
308
309 let foo = RefCell::new(foo);
310 let _ = foo.borrow_mut().resource_path();
311 }
312}