matchit/
tree.rs

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