@@ -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 ,
@@ -77,20 +77,34 @@ struct InsertState<'node, T> {
7777}
7878
7979impl < ' node , T > InsertState < ' node , T > {
80- fn node ( & mut self ) -> & mut Node < T > {
80+ fn node_mut ( & mut self ) -> & mut Node < T > {
8181 match self . child {
8282 None => self . parent ,
8383 Some ( i) => & mut self . parent . children [ i] ,
8484 }
8585 }
8686
87- fn parent ( & mut self ) -> Option < & mut Node < T > > {
87+ fn parent_mut ( & mut self ) -> Option < & mut Node < T > > {
8888 match self . child {
8989 None => None ,
9090 Some ( _) => Some ( self . parent ) ,
9191 }
9292 }
9393
94+ fn parent ( & self ) -> Option < & Node < T > > {
95+ match self . child {
96+ None => None ,
97+ Some ( _) => Some ( self . parent ) ,
98+ }
99+ }
100+
101+ fn node ( & self ) -> & Node < T > {
102+ match self . child {
103+ None => self . parent ,
104+ Some ( i) => & self . parent . children [ i] ,
105+ }
106+ }
107+
94108 fn set_child ( self , i : usize ) -> InsertState < ' node , T > {
95109 match self . child {
96110 None => InsertState {
@@ -129,19 +143,19 @@ impl<T> Node<T> {
129143
130144 ' walk: loop {
131145 // Find the common prefix between the route and the current node.
132- let len = min ( remaining. len ( ) , state. node ( ) . prefix . len ( ) ) ;
146+ let len = min ( remaining. len ( ) , state. node_mut ( ) . prefix . len ( ) ) ;
133147 let common_prefix = ( 0 ..len)
134148 . find ( |& i| {
135- remaining[ i] != state. node ( ) . prefix [ i]
149+ remaining[ i] != state. node_mut ( ) . prefix [ i]
136150 // Make sure not confuse the start of a wildcard with an escaped `{`.
137- || remaining. is_escaped ( i) != state. node ( ) . prefix . is_escaped ( i)
151+ || remaining. is_escaped ( i) != state. node_mut ( ) . prefix . is_escaped ( i)
138152 } )
139153 . unwrap_or ( len) ;
140154
141155 // If this node has a longer prefix than we need, we have to fork and extract the
142156 // common prefix into a shared parent.
143- if state. node ( ) . prefix . len ( ) > common_prefix {
144- let node = state. node ( ) ;
157+ if state. node_mut ( ) . prefix . len ( ) > common_prefix {
158+ let node = state. node_mut ( ) ;
145159
146160 // Move the non-matching suffix into a child node.
147161 let suffix = node. prefix . as_ref ( ) . slice_off ( common_prefix) . to_owned ( ) ;
@@ -165,7 +179,7 @@ impl<T> Node<T> {
165179 }
166180
167181 if remaining. len ( ) == common_prefix {
168- let node = state. node ( ) ;
182+ let node = state. node_mut ( ) ;
169183
170184 // This node must not already contain a value.
171185 if node. value . is_some ( ) {
@@ -178,50 +192,91 @@ impl<T> Node<T> {
178192 return Ok ( ( ) ) ;
179193 }
180194
195+ let common_remaining = remaining;
196+
181197 // Otherwise, the route has a remaining non-matching suffix.
182198 //
183199 // We have to search deeper.
184200 remaining = remaining. slice_off ( common_prefix) ;
185201 let next = remaining[ 0 ] ;
186202
187- // For parameters with a suffix, we have to find the matching suffix or
188- // create a new child node.
189- if matches ! ( state. node( ) . node_type, NodeType :: Param { .. } ) {
203+ {
190204 let terminator = remaining
191205 . iter ( )
192206 . position ( |& b| b == b'/' )
193207 // Include the '/' in the suffix.
194208 . map ( |b| b + 1 )
195209 . unwrap_or ( remaining. len ( ) ) ;
196210
197- let suffix = remaining. slice_until ( terminator) ;
211+ if let Ok ( Some ( wildcard) ) = find_wildcard ( remaining. slice_until ( terminator) ) {
212+ let suffix = remaining. slice_off ( wildcard. end ) ;
198213
199- if !matches ! ( * suffix, b"" | b"/" ) {
200- if let Some ( parent) = state. parent ( ) {
201- 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 {
214+ if !matches ! ( * suffix, b"" | b"/" ) {
215+ // If we are inserting a suffix and there is a static prefix that already leads to this
216+ // route parameter, we have a prefix-suffix conflict.
217+ for child in & state. node ( ) . children {
218+ if state. node ( ) . wild_child_in_segment ( ) {
208219 return Err ( InsertError :: conflict (
209220 & route,
210- UnescapedRoute :: default ( ) . as_ref ( ) , // TODO
211- child ,
221+ common_remaining ,
222+ state . node ( ) ,
212223 ) ) ;
213224 }
225+
226+ if matches ! ( child. node_type, NodeType :: Static )
227+ && child. wild_child_in_segment ( )
228+ {
229+ return Err ( InsertError :: conflict ( & route, remaining, child) ) ;
230+ }
214231 }
215232 }
216233 }
234+ }
235+
236+ // For parameters with a suffix, we have to find the matching suffix or create a new child node.
237+ if matches ! ( state. node_mut( ) . node_type, NodeType :: Param { .. } ) {
238+ let terminator = remaining
239+ . iter ( )
240+ . position ( |& b| b == b'/' )
241+ // Include the '/' in the suffix.
242+ . map ( |b| b + 1 )
243+ . unwrap_or ( remaining. len ( ) ) ;
244+
245+ let suffix = remaining. slice_until ( terminator) ;
217246
218- for ( i, child) in state. node ( ) . children . iter ( ) . enumerate ( ) {
247+ let mut extra_trailing_slash = false ;
248+ for ( i, child) in state. node_mut ( ) . children . iter ( ) . enumerate ( ) {
219249 // Find a matching suffix.
220250 if * child. prefix == * * suffix {
221- state. node ( ) . priority += 1 ;
251+ state. node_mut ( ) . priority += 1 ;
222252 state = state. set_child ( i) ;
223253 continue ' walk;
224254 }
255+
256+ // Matches except for an extra trailing slash.
257+ if let Some ( ( common, remaining) ) = suffix. split_at_checked ( child. prefix . len ( ) ) {
258+ if * common == * child. prefix && remaining == * b"/" {
259+ extra_trailing_slash = true ;
260+ }
261+ }
262+ }
263+
264+ // If we are inserting a conflicting suffix, and there is a static prefix that already leads to
265+ // this route parameter, we have a prefix-suffix conflict.
266+ if !extra_trailing_slash && !matches ! ( * suffix, b"" | b"/" ) {
267+ if let Some ( parent) = state. parent_mut ( ) {
268+ if parent. wild_child_in_segment ( ) {
269+ return Err ( InsertError :: conflict ( & route, common_remaining, parent) ) ;
270+ }
271+
272+ for child in & parent. children {
273+ if matches ! ( child. node_type, NodeType :: Static )
274+ && child. wild_child_in_segment ( )
275+ {
276+ return Err ( InsertError :: conflict ( & route, common_remaining, child) ) ;
277+ }
278+ }
279+ }
225280 }
226281
227282 // Multiple parameters within the same segment, e.g. `/{foo}{bar}`.
@@ -230,19 +285,20 @@ impl<T> Node<T> {
230285 }
231286
232287 // If there is no matching suffix, create a new suffix node.
233- let child = state. node ( ) . add_suffix_child ( Node {
288+ let child = state. node_mut ( ) . add_suffix_child ( Node {
234289 prefix : suffix. to_owned ( ) ,
235290 node_type : NodeType :: Static ,
236291 priority : 1 ,
237292 ..Node :: default ( )
238293 } ) ;
239- state. node ( ) . node_type = NodeType :: Param { suffix : true } ;
294+ let has_suffix = !matches ! ( * suffix, b"" | b"/" ) ;
295+ state. node_mut ( ) . node_type = NodeType :: Param { suffix : has_suffix } ;
240296 state = state. set_child ( child) ;
241297
242298 // If this is the final route segment, insert the value.
243299 if terminator == remaining. len ( ) {
244- state. node ( ) . value = Some ( UnsafeCell :: new ( val) ) ;
245- state. node ( ) . remapping = remapping;
300+ state. node_mut ( ) . value = Some ( UnsafeCell :: new ( val) ) ;
301+ state. node_mut ( ) . remapping = remapping;
246302 return Ok ( ( ) ) ;
247303 }
248304
@@ -252,31 +308,31 @@ impl<T> Node<T> {
252308
253309 // Create a static node unless we are inserting a parameter.
254310 if remaining[ 0 ] != b'{' || remaining. is_escaped ( 0 ) {
255- let child = state. node ( ) . add_child ( Node {
311+ let child = state. node_mut ( ) . add_child ( Node {
256312 node_type : NodeType :: Static ,
257313 priority : 1 ,
258314 ..Node :: default ( )
259315 } ) ;
260- state. node ( ) . indices . push ( remaining[ 0 ] ) ;
316+ state. node_mut ( ) . indices . push ( remaining[ 0 ] ) ;
261317 state = state. set_child ( child) ;
262318 }
263319
264320 // Insert the remaining route.
265- let last = state. node ( ) . insert_route ( remaining, val) ?;
321+ let last = state. node_mut ( ) . insert_route ( remaining, val) ?;
266322 last. remapping = remapping;
267323 return Ok ( ( ) ) ;
268324 }
269325
270326 // Find a child node that matches the next character in the route.
271- for mut i in 0 ..state. node ( ) . indices . len ( ) {
272- if next == state. node ( ) . indices [ i] {
327+ for mut i in 0 ..state. node_mut ( ) . indices . len ( ) {
328+ if next == state. node_mut ( ) . indices [ i] {
273329 // Make sure not confuse the start of a wildcard with an escaped `{` or `}`.
274330 if matches ! ( next, b'{' | b'}' ) && !remaining. is_escaped ( 0 ) {
275331 continue ;
276332 }
277333
278334 // Continue searching in the child.
279- i = state. node ( ) . update_child_priority ( i) ;
335+ i = state. node_mut ( ) . update_child_priority ( i) ;
280336 state = state. set_child ( i) ;
281337 continue ' walk;
282338 }
@@ -286,17 +342,17 @@ impl<T> Node<T> {
286342 //
287343 // If we're not inserting a wildcard we have to create a static child.
288344 if ( next != b'{' || remaining. is_escaped ( 0 ) )
289- && state. node ( ) . node_type != NodeType :: CatchAll
345+ && state. node_mut ( ) . node_type != NodeType :: CatchAll
290346 {
291- let node = state. node ( ) ;
347+ let node = state. node_mut ( ) ;
292348
293349 let terminator = remaining
294350 . iter ( )
295351 . position ( |& b| b == b'/' )
296352 . unwrap_or ( remaining. len ( ) ) ;
297353
298354 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
355+ // If we are inserting a parameter prefix and this node already has a parameter suffix, we
300356 // have a prefix-suffix conflict.
301357 if wildcard. start > 0 && node. wild_child {
302358 let wild_child = node. children . last ( ) . unwrap ( ) ;
@@ -320,35 +376,105 @@ impl<T> Node<T> {
320376 // We're trying to insert a wildcard.
321377 //
322378 // If this node already has a wildcard child, we have to make sure it matches.
323- if state. node ( ) . wild_child {
379+ if state. node_mut ( ) . wild_child {
324380 // Wildcards are always the last child.
325- let wild_child = state. node ( ) . children . len ( ) - 1 ;
381+ let wild_child = state. node_mut ( ) . children . len ( ) - 1 ;
326382 state = state. set_child ( wild_child) ;
327- state. node ( ) . priority += 1 ;
383+ state. node_mut ( ) . priority += 1 ;
328384
329385 // Make sure the route parameter matches.
330- if let Some ( wildcard) = remaining. get ( ..state. node ( ) . prefix . len ( ) ) {
331- if * wildcard != * state. node ( ) . prefix {
332- return Err ( InsertError :: conflict ( & route, remaining, state. node ( ) ) ) ;
386+ if let Some ( wildcard) = remaining. get ( ..state. node_mut ( ) . prefix . len ( ) ) {
387+ if * wildcard != * state. node_mut ( ) . prefix {
388+ return Err ( InsertError :: conflict ( & route, remaining, state. node_mut ( ) ) ) ;
333389 }
334390 }
335391
336392 // Catch-all routes cannot have children.
337- if state. node ( ) . node_type == NodeType :: CatchAll {
338- return Err ( InsertError :: conflict ( & route, remaining, state. node ( ) ) ) ;
393+ if state. node_mut ( ) . node_type == NodeType :: CatchAll {
394+ return Err ( InsertError :: conflict ( & route, remaining, state. node_mut ( ) ) ) ;
395+ }
396+
397+ if let Some ( parent) = state. parent ( ) {
398+ // If there is a route with both a prefix and a suffix, and we are inserting a route with a
399+ // matching prefix but _without_ a suffix, we have a prefix-suffix conflict.
400+ if !parent. prefix . ends_with ( b"/" )
401+ && !state. node ( ) . prefix . starts_with ( b"/" )
402+ && matches ! ( state. node( ) . node_type, NodeType :: Param { suffix: true } )
403+ {
404+ let terminator = remaining
405+ . iter ( )
406+ . position ( |& b| b == b'/' )
407+ // Include the '/' in the suffix.
408+ . map ( |b| b + 1 )
409+ . unwrap_or ( remaining. len ( ) ) ;
410+
411+ if let Ok ( Some ( wildcard) ) = find_wildcard ( remaining. slice_until ( terminator) )
412+ {
413+ let suffix = remaining. slice_off ( wildcard. end ) ;
414+
415+ if matches ! ( * suffix, b"" | b"/" ) {
416+ return Err ( InsertError :: conflict ( & route, remaining, parent) ) ;
417+ }
418+ }
419+ }
339420 }
340421
341422 // Continue with the wildcard node.
342423 continue ' walk;
343424 }
344425
426+ if let Ok ( Some ( wildcard) ) = find_wildcard ( remaining) {
427+ let node = state. node_mut ( ) ;
428+ let suffix = remaining. slice_off ( wildcard. end ) ;
429+
430+ // If we are inserting a suffix and there is a static prefix that already leads to this
431+ // route parameter, we have a prefix-suffix conflict.
432+ if !matches ! ( * suffix, b"" | b"/" ) {
433+ for child in & node. children {
434+ if node. wild_child_in_segment ( ) {
435+ return Err ( InsertError :: conflict ( & route, common_remaining, node) ) ;
436+ }
437+
438+ if matches ! ( child. node_type, NodeType :: Static )
439+ && child. wild_child_in_segment ( )
440+ {
441+ return Err ( InsertError :: conflict ( & route, remaining, child) ) ;
442+ }
443+ }
444+ }
445+ }
446+
345447 // Otherwise, create a new node for the wildcard and insert the route.
346- let last = state. node ( ) . insert_route ( remaining, val) ?;
448+ let last = state. node_mut ( ) . insert_route ( remaining, val) ?;
347449 last. remapping = remapping;
348450 return Ok ( ( ) ) ;
349451 }
350452 }
351453
454+ /// Returns `true` if there is a wildcard parameter node within the current route segment,
455+ /// i.e. before a trailing slash.
456+ fn wild_child_in_segment ( & self ) -> bool {
457+ if self . prefix . last ( ) == Some ( & b'/' ) {
458+ return false ;
459+ }
460+
461+ if self . wild_child {
462+ return true ;
463+ }
464+
465+ for child in & self . children {
466+ if child. prefix . contains ( & b'/' ) {
467+ return false ;
468+ }
469+
470+ if child. wild_child || child. wild_child_in_segment ( ) {
471+ return true ;
472+ }
473+ }
474+
475+ false
476+ }
477+
352478 // Insert a route at this node.
353479 //
354480 // If the route starts with a wildcard, a child node will be created for the parameter
0 commit comments