Skip to content

Commit a767043

Browse files
TroyKomodofundon
andauthored
feat: normal match repeated pattern (#37)
* 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 <[email protected]>
1 parent 09edc45 commit a767043

File tree

2 files changed

+79
-5
lines changed

2 files changed

+79
-5
lines changed

Diff for: src/node.rs

+22-5
Original file line numberDiff line numberDiff line change
@@ -215,12 +215,29 @@ impl<T: fmt::Debug> Node<T> {
215215
if let Some(id) = self.nodes0.as_ref().and_then(|nodes| {
216216
nodes.iter().find_map(|node| match &node.key {
217217
Key::String(s) => {
218-
bytes.iter().position(|b| s[0] == *b).and_then(|n| {
219-
node._find(start + n, &bytes[n..], ranges).map(|id| {
220-
ranges.push(start..start + n);
221-
id
218+
let mut keep_running = true;
219+
bytes
220+
.iter()
221+
// as it turns out doing .copied() here is much slower than dereferencing in the closure
222+
// https://godbolt.org/z/7dnW91T1Y
223+
.take_while(|b| {
224+
if keep_running && **b == b'/' {
225+
keep_running = false;
226+
true
227+
} else {
228+
keep_running
229+
}
230+
})
231+
.enumerate()
232+
.find_map(|(n, b)| {
233+
if s[0] != *b {
234+
return None;
235+
}
236+
node._find(start + n, &bytes[n..], ranges).map(|id| {
237+
ranges.push(start..start + n);
238+
id
239+
})
222240
})
223-
})
224241
}
225242
Key::Parameter(_) => unreachable!(),
226243
})

Diff for: tests/tree.rs

+57
Original file line numberDiff line numberDiff line change
@@ -2257,3 +2257,60 @@ fn test_dots_ext() {
22572257

22582258
assert_eq!(params.params(), &[("name", "abc.xyz")]);
22592259
}
2260+
2261+
#[test]
2262+
fn test_dots_ext_no_qualifier() {
2263+
let mut tree = PathTree::new();
2264+
let _ = tree.insert("/:name.js", 2);
2265+
let _ = tree.insert("/:name.js.gz", 1);
2266+
2267+
assert_eq!(
2268+
format!("{:?}", &tree.node),
2269+
r"
2270+
/
2271+
└── :
2272+
└── .js •0
2273+
└── .gz •1
2274+
"
2275+
);
2276+
2277+
let result = tree.find("/node.js");
2278+
assert!(result.is_some());
2279+
2280+
let (value, params) = result.unwrap();
2281+
assert_eq!(value, &2);
2282+
2283+
assert_eq!(params.params(), &[("name", "node")]);
2284+
2285+
let result = tree.find("/path.lib.js");
2286+
assert!(result.is_some());
2287+
2288+
let (value, params) = result.unwrap();
2289+
assert_eq!(value, &2);
2290+
2291+
assert_eq!(params.params(), &[("name", "path.lib")]);
2292+
2293+
let result = tree.find("/node.js.js");
2294+
assert!(result.is_some());
2295+
2296+
let (value, params) = result.unwrap();
2297+
assert_eq!(value, &2);
2298+
2299+
assert_eq!(params.params(), &[("name", "node.js")]);
2300+
2301+
let result = tree.find("/node.js.gz");
2302+
assert!(result.is_some());
2303+
2304+
let (value, params) = result.unwrap();
2305+
assert_eq!(value, &1);
2306+
2307+
assert_eq!(params.params(), &[("name", "node")]);
2308+
2309+
let result = tree.find("/node.js.gz.js.gz");
2310+
assert!(result.is_some());
2311+
2312+
let (value, params) = result.unwrap();
2313+
assert_eq!(value, &1);
2314+
2315+
assert_eq!(params.params(), &[("name", "node.js.gz")]);
2316+
}

0 commit comments

Comments
 (0)