@@ -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 ,
@@ -71,6 +71,47 @@ pub(crate) enum NodeType {
7171unsafe impl < T : Send > Send for Node < T > { }
7272unsafe impl < T : Sync > Sync for Node < T > { }
7373
74+ struct InsertState < ' node , T > {
75+ parent : & ' node mut Node < T > ,
76+ child : Option < usize > ,
77+ }
78+
79+ impl < ' node , T > InsertState < ' node , T > {
80+ fn node_mut ( & mut self ) -> & mut Node < T > {
81+ match self . child {
82+ None => self . parent ,
83+ Some ( i) => & mut self . parent . children [ i] ,
84+ }
85+ }
86+
87+ fn parent ( & self ) -> Option < & Node < T > > {
88+ match self . child {
89+ None => None ,
90+ Some ( _) => Some ( self . parent ) ,
91+ }
92+ }
93+
94+ fn node ( & self ) -> & Node < T > {
95+ match self . child {
96+ None => self . parent ,
97+ Some ( i) => & self . parent . children [ i] ,
98+ }
99+ }
100+
101+ fn set_child ( self , i : usize ) -> InsertState < ' node , T > {
102+ match self . child {
103+ None => InsertState {
104+ parent : self . parent ,
105+ child : Some ( i) ,
106+ } ,
107+ Some ( prev) => InsertState {
108+ parent : & mut self . parent . children [ prev] ,
109+ child : Some ( i) ,
110+ } ,
111+ }
112+ }
113+ }
114+
74115impl < T > Node < T > {
75116 // Insert a route into the tree.
76117 pub fn insert ( & mut self , route : String , val : T ) -> Result < ( ) , InsertError > {
@@ -88,21 +129,27 @@ impl<T> Node<T> {
88129 return Ok ( ( ) ) ;
89130 }
90131
91- let mut node = self ;
132+ let mut state = InsertState {
133+ parent : self ,
134+ child : None ,
135+ } ;
136+
92137 ' walk: loop {
93138 // Find the common prefix between the route and the current node.
94- let len = min ( remaining. len ( ) , node. prefix . len ( ) ) ;
139+ let len = min ( remaining. len ( ) , state . node ( ) . prefix . len ( ) ) ;
95140 let common_prefix = ( 0 ..len)
96141 . find ( |& i| {
97- remaining[ i] != node. prefix [ i]
142+ remaining[ i] != state . node ( ) . prefix [ i]
98143 // Make sure not confuse the start of a wildcard with an escaped `{`.
99- || remaining. is_escaped ( i) != node. prefix . is_escaped ( i)
144+ || remaining. is_escaped ( i) != state . node ( ) . prefix . is_escaped ( i)
100145 } )
101146 . unwrap_or ( len) ;
102147
103148 // If this node has a longer prefix than we need, we have to fork and extract the
104149 // common prefix into a shared parent.
105- if node. prefix . len ( ) > common_prefix {
150+ if state. node ( ) . prefix . len ( ) > common_prefix {
151+ let node = state. node_mut ( ) ;
152+
106153 // Move the non-matching suffix into a child node.
107154 let suffix = node. prefix . as_ref ( ) . slice_off ( common_prefix) . to_owned ( ) ;
108155 let child = Node {
@@ -125,6 +172,8 @@ impl<T> Node<T> {
125172 }
126173
127174 if remaining. len ( ) == common_prefix {
175+ let node = state. node_mut ( ) ;
176+
128177 // This node must not already contain a value.
129178 if node. value . is_some ( ) {
130179 return Err ( InsertError :: conflict ( & route, remaining, node) ) ;
@@ -136,30 +185,58 @@ impl<T> Node<T> {
136185 return Ok ( ( ) ) ;
137186 }
138187
188+ let common_remaining = remaining;
189+
139190 // Otherwise, the route has a remaining non-matching suffix.
140191 //
141192 // We have to search deeper.
142193 remaining = remaining. slice_off ( common_prefix) ;
143194 let next = remaining[ 0 ] ;
144195
145- // For parameters with a suffix, we have to find the matching suffix or
146- // create a new child node.
147- if matches ! ( node. node_type, NodeType :: Param { .. } ) {
196+ // For parameters with a suffix, we have to find the matching suffix or create a new child node.
197+ if matches ! ( state. node( ) . node_type, NodeType :: Param { .. } ) {
148198 let terminator = remaining
149199 . iter ( )
150200 . position ( |& b| b == b'/' )
201+ // Include the '/' in the suffix.
151202 . map ( |b| b + 1 )
152203 . unwrap_or ( remaining. len ( ) ) ;
153204
154205 let suffix = remaining. slice_until ( terminator) ;
155206
156- for ( i, child) in node. children . iter ( ) . enumerate ( ) {
207+ let mut extra_trailing_slash = false ;
208+ for ( i, child) in state. node ( ) . children . iter ( ) . enumerate ( ) {
157209 // Find a matching suffix.
158210 if * child. prefix == * * suffix {
159- node = & mut node . children [ i ] ;
160- node . priority += 1 ;
211+ state . node_mut ( ) . priority += 1 ;
212+ state = state . set_child ( i ) ;
161213 continue ' walk;
162214 }
215+
216+ // Matches except for an extra trailing slash.
217+ if let Some ( ( common, remaining) ) = suffix. split_at_checked ( child. prefix . len ( ) ) {
218+ if * common == * child. prefix && remaining == * b"/" {
219+ extra_trailing_slash = true ;
220+ }
221+ }
222+ }
223+
224+ // If we are inserting a conflicting suffix, and there is a static prefix that already leads to
225+ // this route parameter, we have a prefix-suffix conflict.
226+ if !extra_trailing_slash && !matches ! ( * suffix, b"" | b"/" ) {
227+ if let Some ( parent) = state. parent ( ) {
228+ // TODO: Combine these two conditions.
229+ if parent. wild_child_in_segment ( ) {
230+ return Err ( InsertError :: conflict ( & route, common_remaining, parent) ) ;
231+ }
232+ for child in & parent. children {
233+ if matches ! ( child. node_type, NodeType :: Static )
234+ && child. wild_child_in_segment ( )
235+ {
236+ return Err ( InsertError :: conflict ( & route, common_remaining, child) ) ;
237+ }
238+ }
239+ }
163240 }
164241
165242 // Multiple parameters within the same segment, e.g. `/{foo}{bar}`.
@@ -168,19 +245,20 @@ impl<T> Node<T> {
168245 }
169246
170247 // If there is no matching suffix, create a new suffix node.
171- let child = node . add_suffix_child ( Node {
248+ let child = state . node_mut ( ) . add_suffix_child ( Node {
172249 prefix : suffix. to_owned ( ) ,
173250 node_type : NodeType :: Static ,
174251 priority : 1 ,
175252 ..Node :: default ( )
176253 } ) ;
177- node. node_type = NodeType :: Param { suffix : true } ;
178- node = & mut node. children [ child] ;
254+ let has_suffix = !matches ! ( * suffix, b"" | b"/" ) ;
255+ state. node_mut ( ) . node_type = NodeType :: Param { suffix : has_suffix } ;
256+ state = state. set_child ( child) ;
179257
180258 // If this is the final route segment, insert the value.
181259 if terminator == remaining. len ( ) {
182- node . value = Some ( UnsafeCell :: new ( val) ) ;
183- node . remapping = remapping;
260+ state . node_mut ( ) . value = Some ( UnsafeCell :: new ( val) ) ;
261+ state . node_mut ( ) . remapping = remapping;
184262 return Ok ( ( ) ) ;
185263 }
186264
@@ -190,40 +268,68 @@ impl<T> Node<T> {
190268
191269 // Create a static node unless we are inserting a parameter.
192270 if remaining[ 0 ] != b'{' || remaining. is_escaped ( 0 ) {
193- let child = node . add_child ( Node {
271+ let child = state . node_mut ( ) . add_child ( Node {
194272 node_type : NodeType :: Static ,
195273 priority : 1 ,
196274 ..Node :: default ( )
197275 } ) ;
198- node . indices . push ( remaining[ 0 ] ) ;
199- node = & mut node . children [ child] ;
276+ state . node_mut ( ) . indices . push ( remaining[ 0 ] ) ;
277+ state = state . set_child ( child) ;
200278 }
201279
202280 // Insert the remaining route.
203- let last = node . insert_route ( remaining, val) ?;
281+ let last = state . node_mut ( ) . insert_route ( remaining, val) ?;
204282 last. remapping = remapping;
205283 return Ok ( ( ) ) ;
206284 }
207285
208286 // Find a child node that matches the next character in the route.
209- for mut i in 0 ..node. indices . len ( ) {
210- if next == node. indices [ i] {
287+ for mut i in 0 ..state . node ( ) . indices . len ( ) {
288+ if next == state . node ( ) . indices [ i] {
211289 // Make sure not confuse the start of a wildcard with an escaped `{` or `}`.
212290 if matches ! ( next, b'{' | b'}' ) && !remaining. is_escaped ( 0 ) {
213291 continue ;
214292 }
215293
216294 // Continue searching in the child.
217- i = node . update_child_priority ( i) ;
218- node = & mut node . children [ i ] ;
295+ i = state . node_mut ( ) . update_child_priority ( i) ;
296+ state = state . set_child ( i ) ;
219297 continue ' walk;
220298 }
221299 }
222300
223301 // We couldn't find a matching child.
224302 //
225303 // If we're not inserting a wildcard we have to create a static child.
226- if ( next != b'{' || remaining. is_escaped ( 0 ) ) && node. node_type != NodeType :: CatchAll {
304+ if ( next != b'{' || remaining. is_escaped ( 0 ) )
305+ && state. node ( ) . node_type != NodeType :: CatchAll
306+ {
307+ let node = state. node_mut ( ) ;
308+
309+ let terminator = remaining
310+ . iter ( )
311+ . position ( |& b| b == b'/' )
312+ . unwrap_or ( remaining. len ( ) ) ;
313+
314+ if let Ok ( Some ( wildcard) ) = find_wildcard ( remaining. slice_until ( terminator) ) {
315+ // If we are inserting a parameter prefix and this node already has a parameter suffix, we
316+ // have a prefix-suffix conflict.
317+ if wildcard. start > 0 && node. wild_child {
318+ let wild_child = node. children . last ( ) . unwrap ( ) ;
319+
320+ if matches ! ( wild_child. node_type, NodeType :: Param { suffix: true } ) {
321+ return Err ( InsertError :: conflict ( & route, remaining, wild_child) ) ;
322+ }
323+ }
324+
325+ // Similarly, we are inserting a parameter suffix and this node already has a parameter prefix, we
326+ // have a prefix-suffix conflict.
327+ let suffix = remaining. slice_off ( wildcard. end ) ;
328+ if !matches ! ( * suffix, b"" | b"/" ) && node. wild_child_in_segment ( ) {
329+ return Err ( InsertError :: conflict ( & route, remaining, node) ) ;
330+ }
331+ }
332+
227333 node. indices . push ( next) ;
228334 let child = node. add_child ( Node :: default ( ) ) ;
229335 let child = node. update_child_priority ( child) ;
@@ -237,34 +343,90 @@ impl<T> Node<T> {
237343 // We're trying to insert a wildcard.
238344 //
239345 // If this node already has a wildcard child, we have to make sure it matches.
240- if node. wild_child {
346+ if state . node ( ) . wild_child {
241347 // Wildcards are always the last child.
242- node = node. children . last_mut ( ) . unwrap ( ) ;
243- node. priority += 1 ;
348+ let wild_child = state. node ( ) . children . len ( ) - 1 ;
349+ state = state. set_child ( wild_child) ;
350+ state. node_mut ( ) . priority += 1 ;
244351
245352 // Make sure the route parameter matches.
246- if let Some ( wildcard) = remaining. get ( ..node. prefix . len ( ) ) {
247- if * wildcard != * node. prefix {
248- return Err ( InsertError :: conflict ( & route, remaining, node) ) ;
353+ if let Some ( wildcard) = remaining. get ( ..state . node ( ) . prefix . len ( ) ) {
354+ if * wildcard != * state . node ( ) . prefix {
355+ return Err ( InsertError :: conflict ( & route, remaining, state . node ( ) ) ) ;
249356 }
250357 }
251358
252359 // Catch-all routes cannot have children.
253- if node. node_type == NodeType :: CatchAll {
254- return Err ( InsertError :: conflict ( & route, remaining, node) ) ;
360+ if state. node ( ) . node_type == NodeType :: CatchAll {
361+ return Err ( InsertError :: conflict ( & route, remaining, state. node ( ) ) ) ;
362+ }
363+
364+ if let Some ( parent) = state. parent ( ) {
365+ // If there is a route with both a prefix and a suffix, and we are inserting a route with a
366+ // matching prefix but _without_ a suffix, we have a prefix-suffix conflict.
367+ if !parent. prefix . ends_with ( b"/" )
368+ && !state. node ( ) . prefix . starts_with ( b"/" )
369+ && matches ! ( state. node( ) . node_type, NodeType :: Param { suffix: true } )
370+ {
371+ let terminator = remaining
372+ . iter ( )
373+ . position ( |& b| b == b'/' )
374+ // Include the '/' in the suffix.
375+ . map ( |b| b + 1 )
376+ . unwrap_or ( remaining. len ( ) ) ;
377+
378+ if let Ok ( Some ( wildcard) ) = find_wildcard ( remaining. slice_until ( terminator) )
379+ {
380+ let suffix = remaining. slice_off ( wildcard. end ) ;
381+ if matches ! ( * suffix, b"" | b"/" ) {
382+ return Err ( InsertError :: conflict ( & route, remaining, parent) ) ;
383+ }
384+ }
385+ }
255386 }
256387
257388 // Continue with the wildcard node.
258389 continue ' walk;
259390 }
260391
392+ if let Ok ( Some ( wildcard) ) = find_wildcard ( remaining) {
393+ let node = state. node ( ) ;
394+ let suffix = remaining. slice_off ( wildcard. end ) ;
395+
396+ // If we are inserting a suffix and there is a static prefix that already leads to this
397+ // route parameter, we have a prefix-suffix conflict.
398+ if !matches ! ( * suffix, b"" | b"/" ) {
399+ for child in & node. children {
400+ if matches ! ( child. node_type, NodeType :: Static )
401+ && child. wild_child_in_segment ( )
402+ {
403+ return Err ( InsertError :: conflict ( & route, remaining, child) ) ;
404+ }
405+ }
406+ }
407+ }
408+
261409 // Otherwise, create a new node for the wildcard and insert the route.
262- let last = node . insert_route ( remaining, val) ?;
410+ let last = state . node_mut ( ) . insert_route ( remaining, val) ?;
263411 last. remapping = remapping;
264412 return Ok ( ( ) ) ;
265413 }
266414 }
267415
416+ /// Returns `true` if there is a wildcard parameter node within the current route segment,
417+ /// i.e. before a trailing slash.
418+ fn wild_child_in_segment ( & self ) -> bool {
419+ if self . prefix . contains ( & b'/' ) {
420+ return false ;
421+ }
422+
423+ if self . wild_child {
424+ return true ;
425+ }
426+
427+ self . children . iter ( ) . any ( Node :: wild_child_in_segment)
428+ }
429+
268430 // Insert a route at this node.
269431 //
270432 // If the route starts with a wildcard, a child node will be created for the parameter
0 commit comments