Skip to content

Commit 5c498aa

Browse files
committed
reorganize branching
1 parent 2b8feda commit 5c498aa

1 file changed

Lines changed: 123 additions & 114 deletions

File tree

src/tree.rs

Lines changed: 123 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -481,148 +481,157 @@ impl<T> Node<T> {
481481
let mut path = full_path;
482482
let mut backtracking = false;
483483
let mut params = Params::new();
484-
let mut skipped_nodes = Vec::new();
484+
let mut skipped_nodes: Vec<Skipped<'_, '_, T>> = Vec::new();
485485

486486
'walk: loop {
487+
// Initialize the backtracker.
487488
backtracker!(skipped_nodes, path, current, params, backtracking, 'walk);
488489

489-
// The path is longer than this node's prefix, search deeper.
490-
if path.len() > current.prefix.len() {
491-
let (prefix, rest) = path.split_at(current.prefix.len());
492-
493-
// Found a matching prefix.
494-
if *prefix == *current.prefix {
495-
let first = rest[0];
496-
let consumed = path;
497-
path = rest;
498-
499-
// If we are currently backtracking, avoid searching static children
500-
// that we already searched.
501-
if !backtracking {
502-
// Find a child node that matches the next character in the path.
503-
if let Some(i) = current.indices.iter().position(|&c| c == first) {
504-
// Keep track of wildcard routes that we skip.
505-
//
506-
// We may end up needing to backtrack later in case we do not find a
507-
// match.
508-
if current.wild_child {
509-
skipped_nodes.push(Skipped {
510-
path: consumed,
511-
node: current,
512-
params: params.len(),
513-
});
514-
}
515-
516-
// Continue searching.
517-
current = &current.children[i];
518-
continue 'walk;
519-
}
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));
520499
}
500+
}
521501

522-
// We didn't find a matching static child.
523-
//
524-
// If there are no wildcards, then there are no matching routes in the tree.
525-
if !current.wild_child {
526-
// Try backtracking in case we skipped a wildcard that may match.
527-
try_backtrack!();
528-
return Err(MatchError::NotFound);
529-
}
502+
// Try backtracking in case we skipped a wildcard that may match.
503+
try_backtrack!();
530504

531-
// Continue searching in the wildcard, which are kept at the end of the list.
532-
current = current.children.last().unwrap();
533-
match current.node_type {
534-
// Match against a route parameter.
535-
NodeType::Param => {
536-
// Check for more path segments.
537-
match path.iter().position(|&c| c == b'/') {
538-
// Found another segment.
539-
Some(i) => {
540-
let (param, rest) = path.split_at(i);
541-
542-
// If there is a static child, continue the search.
543-
if let [child] = current.children.as_slice() {
544-
// Store the parameter value.
545-
//
546-
// Parameters are normalized so the key is irrelevant at this point.
547-
params.push(b"", param);
548-
549-
// Continue searching.
550-
path = rest;
551-
current = child;
552-
backtracking = false;
553-
continue 'walk;
554-
}
505+
// Otherwise, there are no matching routes in the tree.
506+
return Err(MatchError::NotFound);
507+
}
555508

556-
// Try backtracking in case we skipped a wildcard that may match.
557-
try_backtrack!();
509+
// Otherwise, the path is longer than this node's prefix, search deeper.
510+
let (prefix, rest) = path.split_at(current.prefix.len());
558511

559-
// Otherwise, there are no matching routes in the tree.
560-
return Err(MatchError::NotFound);
561-
}
562-
// This is the last path segment.
563-
None => {
564-
// Found the matching value.
565-
if let Some(ref value) = current.value {
566-
// Store the parameter value.
567-
params.push(b"", path);
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!();
568516

569-
// Remap the keys of any route parameters we accumulated during the search.
570-
params.for_each_key_mut(|(i, key)| {
571-
*key = &current.remapping[i]
572-
});
517+
// Otherwise, there are no matching routes in the tree.
518+
return Err(MatchError::NotFound);
519+
}
520+
521+
let previous = path;
522+
path = rest;
573523

574-
return Ok((value, params));
575-
}
524+
// If we are currently backtracking, avoid searching static children
525+
// that we already searched.
526+
if !backtracking {
527+
let next = path[0];
576528

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 => {
577573
// Try backtracking in case we skipped a wildcard that may match.
578574
try_backtrack!();
579575

580576
// Otherwise, there are no matching routes in the tree.
581577
return Err(MatchError::NotFound);
582578
}
583-
}
584-
}
585-
NodeType::CatchAll => {
586-
// Catch-all segments are only allowed at the end of the route.
587-
//
588-
// This node must contain the value if there is a match.
589-
return match current.value {
590-
// Found the value.
591-
Some(ref value) => {
592-
// Remap the keys of any route parameters we accumulated during the search.
593-
params
594-
.for_each_key_mut(|(i, key)| *key = &current.remapping[i]);
595-
596-
// Store the final catch-all parameter (`{*...}`).
597-
let key = &current.prefix[2..current.prefix.len() - 1];
598-
params.push(key, path);
599-
600-
Ok((value, params))
601-
}
602-
// Otherwise, there are no matching routes in the tree.
603-
None => Err(MatchError::NotFound),
604579
};
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));
605589
}
606-
_ => unreachable!(),
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;
607606
}
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);
608613
}
609-
}
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+
};
610623

611-
// Check for an exact match.
612-
if *path == *current.prefix {
613-
// Found the matching value.
614-
if let Some(ref value) = current.value {
615624
// Remap the keys of any route parameters we accumulated during the search.
616625
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+
617631
return Ok((value, params));
618632
}
633+
_ => unreachable!(),
619634
}
620-
621-
// Try backtracking in case we skipped a wildcard that may match.
622-
try_backtrack!();
623-
624-
// Otherwise, there are no matching routes in the tree.
625-
return Err(MatchError::NotFound);
626635
}
627636
}
628637

0 commit comments

Comments
 (0)