Skip to content

Commit 650830e

Browse files
committed
wip
1 parent 65f24ed commit 650830e

3 files changed

Lines changed: 122 additions & 80 deletions

File tree

src/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ impl InsertError {
7979
route.append(&current.prefix);
8080
}
8181

82-
// Add the prefixes of any conflicting children.
82+
// Add the prefixes of the first conflicting child.
8383
let mut child = current.children.first();
8484
while let Some(node) = child {
8585
route.append(&node.prefix);

src/tree.rs

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub struct Node<T> {
3434
// The value stored at this node.
3535
//
3636
// See `Node::at` for why an `UnsafeCell` is necessary.
37-
value: Option<UnsafeCell<T>>,
37+
pub(crate) value: Option<UnsafeCell<T>>,
3838

3939
// A parameter name remapping, stored at nodes that hold values.
4040
pub(crate) remapping: ParamRemapping,
@@ -178,14 +178,15 @@ impl<T> Node<T> {
178178
return Ok(());
179179
}
180180

181+
let common_remaining = remaining;
182+
181183
// Otherwise, the route has a remaining non-matching suffix.
182184
//
183185
// We have to search deeper.
184186
remaining = remaining.slice_off(common_prefix);
185187
let next = remaining[0];
186188

187-
// For parameters with a suffix, we have to find the matching suffix or
188-
// create a new child node.
189+
// For parameters with a suffix, we have to find the matching suffix or create a new child node.
189190
if matches!(state.node().node_type, NodeType::Param { .. }) {
190191
let terminator = remaining
191192
.iter()
@@ -196,20 +197,15 @@ impl<T> Node<T> {
196197

197198
let suffix = remaining.slice_until(terminator);
198199

200+
// If we are inserting a suffix and there is a static prefix that already leads to this
201+
// route parameter, we have a prefix-suffix conflict.
199202
if !matches!(*suffix, b"" | b"/") {
200203
if let Some(parent) = state.parent() {
201204
for child in &parent.children {
202-
// If there is a static prefix that also leads to this route
203-
// parameter, we have a prefix-suffix conflict.
204-
//
205-
// For example, `/prefix{a}` and `/{a}suffix` are conflicting, as there is no clear
206-
// choice to match against `/prefixsuffix`.
207-
if matches!(child.node_type, NodeType::Static) && child.wild_child {
208-
return Err(InsertError::conflict(
209-
&route,
210-
UnescapedRoute::default().as_ref(), // TODO
211-
child,
212-
));
205+
if matches!(child.node_type, NodeType::Static)
206+
&& child.wild_child_in_segment()
207+
{
208+
return Err(InsertError::conflict(&route, common_remaining, child));
213209
}
214210
}
215211
}
@@ -296,7 +292,7 @@ impl<T> Node<T> {
296292
.unwrap_or(remaining.len());
297293

298294
if let Ok(Some(wildcard)) = find_wildcard(remaining.slice_until(terminator)) {
299-
// If there is a parameter prefix and this node also has a parameter suffix, we
295+
// If we are inserting a parameter prefix and this node already has a parameter suffix, we
300296
// have a prefix-suffix conflict.
301297
if wildcard.start > 0 && node.wild_child {
302298
let wild_child = node.children.last().unwrap();
@@ -342,13 +338,49 @@ impl<T> Node<T> {
342338
continue 'walk;
343339
}
344340

341+
if let Ok(Some(wildcard)) = find_wildcard(remaining) {
342+
let suffix = remaining.slice_off(wildcard.end);
343+
344+
// If we are inserting a suffix and there is a static prefix that already leads to this
345+
// route parameter, we have a prefix-suffix conflict.
346+
if !matches!(*suffix, b"" | b"/") {
347+
for child in &state.node().children {
348+
if matches!(child.node_type, NodeType::Static)
349+
&& child.wild_child_in_segment()
350+
{
351+
return Err(InsertError::conflict(&route, remaining, child));
352+
}
353+
}
354+
}
355+
}
356+
345357
// Otherwise, create a new node for the wildcard and insert the route.
346358
let last = state.node().insert_route(remaining, val)?;
347359
last.remapping = remapping;
348360
return Ok(());
349361
}
350362
}
351363

364+
/// Returns `true` if there is a wildcard parameter node within the current route segment,
365+
/// i.e. before a trailing slash.
366+
fn wild_child_in_segment(&self) -> bool {
367+
if self.wild_child {
368+
return true;
369+
}
370+
371+
for child in &self.children {
372+
if child.prefix.contains(&b'/') {
373+
continue;
374+
}
375+
376+
if child.wild_child || child.wild_child_in_segment() {
377+
return true;
378+
}
379+
}
380+
381+
false
382+
}
383+
352384
// Insert a route at this node.
353385
//
354386
// If the route starts with a wildcard, a child node will be created for the parameter

tests/insert.rs

Lines changed: 74 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -89,72 +89,82 @@ fn wildcard_conflict() {
8989
#[test]
9090
fn prefix_suffix_conflict() {
9191
InsertTest(vec![
92-
("/a/{a}suffix", Ok(())),
93-
("/a/foo/prefix{a}", Ok(())),
94-
("/a/prefix{a}", Err(conflict("/a/{a}suffix"))),
95-
96-
("/b/{a}suffix", Ok(())),
97-
("/b/prefix{a}", Err(conflict("/b/{a}suffix"))),
98-
("/b/prefix{a}suff", Err(conflict("/b/{a}suffix"))),
99-
("/b/prefix{a}suffix", Err(conflict("/b/{a}suffix"))),
100-
("/b/prefix{a}suffixabc", Err(conflict("/b/{a}suffix"))),
101-
102-
("/c/prefix{a}", Ok(())),
103-
("/c/{a}suffix", Err(conflict("/c/prefix{a}"))),
104-
("/c/prefix{a}suffix", Err(conflict("/c/prefix{a}"))),
105-
("/c/prefixabc{a}suffix", Err(conflict("/c/prefix{a}"))),
106-
("/c/pre{a}suffix", Err(conflict("/c/prefix{a}"))),
107-
108-
("/d/{a}", Ok(())),
92+
// ("/a/{a}suffix", Ok(())),
93+
// ("/a/prefix{a}", Err(conflict("/a/{a}suffix"))),
94+
// ("/a/foo/prefix{a}", Ok(())),
95+
// ("/a/prefix{a}", Err(conflict("/a/{a}suffix"))),
96+
97+
// ("/b/{a}suffix", Ok(())),
98+
// ("/b/prefix{a}", Err(conflict("/b/{a}suffix"))),
99+
// ("/b/prefix{a}suff", Err(conflict("/b/{a}suffix"))),
100+
// ("/b/prefix{a}suffix", Err(conflict("/b/{a}suffix"))),
101+
// ("/b/prefix{a}suffixabc", Err(conflict("/b/{a}suffix"))),
102+
103+
("/b/prefix{a}", Ok(())),
104+
("/b/{a}", Ok(())),
105+
("/b/{a}suffix", Err(conflict("/b/prefix{a}"))),
106+
107+
("/c/prefix1{a}", Ok(())),
108+
("/c/prefix2{a}", Ok(())),
109+
("/c/{a}", Ok(())),
110+
("/c/{a}suffix", Err(conflict("/c/prefix1{a}"))),
111+
109112
("/d/prefix{a}", Ok(())),
110113
("/d/{a}suffix", Err(conflict("/d/prefix{a}"))),
111-
("/d/prefix{a}suffix", Err(conflict("/d/prefix{a}"))),
112-
("/d/prefixabc{a}suffix", Err(conflict("/d/prefix{a}"))),
113-
("/d/pre{a}suffix", Err(conflict("/d/prefix{a}"))),
114-
115-
("/e/{a}", Ok(())),
116-
("/e/{a}suffix", Ok(())),
117-
("/e/prefix{a}", Err(conflict("/e/{a}suffix"))),
118-
("/e/prefix{a}suff", Err(conflict("/e/{a}suffix"))),
119-
("/e/prefix{a}suffix", Err(conflict("/e/{a}suffix"))),
120-
("/e/prefix{a}suffixabc", Err(conflict("/e/{a}suffix"))),
121-
122-
("/f/prefix{a}suffix", Ok(())),
123-
124-
("/f/pre{a}", Err(conflict("/f/prefix{a}suffix"))),
125-
("/f/prefix{a}", Err(conflict("/f/prefix{a}suffix"))),
126-
("/f/prefixabc{a}", Err(conflict("/f/prefix{a}suffix"))),
127-
128-
("/f/pre{a}suffix", Err(conflict("/f/prefix{a}suffix"))),
129-
("/f/prefix{a}suffix", Err(conflict("/f/prefix{a}suffix"))),
130-
("/f/prefixabc{a}suffix", Err(conflict("/f/prefix{a}suffix"))),
131-
132-
("/f/prefix{a}suff", Err(conflict("/f/prefix{a}suffix"))),
133-
("/f/prefix{a}suffix", Err(conflict("/f/prefix{a}suffix"))),
134-
("/f/prefix{a}suffixabc", Err(conflict("/f/prefix{a}suffix"))),
135-
136-
("/f/{a}suff", Err(conflict("/f/prefix{a}suffix"))),
137-
("/f/{a}suffix", Err(conflict("/f/prefix{a}suffix"))),
138-
("/f/{a}suffixabc", Err(conflict("/f/prefix{a}suffix"))),
139-
140-
("/g/{a}", Ok(())),
141-
("/g/prefix{a}suffix", Ok(())),
142-
143-
("/g/pre{a}", Err(conflict("/f/prefix{a}suffix"))),
144-
("/g/prefix{a}", Err(conflict("/f/prefix{a}suffix"))),
145-
("/g/prefixabc{a}", Err(conflict("/f/prefix{a}suffix"))),
146-
147-
("/g/pre{a}suffix", Err(conflict("/f/prefix{a}suffix"))),
148-
("/g/prefix{a}suffix", Err(conflict("/f/prefix{a}suffix"))),
149-
("/g/prefixabc{a}suffix", Err(conflict("/f/prefix{a}suffix"))),
150-
151-
("/g/prefix{a}suff", Err(conflict("/f/prefix{a}suffix"))),
152-
("/g/prefix{a}suffix", Err(conflict("/f/prefix{a}suffix"))),
153-
("/g/prefix{a}suffixabc", Err(conflict("/f/prefix{a}suffix"))),
154-
155-
("/g/{a}suff", Err(conflict("/f/prefix{a}suffix"))),
156-
("/g/{a}suffix", Err(conflict("/f/prefix{a}suffix"))),
157-
("/g/{a}suffixabc", Err(conflict("/f/prefix{a}suffix"))),
114+
// ("/c/prefix{a}suffix", Err(conflict("/c/prefix{a}"))),
115+
// ("/c/prefixabc{a}suffix", Err(conflict("/c/prefix{a}"))),
116+
// ("/c/pre{a}suffix", Err(conflict("/c/prefix{a}"))),
117+
118+
// ("/d/{a}", Ok(())),
119+
// ("/d/prefix{a}", Ok(())),
120+
// ("/d/{a}suffix", Err(conflict("/d/prefix{a}"))),
121+
// ("/d/prefix{a}suffix", Err(conflict("/d/prefix{a}"))),
122+
// ("/d/prefixabc{a}suffix", Err(conflict("/d/prefix{a}"))),
123+
// ("/d/pre{a}suffix", Err(conflict("/d/prefix{a}"))),
124+
125+
// ("/e/{a}", Ok(())),
126+
// ("/e/{a}suffix", Ok(())),
127+
// ("/e/prefix{a}", Err(conflict("/e/{a}suffix"))),
128+
// ("/e/prefix{a}suff", Err(conflict("/e/{a}suffix"))),
129+
// ("/e/prefix{a}suffix", Err(conflict("/e/{a}suffix"))),
130+
// ("/e/prefix{a}suffixabc", Err(conflict("/e/{a}suffix"))),
131+
132+
// ("/f/prefix{a}suffix", Ok(())),
133+
134+
// ("/f/pre{a}", Err(conflict("/f/prefix{a}suffix"))),
135+
// ("/f/prefix{a}", Err(conflict("/f/prefix{a}suffix"))),
136+
// ("/f/prefixabc{a}", Err(conflict("/f/prefix{a}suffix"))),
137+
138+
// ("/f/pre{a}suffix", Err(conflict("/f/prefix{a}suffix"))),
139+
// ("/f/prefix{a}suffix", Err(conflict("/f/prefix{a}suffix"))),
140+
// ("/f/prefixabc{a}suffix", Err(conflict("/f/prefix{a}suffix"))),
141+
142+
// ("/f/prefix{a}suff", Err(conflict("/f/prefix{a}suffix"))),
143+
// ("/f/prefix{a}suffix", Err(conflict("/f/prefix{a}suffix"))),
144+
// ("/f/prefix{a}suffixabc", Err(conflict("/f/prefix{a}suffix"))),
145+
146+
// ("/f/{a}suff", Err(conflict("/f/prefix{a}suffix"))),
147+
// ("/f/{a}suffix", Err(conflict("/f/prefix{a}suffix"))),
148+
// ("/f/{a}suffixabc", Err(conflict("/f/prefix{a}suffix"))),
149+
150+
// ("/g/{a}", Ok(())),
151+
// ("/g/prefix{a}suffix", Ok(())),
152+
153+
// ("/g/pre{a}", Err(conflict("/f/prefix{a}suffix"))),
154+
// ("/g/prefix{a}", Err(conflict("/f/prefix{a}suffix"))),
155+
// ("/g/prefixabc{a}", Err(conflict("/f/prefix{a}suffix"))),
156+
157+
// ("/g/pre{a}suffix", Err(conflict("/f/prefix{a}suffix"))),
158+
// ("/g/prefix{a}suffix", Err(conflict("/f/prefix{a}suffix"))),
159+
// ("/g/prefixabc{a}suffix", Err(conflict("/f/prefix{a}suffix"))),
160+
161+
// ("/g/prefix{a}suff", Err(conflict("/f/prefix{a}suffix"))),
162+
// ("/g/prefix{a}suffix", Err(conflict("/f/prefix{a}suffix"))),
163+
// ("/g/prefix{a}suffixabc", Err(conflict("/f/prefix{a}suffix"))),
164+
165+
// ("/g/{a}suff", Err(conflict("/f/prefix{a}suffix"))),
166+
// ("/g/{a}suffix", Err(conflict("/f/prefix{a}suffix"))),
167+
// ("/g/{a}suffixabc", Err(conflict("/f/prefix{a}suffix"))),
158168
])
159169
.run()
160170
}

0 commit comments

Comments
 (0)