matchit/tree.rs
1use crate::escape::{UnescapedRef, UnescapedRoute};
2use crate::{InsertError, MatchError, Params};
3
4use std::cell::UnsafeCell;
5use std::cmp::min;
6use std::collections::VecDeque;
7use std::ops::Range;
8use std::{fmt, mem};
9
10/// A radix tree used for URL path matching.
11///
12/// See [the crate documentation](crate) for details.
13pub struct Node<T> {
14 // This node's prefix.
15 pub(crate) prefix: UnescapedRoute,
16 // The priority of this node.
17 //
18 // Nodes with more children are higher priority and searched first.
19 pub(crate) priority: u32,
20 // Whether this node contains a wildcard child.
21 pub(crate) wild_child: bool,
22 // The first character of any static children, for fast linear search.
23 pub(crate) indices: Vec<u8>,
24 // The type of this node.
25 pub(crate) node_type: NodeType,
26 pub(crate) children: Vec<Self>,
27 // The value stored at this node.
28 //
29 // See `Node::at` for why an `UnsafeCell` is necessary.
30 value: Option<UnsafeCell<T>>,
31 // Parameter name remapping, stored at nodes that hold values.
32 pub(crate) remapping: ParamRemapping,
33}
34
35/// The types of nodes a tree can hold.
36#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone)]
37pub(crate) enum NodeType {
38 /// The root path.
39 Root,
40 /// A route parameter, e.g. `/{id}`.
41 Param,
42 /// A catch-all parameter, e.g. `/*file`.
43 CatchAll,
44 /// A static prefix, e.g. `/foo`.
45 Static,
46}
47
48/// Safety: We expose `value` per Rust's usual borrowing rules, so we can just
49/// delegate these traits.
50unsafe impl<T: Send> Send for Node<T> {}
51unsafe impl<T: Sync> Sync for Node<T> {}
52
53impl<T> Node<T> {
54 // Insert a route into the tree.
55 pub fn insert(&mut self, route: String, val: T) -> Result<(), InsertError> {
56 let route = UnescapedRoute::new(route.into_bytes());
57 let (route, remapping) = normalize_params(route)?;
58 let mut remaining = route.as_ref();
59
60 self.priority += 1;
61
62 // If the tree is empty, insert the root node.
63 if self.prefix.is_empty() && self.children.is_empty() {
64 let last = self.insert_route(remaining, val)?;
65 last.remapping = remapping;
66 self.node_type = NodeType::Root;
67 return Ok(());
68 }
69
70 let mut current = self;
71 'walk: loop {
72 // Find the common prefix between the route and the current node.
73 let len = min(remaining.len(), current.prefix.len());
74 let common_prefix = (0..len)
75 .find(|&i| {
76 remaining[i] != current.prefix[i]
77 // Make sure not confuse the start of a wildcard with an escaped `{`.
78 || remaining.is_escaped(i) != current.prefix.is_escaped(i)
79 })
80 .unwrap_or(len);
81
82 // If this node has a longer prefix than we need, we have to fork and extract the
83 // common prefix into a shared parent.
84 if current.prefix.len() > common_prefix {
85 // Move the non-matching suffix into a child node.
86 let suffix = current.prefix.as_ref().slice_off(common_prefix).to_owned();
87 let child = Node {
88 prefix: suffix,
89 value: current.value.take(),
90 indices: current.indices.clone(),
91 wild_child: current.wild_child,
92 children: mem::take(&mut current.children),
93 remapping: mem::take(&mut current.remapping),
94 priority: current.priority - 1,
95 node_type: NodeType::Static,
96 };
97
98 // The current node now only holds the common prefix.
99 current.children = vec![child];
100 current.indices = vec![current.prefix[common_prefix]];
101 current.prefix = current
102 .prefix
103 .as_ref()
104 .slice_until(common_prefix)
105 .to_owned();
106 current.wild_child = false;
107 continue;
108 }
109
110 if remaining.len() == common_prefix {
111 // This node must not already contain a value.
112 if current.value.is_some() {
113 return Err(InsertError::conflict(&route, remaining, current));
114 }
115
116 // Insert the value.
117 current.value = Some(UnsafeCell::new(val));
118 current.remapping = remapping;
119 return Ok(());
120 }
121
122 // Otherwise, the route has a remaining non-matching suffix.
123 //
124 // We have to search deeper.
125 remaining = remaining.slice_off(common_prefix);
126 let next = remaining[0];
127
128 // After matching against a wildcard the next character is always `/`.
129 //
130 // Continue searching in the child node if it already exists.
131 if current.node_type == NodeType::Param && current.children.len() == 1 {
132 debug_assert_eq!(next, b'/');
133 current = &mut current.children[0];
134 current.priority += 1;
135 continue 'walk;
136 }
137
138 // Find a child node that matches the next character in the route.
139 for mut i in 0..current.indices.len() {
140 if next == current.indices[i] {
141 // Make sure not confuse the start of a wildcard with an escaped `{` or `}`.
142 if matches!(next, b'{' | b'}') && !remaining.is_escaped(0) {
143 continue;
144 }
145
146 // Continue searching in the child.
147 i = current.update_child_priority(i);
148 current = &mut current.children[i];
149 continue 'walk;
150 }
151 }
152
153 // We couldn't find a matching child.
154 //
155 // If we're not inserting a wildcard we have to create a child.
156 if (!matches!(next, b'{') || remaining.is_escaped(0))
157 && current.node_type != NodeType::CatchAll
158 {
159 current.indices.push(next);
160 let mut child = current.add_child(Node::default());
161 child = current.update_child_priority(child);
162
163 // Insert into the newly created node.
164 let last = current.children[child].insert_route(remaining, val)?;
165 last.remapping = remapping;
166 return Ok(());
167 }
168
169 // We're trying to insert a wildcard.
170 //
171 // If this node already has a wildcard child, we have to make sure it matches.
172 if current.wild_child {
173 // Wildcards are always the last child.
174 current = current.children.last_mut().unwrap();
175 current.priority += 1;
176
177 // Make sure the route parameter matches.
178 if let Some(wildcard) = remaining.get(..current.prefix.len()) {
179 if *wildcard != *current.prefix {
180 return Err(InsertError::conflict(&route, remaining, current));
181 }
182 }
183
184 // Catch-all routes cannot have children.
185 if current.node_type == NodeType::CatchAll {
186 return Err(InsertError::conflict(&route, remaining, current));
187 }
188
189 // Continue with the wildcard node.
190 continue 'walk;
191 }
192
193 // Otherwise, create a new node for the wildcard and insert the route.
194 let last = current.insert_route(remaining, val)?;
195 last.remapping = remapping;
196 return Ok(());
197 }
198 }
199
200 /// Removes a route from the tree, returning the value if the route already existed.
201 ///
202 /// The provided path should be the same as the one used to insert the route, including
203 /// wildcards.
204 pub fn remove(&mut self, route: String) -> Option<T> {
205 let route = UnescapedRoute::new(route.into_bytes());
206 let (route, remapping) = normalize_params(route).ok()?;
207 let mut remaining = route.unescaped();
208
209 // Check if we are removing the root node.
210 if remaining == self.prefix.unescaped() {
211 let value = self.value.take().map(UnsafeCell::into_inner);
212
213 // If the root node has no children, we can reset it.
214 if self.children.is_empty() {
215 *self = Node::default();
216 }
217
218 return value;
219 }
220
221 let mut current = self;
222 'walk: loop {
223 // The path is longer than this node's prefix, search deeper.
224 if remaining.len() > current.prefix.len() {
225 let (prefix, rest) = remaining.split_at(current.prefix.len());
226
227 // The prefix matches.
228 if prefix == current.prefix.unescaped() {
229 let first = rest[0];
230 remaining = rest;
231
232 // If there is a single child node, we can continue searching in the child.
233 if current.children.len() == 1 {
234 // The route matches, remove the node.
235 if current.children[0].prefix.unescaped() == remaining {
236 return current.remove_child(0, &remapping);
237 }
238
239 // Otherwise, continue searching.
240 current = &mut current.children[0];
241 continue 'walk;
242 }
243
244 // Find a child node that matches the next character in the route.
245 if let Some(i) = current.indices.iter().position(|&c| c == first) {
246 // The route matches, remove the node.
247 if current.children[i].prefix.unescaped() == remaining {
248 return current.remove_child(i, &remapping);
249 }
250
251 // Otherwise, continue searching.
252 current = &mut current.children[i];
253 continue 'walk;
254 }
255
256 // If the node has a matching wildcard child, continue searching in the child.
257 if current.wild_child
258 && remaining.first().zip(remaining.get(2)) == Some((&b'{', &b'}'))
259 {
260 // The route matches, remove the node.
261 if current.children.last_mut().unwrap().prefix.unescaped() == remaining {
262 return current.remove_child(current.children.len() - 1, &remapping);
263 }
264
265 current = current.children.last_mut().unwrap();
266 continue 'walk;
267 }
268 }
269 }
270
271 // Could not find a match.
272 return None;
273 }
274 }
275
276 /// Remove the child node at the given index, if the route parameters match.
277 fn remove_child(&mut self, i: usize, remapping: &ParamRemapping) -> Option<T> {
278 // Require an exact match to remove a route.
279 //
280 // For example, `/{a}` cannot be used to remove `/{b}`.
281 if self.children[i].remapping != *remapping {
282 return None;
283 }
284
285 // If the node does not have any children, we can remove it completely.
286 let value = if self.children[i].children.is_empty() {
287 // Removing a single child with no indices.
288 if self.children.len() == 1 && self.indices.is_empty() {
289 self.wild_child = false;
290 self.children.remove(0).value.take()
291 } else {
292 // Remove the child node.
293 let child = self.children.remove(i);
294
295 match child.node_type {
296 // Remove the index if we removed a static prefix.
297 NodeType::Static => {
298 self.indices.remove(i);
299 }
300 // Otherwise, we removed a wildcard.
301 _ => self.wild_child = false,
302 }
303
304 child.value
305 }
306 }
307 // Otherwise, remove the value but preserve the node.
308 else {
309 self.children[i].value.take()
310 };
311
312 value.map(UnsafeCell::into_inner)
313 }
314
315 // Adds a child to this node, keeping wildcards at the end.
316 fn add_child(&mut self, child: Node<T>) -> usize {
317 let len = self.children.len();
318
319 if self.wild_child && len > 0 {
320 self.children.insert(len - 1, child);
321 len - 1
322 } else {
323 self.children.push(child);
324 len
325 }
326 }
327
328 // Increments priority of the given child node, reordering the children if necessary.
329 //
330 // Returns the new index of the node.
331 fn update_child_priority(&mut self, i: usize) -> usize {
332 self.children[i].priority += 1;
333 let priority = self.children[i].priority;
334
335 // Move the node to the front as necessary.
336 let mut updated = i;
337 while updated > 0 && self.children[updated - 1].priority < priority {
338 self.children.swap(updated - 1, updated);
339 updated -= 1;
340 }
341
342 // Update the position of the indices to match.
343 if updated != i {
344 self.indices[updated..=i].rotate_right(1);
345 }
346
347 updated
348 }
349
350 // Insert a route at this node.
351 fn insert_route(
352 &mut self,
353 mut prefix: UnescapedRef<'_>,
354 val: T,
355 ) -> Result<&mut Node<T>, InsertError> {
356 let mut current = self;
357
358 loop {
359 // Search for a wildcard segment.
360 let wildcard = match find_wildcard(prefix)? {
361 Some(wildcard) => wildcard,
362 // There is no wildcard, simply insert into the current node.
363 None => {
364 current.value = Some(UnsafeCell::new(val));
365 current.prefix = prefix.to_owned();
366 return Ok(current);
367 }
368 };
369
370 // Insering a catch-all route.
371 if prefix[wildcard.clone()][1] == b'*' {
372 // Ensure there is no suffix after the parameter, e.g. `/foo/{*x}/bar`.
373 if wildcard.end != prefix.len() {
374 return Err(InsertError::InvalidCatchAll);
375 }
376
377 // Add the prefix before the wildcard into the current node.
378 if wildcard.start > 0 {
379 current.prefix = prefix.slice_until(wildcard.start).to_owned();
380 prefix = prefix.slice_off(wildcard.start);
381 }
382
383 // Add the catch-all as a child node.
384 let child = Self {
385 prefix: prefix.to_owned(),
386 node_type: NodeType::CatchAll,
387 value: Some(UnsafeCell::new(val)),
388 priority: 1,
389 ..Self::default()
390 };
391
392 let i = current.add_child(child);
393 current.wild_child = true;
394 return Ok(&mut current.children[i]);
395 }
396
397 // Otherwise, we're inserting a regular route parameter.
398 assert_eq!(prefix[wildcard.clone()][0], b'{');
399
400 // Add the prefix before the wildcard into the current node.
401 if wildcard.start > 0 {
402 current.prefix = prefix.slice_until(wildcard.start).to_owned();
403 prefix = prefix.slice_off(wildcard.start);
404 }
405
406 // Add the parameter as a child node.
407 let child = Self {
408 node_type: NodeType::Param,
409 prefix: prefix.slice_until(wildcard.len()).to_owned(),
410 ..Self::default()
411 };
412
413 let child = current.add_child(child);
414 current.wild_child = true;
415 current = &mut current.children[child];
416 current.priority += 1;
417
418 // If the route doesn't end in the wildcard, we have to insert the suffix as a child.
419 if wildcard.len() < prefix.len() {
420 prefix = prefix.slice_off(wildcard.len());
421 let child = Self {
422 priority: 1,
423 ..Self::default()
424 };
425
426 let child = current.add_child(child);
427 current = &mut current.children[child];
428 continue;
429 }
430
431 // Finally, insert the value.
432 current.value = Some(UnsafeCell::new(val));
433 return Ok(current);
434 }
435 }
436}
437
438/// A wildcard node that was skipped during a tree search.
439///
440/// Contains the state necessary to backtrack to the given node.
441struct Skipped<'n, 'p, T> {
442 // The node that was skipped.
443 node: &'n Node<T>,
444 /// The path at the time we skipped this node.
445 path: &'p [u8],
446 // The number of parameters that were present.
447 params: usize,
448}
449
450#[rustfmt::skip]
451macro_rules! backtracker {
452 ($skipped_nodes:ident, $path:ident, $current:ident, $params:ident, $backtracking:ident, $walk:lifetime) => {
453 macro_rules! try_backtrack {
454 () => {
455 // Try backtracking to any matching wildcard nodes that we skipped while
456 // traversing the tree.
457 while let Some(skipped) = $skipped_nodes.pop() {
458 if skipped.path.ends_with($path) {
459 // Restore the search state.
460 $path = skipped.path;
461 $current = &skipped.node;
462 $params.truncate(skipped.params);
463 $backtracking = true;
464 continue $walk;
465 }
466 }
467 };
468 }
469 };
470}
471
472impl<T> Node<T> {
473 // Returns the node matching the given path.
474 //
475 // Returning an `UnsafeCell` allows us to avoid duplicating the logic between `Node::at` and
476 // `Node::at_mut`, as Rust doesn't have a great way of abstracting over mutability.
477 pub fn at<'node, 'path>(
478 &'node self,
479 full_path: &'path [u8],
480 ) -> Result<(&'node UnsafeCell<T>, Params<'node, 'path>), MatchError> {
481 let mut current = self;
482 let mut path = full_path;
483 let mut backtracking = false;
484 let mut params = Params::new();
485 let mut skipped_nodes: Vec<Skipped<'_, '_, T>> = Vec::new();
486
487 'walk: loop {
488 // Initialize the backtracker.
489 backtracker!(skipped_nodes, path, current, params, backtracking, 'walk);
490
491 // Reached the end of the search.
492 if path.len() <= current.prefix.len() {
493 // Check for an exact match.
494 if *path == *current.prefix {
495 // Found the matching value.
496 if let Some(ref value) = current.value {
497 // Remap the keys of any route parameters we accumulated during the search.
498 params.for_each_key_mut(|(i, key)| *key = ¤t.remapping[i]);
499 return Ok((value, params));
500 }
501 }
502
503 // Try backtracking in case we skipped a wildcard that may match.
504 try_backtrack!();
505
506 // Otherwise, there are no matching routes in the tree.
507 return Err(MatchError::NotFound);
508 }
509
510 // Otherwise, the path is longer than this node's prefix, search deeper.
511 let (prefix, rest) = path.split_at(current.prefix.len());
512
513 // The prefix does not match.
514 if *prefix != *current.prefix {
515 // Try backtracking in case we skipped a wildcard that may match.
516 try_backtrack!();
517
518 // Otherwise, there are no matching routes in the tree.
519 return Err(MatchError::NotFound);
520 }
521
522 let previous = path;
523 path = rest;
524
525 // If we are currently backtracking, avoid searching static children
526 // that we already searched.
527 if !backtracking {
528 let next = path[0];
529
530 // Find a child node that matches the next character in the path.
531 if let Some(i) = current.indices.iter().position(|&c| c == next) {
532 // Keep track of wildcard routes that we skip.
533 //
534 // We may end up needing to backtrack later in case we do not find a
535 // match.
536 if current.wild_child {
537 skipped_nodes.push(Skipped {
538 path: previous,
539 node: current,
540 params: params.len(),
541 });
542 }
543
544 // Continue searching.
545 current = ¤t.children[i];
546 continue 'walk;
547 }
548 }
549
550 // We didn't find a matching static child.
551 //
552 // If there are no wildcards, then there are no matching routes in the tree.
553 if !current.wild_child {
554 // Try backtracking in case we skipped a wildcard that may match.
555 try_backtrack!();
556 return Err(MatchError::NotFound);
557 }
558
559 // Continue searching in the wildcard child, which is kept at the end of the list.
560 current = current.children.last().unwrap();
561 match current.node_type {
562 // Match against a route parameter.
563 NodeType::Param => {
564 // Check for more path segments.
565 let i = match path.iter().position(|&c| c == b'/') {
566 // Double `//` implying an empty parameter, no match.
567 Some(0) => {
568 try_backtrack!();
569 return Err(MatchError::NotFound);
570 }
571 // Found another segment.
572 Some(i) => i,
573 // This is the last path segment.
574 None => {
575 let value = match current.value {
576 // Found the matching value.
577 Some(ref value) => value,
578 None => {
579 // Try backtracking in case we skipped a wildcard that may match.
580 try_backtrack!();
581
582 // Otherwise, there are no matching routes in the tree.
583 return Err(MatchError::NotFound);
584 }
585 };
586
587 // Store the parameter value.
588 // Parameters are normalized so the key is irrelevant for now.
589 params.push(b"", path);
590
591 // Remap the keys of any route parameters we accumulated during the search.
592 params.for_each_key_mut(|(i, key)| *key = ¤t.remapping[i]);
593
594 return Ok((value, params));
595 }
596 };
597
598 // Found another path segment.
599 let (param, rest) = path.split_at(i);
600
601 // If there is a static child, continue the search.
602 if let [child] = current.children.as_slice() {
603 // Store the parameter value.
604 // Parameters are normalized so the key is irrelevant for now.
605 params.push(b"", param);
606
607 // Continue searching.
608 path = rest;
609 current = child;
610 backtracking = false;
611 continue 'walk;
612 }
613
614 // Try backtracking in case we skipped a wildcard that may match.
615 try_backtrack!();
616
617 // Otherwise, there are no matching routes in the tree.
618 return Err(MatchError::NotFound);
619 }
620 NodeType::CatchAll => {
621 // Catch-all segments are only allowed at the end of the route, meaning
622 // this node must contain the value.
623 let value = match current.value {
624 // Found the matching value.
625 Some(ref value) => value,
626 // Otherwise, there are no matching routes in the tree.
627 None => return Err(MatchError::NotFound),
628 };
629
630 // Remap the keys of any route parameters we accumulated during the search.
631 params.for_each_key_mut(|(i, key)| *key = ¤t.remapping[i]);
632
633 // Store the final catch-all parameter (`{*...}`).
634 let key = ¤t.prefix[2..current.prefix.len() - 1];
635 params.push(key, path);
636
637 return Ok((value, params));
638 }
639 _ => unreachable!(),
640 }
641 }
642 }
643
644 /// Test helper that ensures route priorities are consistent.
645 #[cfg(feature = "__test_helpers")]
646 pub fn check_priorities(&self) -> Result<u32, (u32, u32)> {
647 let mut priority: u32 = 0;
648 for child in &self.children {
649 priority += child.check_priorities()?;
650 }
651
652 if self.value.is_some() {
653 priority += 1;
654 }
655
656 if self.priority != priority {
657 return Err((self.priority, priority));
658 }
659
660 Ok(priority)
661 }
662}
663
664impl<T> Node<T> {
665 /// Iterates over the tree and calls the given visitor function
666 /// with fully resolved path and its value.
667 pub fn for_each<V: FnMut(String, T)>(self, mut visitor: V) {
668 let mut queue = VecDeque::from([(self.prefix.clone(), self)]);
669
670 // Perform a BFS on the routing tree.
671 while let Some((mut prefix, mut node)) = queue.pop_front() {
672 denormalize_params(&mut prefix, &node.remapping);
673
674 if let Some(value) = node.value.take() {
675 let path = String::from_utf8(prefix.unescaped().to_vec()).unwrap();
676 visitor(path, value.into_inner());
677 }
678
679 // Traverse the child nodes.
680 for child in node.children {
681 let mut prefix = prefix.clone();
682 prefix.append(&child.prefix);
683 queue.push_back((prefix, child));
684 }
685 }
686 }
687}
688
689/// An ordered list of route parameters keys for a specific route.
690///
691/// To support conflicting routes like `/{a}/foo` and `/{b}/bar`, route parameters
692/// are normalized before being inserted into the tree. Parameter remapping are
693/// stored at nodes containing values, containing the "true" names of all route parameters
694/// for the given route.
695type ParamRemapping = Vec<Vec<u8>>;
696
697/// Returns `path` with normalized route parameters, and a parameter remapping
698/// to store at the node for this route.
699///
700/// Note that the parameter remapping may contain unescaped characters.
701fn normalize_params(
702 mut path: UnescapedRoute,
703) -> Result<(UnescapedRoute, ParamRemapping), InsertError> {
704 let mut start = 0;
705 let mut original = ParamRemapping::new();
706
707 // Parameter names are normalized alphabetically.
708 let mut next = b'a';
709
710 loop {
711 // Find a wildcard to normalize.
712 let mut wildcard = match find_wildcard(path.as_ref().slice_off(start))? {
713 Some(wildcard) => wildcard,
714 // No wildcard, we are done.
715 None => return Ok((path, original)),
716 };
717
718 wildcard.start += start;
719 wildcard.end += start;
720
721 // Ensure the parameter has a valid name.
722 if wildcard.len() < 2 {
723 return Err(InsertError::InvalidParam);
724 }
725
726 // We don't need to normalize catch-all parameters, as they are always
727 // at the end of a route.
728 if path[wildcard.clone()][1] == b'*' {
729 start = wildcard.end;
730 continue;
731 }
732
733 // Normalize the parameter.
734 let removed = path.splice(wildcard.clone(), vec![b'{', next, b'}']);
735
736 // Preserve the original name for remapping.
737 let mut removed = removed.skip(1).collect::<Vec<_>>();
738 removed.pop();
739 original.push(removed);
740
741 next += 1;
742 if next > b'z' {
743 panic!("Too many route parameters.");
744 }
745
746 // Continue the search after the parameter we just normalized.
747 start = wildcard.start + 3;
748 }
749}
750
751/// Restores `route` to it's original, denormalized form.
752pub(crate) fn denormalize_params(route: &mut UnescapedRoute, params: &ParamRemapping) {
753 let mut start = 0;
754 let mut i = 0;
755
756 loop {
757 // Find a wildcard to denormalize.
758 let mut wildcard = match find_wildcard(route.as_ref().slice_off(start)).unwrap() {
759 Some(w) => w,
760 None => return,
761 };
762
763 wildcard.start += start;
764 wildcard.end += start;
765
766 // Get the corresponding parameter remapping.
767 let mut next = match params.get(i) {
768 Some(param) => param.clone(),
769 None => return,
770 };
771
772 // Denormalize this parameter.
773 next.insert(0, b'{');
774 next.push(b'}');
775 let _ = route.splice(wildcard.clone(), next.clone());
776
777 i += 1;
778 start = wildcard.start + next.len();
779 }
780}
781
782// Searches for a wildcard segment and checks the path for invalid characters.
783fn find_wildcard(path: UnescapedRef<'_>) -> Result<Option<Range<usize>>, InsertError> {
784 for (start, &c) in path.iter().enumerate() {
785 // Found an unescaped closing brace without a corresponding opening brace.
786 if c == b'}' && !path.is_escaped(start) {
787 return Err(InsertError::InvalidParam);
788 }
789
790 // Keep going until we find an unescaped opening brace.
791 if c != b'{' || path.is_escaped(start) {
792 continue;
793 }
794
795 // Ensure there is a non-empty parameter name.
796 if path.get(start + 1) == Some(&b'}') {
797 return Err(InsertError::InvalidParam);
798 }
799
800 // Find the corresponding closing brace.
801 for (i, &c) in path.iter().enumerate().skip(start + 2) {
802 match c {
803 b'}' => {
804 // This closing brace was escaped, keep searching.
805 if path.is_escaped(i) {
806 continue;
807 }
808
809 // Ensure catch-all parameters have a non-empty name.
810 if path.get(i - 1) == Some(&b'*') {
811 return Err(InsertError::InvalidParam);
812 }
813
814 if let Some(&c) = path.get(i + 1) {
815 // Prefixes after route parameters are not supported.
816 if c != b'/' {
817 return Err(InsertError::InvalidParamSegment);
818 }
819 }
820
821 return Ok(Some(start..i + 1));
822 }
823 // `*` and `/` are invalid in parameter names.
824 b'*' | b'/' => return Err(InsertError::InvalidParam),
825 _ => {}
826 }
827 }
828
829 // Missing closing brace.
830 return Err(InsertError::InvalidParam);
831 }
832
833 Ok(None)
834}
835
836impl<T> Clone for Node<T>
837where
838 T: Clone,
839{
840 fn clone(&self) -> Self {
841 let value = self.value.as_ref().map(|value| {
842 // Safety: We only expose `&mut T` through `&mut self`.
843 let value = unsafe { &*value.get() };
844 UnsafeCell::new(value.clone())
845 });
846
847 Self {
848 value,
849 prefix: self.prefix.clone(),
850 wild_child: self.wild_child,
851 node_type: self.node_type.clone(),
852 indices: self.indices.clone(),
853 children: self.children.clone(),
854 remapping: self.remapping.clone(),
855 priority: self.priority,
856 }
857 }
858}
859
860impl<T> Default for Node<T> {
861 fn default() -> Self {
862 Self {
863 remapping: ParamRemapping::new(),
864 prefix: UnescapedRoute::default(),
865 wild_child: false,
866 node_type: NodeType::Static,
867 indices: Vec::new(),
868 children: Vec::new(),
869 value: None,
870 priority: 0,
871 }
872 }
873}
874
875impl<T> fmt::Debug for Node<T>
876where
877 T: fmt::Debug,
878{
879 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
880 // Safety: We only expose `&mut T` through `&mut self`.
881 let value = unsafe { self.value.as_ref().map(|x| &*x.get()) };
882
883 let mut f = f.debug_struct("Node");
884 f.field("value", &value)
885 .field("prefix", &self.prefix)
886 .field("node_type", &self.node_type)
887 .field("children", &self.children);
888
889 // Extra information for debugging purposes.
890 #[cfg(test)]
891 {
892 let indices = self
893 .indices
894 .iter()
895 .map(|&x| char::from_u32(x as _))
896 .collect::<Vec<_>>();
897
898 let params = self
899 .remapping
900 .iter()
901 .map(|x| std::str::from_utf8(x).unwrap())
902 .collect::<Vec<_>>();
903
904 f.field("indices", &indices).field("params", ¶ms);
905 }
906
907 f.finish()
908 }
909}