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 = &current.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 = &current.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 = &current.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 = &current.remapping[i]);
632
633                    // Store the final catch-all parameter (`{*...}`).
634                    let key = &current.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", &params);
905        }
906
907        f.finish()
908    }
909}