Skip to content

Commit

Permalink
feat: normal match repeated pattern (#37)
Browse files Browse the repository at this point in the history
* feat: normal match repeated pattern

This commit adds a feature which allows the normal matcher to match
paths like `/:file.gz` or `/:lib.js.gz`

Previously this would have found no routes on paths like
`/node.js.gz`

Now `/:file.gz` matches `/node.js.gz` where "name" => "node.js"
And `/:lib.js.gz` matches `/node.js.gz` where "lib" => "node"

Which to me seems like the correct result in these cases.

fixes: #36

* chore: remove iter copied

* fix: revert iter enumerate

* chore: remove unless comments

* chore: check keeprunning first

---------

Co-authored-by: Fangdun Tsai <fundon@pindash.io>
  • Loading branch information
TroyKomodo and fundon authored Jan 2, 2024
1 parent 09edc45 commit a767043
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 5 deletions.
27 changes: 22 additions & 5 deletions src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,29 @@ impl<T: fmt::Debug> Node<T> {
if let Some(id) = self.nodes0.as_ref().and_then(|nodes| {
nodes.iter().find_map(|node| match &node.key {
Key::String(s) => {
bytes.iter().position(|b| s[0] == *b).and_then(|n| {
node._find(start + n, &bytes[n..], ranges).map(|id| {
ranges.push(start..start + n);
id
let mut keep_running = true;
bytes
.iter()
// as it turns out doing .copied() here is much slower than dereferencing in the closure
// https://godbolt.org/z/7dnW91T1Y
.take_while(|b| {
if keep_running && **b == b'/' {
keep_running = false;
true
} else {
keep_running
}
})
.enumerate()
.find_map(|(n, b)| {
if s[0] != *b {
return None;
}
node._find(start + n, &bytes[n..], ranges).map(|id| {
ranges.push(start..start + n);
id
})
})
})
}
Key::Parameter(_) => unreachable!(),
})
Expand Down
57 changes: 57 additions & 0 deletions tests/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2257,3 +2257,60 @@ fn test_dots_ext() {

assert_eq!(params.params(), &[("name", "abc.xyz")]);
}

#[test]
fn test_dots_ext_no_qualifier() {
let mut tree = PathTree::new();
let _ = tree.insert("/:name.js", 2);
let _ = tree.insert("/:name.js.gz", 1);

assert_eq!(
format!("{:?}", &tree.node),
r"
/
└── :
└── .js •0
└── .gz •1
"
);

let result = tree.find("/node.js");
assert!(result.is_some());

let (value, params) = result.unwrap();
assert_eq!(value, &2);

assert_eq!(params.params(), &[("name", "node")]);

let result = tree.find("/path.lib.js");
assert!(result.is_some());

let (value, params) = result.unwrap();
assert_eq!(value, &2);

assert_eq!(params.params(), &[("name", "path.lib")]);

let result = tree.find("/node.js.js");
assert!(result.is_some());

let (value, params) = result.unwrap();
assert_eq!(value, &2);

assert_eq!(params.params(), &[("name", "node.js")]);

let result = tree.find("/node.js.gz");
assert!(result.is_some());

let (value, params) = result.unwrap();
assert_eq!(value, &1);

assert_eq!(params.params(), &[("name", "node")]);

let result = tree.find("/node.js.gz.js.gz");
assert!(result.is_some());

let (value, params) = result.unwrap();
assert_eq!(value, &1);

assert_eq!(params.params(), &[("name", "node.js.gz")]);
}

0 comments on commit a767043

Please sign in to comment.