radix_router/
tree.rs

1use router::{Param, Params};
2// use std::fmt::Debug;
3use std::mem;
4use std::str;
5
6fn min(a: usize, b: usize) -> usize {
7    if a <= b {
8        return a;
9    }
10    b
11}
12
13fn count_params(path: &[u8]) -> u8 {
14    let mut n = 0;
15    for &c in path {
16        if c != b':' && c != b'*' {
17            continue;
18        }
19        n += 1;
20    }
21    if n > 255 {
22        return 255;
23    }
24    n as u8
25}
26
27#[derive(PartialEq, Clone, Debug, PartialOrd)]
28pub enum NodeType {
29    Static,
30    Root,
31    Param,
32    CatchAll,
33}
34
35#[derive(Debug, Clone)]
36pub struct Node<T> {
37    path: Vec<u8>,
38    wild_child: bool,
39    n_type: NodeType,
40    max_params: u8,
41    indices: Vec<u8>,
42    children: Vec<Box<Node<T>>>,
43    handle: Option<T>,
44    priority: u32,
45}
46
47impl<T> Node<T> {
48    pub fn new() -> Node<T> {
49        Node {
50            path: Vec::new(),
51            wild_child: false,
52            n_type: NodeType::Static,
53            max_params: 0,
54            indices: Vec::new(),
55            children: Vec::new(),
56            handle: None,
57            priority: 0,
58        }
59    }
60
61    /// increments priority of the given child and reorders if necessary
62    fn increment_child_prio(&mut self, pos: usize) -> usize {
63        self.children[pos].priority += 1;
64        let prio = self.children[pos].priority;
65        // adjust position (move to front)
66        let mut new_pos = pos;
67
68        while new_pos > 0 && self.children[new_pos - 1].priority < prio {
69            // swap node positions
70            self.children.swap(new_pos - 1, new_pos);
71            new_pos -= 1;
72        }
73
74        // build new index char string
75        if new_pos != pos {
76            self.indices = [
77                &self.indices[..new_pos],    // unchanged prefix, might be empty
78                &self.indices[pos..pos + 1], // the index char we move
79                &self.indices[new_pos..pos], // rest without char at 'pos'
80                &self.indices[pos + 1..],    // rest without char at 'pos'
81            ].concat();
82        }
83
84        new_pos
85    }
86
87    /// addRoute adds a node with the given handle to the path.
88    /// Not concurrency-safe!
89    pub fn add_route(&mut self, path: &str, handle: T) {
90        let full_path = path.clone();
91        let path = path.as_ref();
92        self.priority += 1;
93        let num_params = count_params(path);
94
95        // non-empty tree
96        if self.path.len() > 0 || self.children.len() > 0 {
97            self.add_route_loop(num_params, path, full_path, handle);
98        } else {
99            // Empty tree
100            self.insert_child(num_params, path, full_path, handle);
101            self.n_type = NodeType::Root;
102        }
103    }
104
105    fn add_route_loop(&mut self, num_params: u8, mut path: &[u8], full_path: &str, handle: T) {
106        // Update max_params of the current node
107        if num_params > self.max_params {
108            self.max_params = num_params;
109        }
110
111        // Find the longest common prefix.
112        // This also implies that the common prefix contains no ':' or '*'
113        // since the existing key can't contain those chars.
114        let mut i = 0;
115        let max = min(path.len(), self.path.len());
116
117        while i < max && path[i] == self.path[i] {
118            i += 1;
119        }
120
121        // Split edge
122        if i < self.path.len() {
123            let mut child = Node {
124                path: self.path[i..].to_vec(),
125                wild_child: self.wild_child,
126                n_type: NodeType::Static,
127                indices: self.indices.clone(),
128                children: Vec::new(),
129                handle: self.handle.take(),
130                priority: self.priority - 1,
131
132                max_params: 0,
133            };
134
135            mem::swap(&mut self.children, &mut child.children);
136
137            // Update max_params (max of all children)
138            for c in &child.children {
139                if c.max_params > child.max_params {
140                    child.max_params = c.max_params;
141                }
142            }
143
144            self.children = vec![Box::new(child)];
145            self.indices = vec![self.path[i]];
146            self.path = path[..i].to_vec();
147            self.wild_child = false;
148        }
149
150        // Make new node a child of this node
151        if i < path.len() {
152            path = &path[i..];
153
154            if self.wild_child {
155                // *n = * {n}.children[0].clone();
156                return self.children[0].is_wild_child(num_params, path, full_path, handle);
157            }
158
159            let c = path[0];
160
161            // slash after param
162            if self.n_type == NodeType::Param && c == b'/' && self.children.len() == 1 {
163                self.children[0].priority += 1;
164                return self.children[0].add_route_loop(num_params, path, full_path, handle);
165            }
166
167            // Check if a child with the next path byte exists
168            for mut i in 0..self.indices.len() {
169                if c == self.indices[i] {
170                    i = self.increment_child_prio(i);
171                    return self.children[i].add_route_loop(num_params, path, full_path, handle);
172                }
173            }
174
175            // Otherwise insert it
176            if c != b':' && c != b'*' {
177                self.indices.push(c);
178
179                let len = self.indices.len();
180
181                let child: Box<Node<T>> = Box::new(Node {
182                    path: Vec::new(),
183
184                    wild_child: false,
185
186                    n_type: NodeType::Static,
187
188                    max_params: num_params,
189
190                    indices: Vec::new(),
191
192                    children: Vec::new(),
193
194                    handle: None,
195
196                    priority: 0,
197                });
198
199                self.children.push(child);
200
201                let i = self.increment_child_prio(len - 1);
202
203                return self.children[i].insert_child(num_params, path, full_path, handle);
204            }
205
206            return self.insert_child(num_params, path, full_path, handle);
207        } else if i == path.len() {
208            // Make node a (in-path) leaf
209            if self.handle.is_some() {
210                panic!("a handle is already registered for path '{}'", full_path);
211            }
212
213            self.handle = Some(handle);
214        }
215
216        return;
217    }
218
219    fn is_wild_child(&mut self, mut num_params: u8, path: &[u8], full_path: &str, handle: T) {
220        self.priority += 1;
221
222        // Update maxParams of the child node
223
224        if num_params > self.max_params {
225            self.max_params = num_params;
226        }
227
228        num_params -= 1;
229
230        // Check if the wildcard matches
231
232        if path.len() >= self.path.len()
233            && self.path == &path[..self.path.len()]
234            // Check for longer wildcard, e.g. :name and :names
235            && (self.path.len() >= path.len() || path[self.path.len()] == b'/')
236        {
237            self.add_route_loop(num_params, path, full_path, handle);
238        } else {
239            // Wildcard conflict
240            let path_seg = if self.n_type == NodeType::CatchAll {
241                str::from_utf8(path).unwrap()
242            } else {
243                str::from_utf8(path)
244                    .unwrap()
245                    .splitn(2, '/')
246                    .into_iter()
247                    .next()
248                    .unwrap()
249            };
250
251            let prefix = [
252                &full_path[..full_path.find(path_seg).unwrap()],
253                str::from_utf8(&self.path).unwrap(),
254            ].concat();
255
256            panic!("'{}' in new path '{}' conflicts with existing wildcard '{}' in existing prefix '{}'", path_seg, full_path, str::from_utf8(&self.path).unwrap(), prefix);
257        }
258    }
259
260    fn insert_child(&mut self, num_params: u8, path: &[u8], full_path: &str, handle: T) {
261        self.insert_child_loop(0, 0, num_params, path, full_path, handle);
262    }
263
264    fn insert_child_loop(
265        &mut self,
266        mut offset: usize,
267        mut i: usize,
268        mut num_params: u8,
269        path: &[u8],
270        full_path: &str,
271        handle: T,
272    ) {
273        if num_params > 0 {
274            let max = path.len();
275            let c = path[i];
276
277            // find prefix until first wildcard (beginning with ':'' or '*'')
278            if c != b':' && c != b'*' {
279                return self.insert_child_loop(offset, i + 1, num_params, path, full_path, handle);
280            }
281
282            // find wildcard end (either '/' or path end)
283            let mut end = i + 1;
284            while end < max && path[end] != b'/' {
285                match path[end] {
286                    // the wildcard name must not contain ':' and '*'
287                    b':' | b'*' => panic!(
288                        "only one wildcard per path segment is allowed, has: '{}' in path '{}'",
289                        str::from_utf8(&path[i..]).unwrap(),
290                        full_path
291                    ),
292                    _ => end += 1,
293                }
294            }
295
296            // println!("self path: {}", str::from_utf8(&self.path).unwrap());
297            // println!("temp path: {}", str::from_utf8(path).unwrap());
298            // println!("self {:?}", self.children[0]);
299            // println!("self {:?}", self.children.len());
300
301            // check if this Node existing children which would be
302            // unreachable if we insert the wildcard here
303            if self.children.len() > 0 {
304                panic!(
305                    "wildcard route '{}' conflicts with existing children in path '{}'",
306                    str::from_utf8(&path[i..end]).unwrap(),
307                    full_path
308                )
309            }
310
311            // check if the wildcard has a name
312            if end - i < 2 {
313                panic!(
314                    "wildcards must be named with a non-empty name in path '{}'",
315                    full_path
316                );
317            }
318
319            if c == b':' {
320                // Param
321                // split path at the beginning of the wildcard
322                if i > 0 {
323                    self.path = path[offset..i].to_vec();
324                    offset = i;
325                }
326
327                let child = Box::new(Node {
328                    path: Vec::new(),
329                    wild_child: false,
330                    n_type: NodeType::Param,
331                    max_params: num_params,
332                    indices: Vec::new(),
333                    children: Vec::new(),
334                    handle: None,
335                    priority: 0,
336                });
337
338                self.children = vec![child];
339                self.wild_child = true;
340
341                self.children[0].priority += 1;
342                num_params -= 1;
343
344                if end < max {
345                    self.children[0].path = path[offset..end].to_vec();
346                    offset = end;
347
348                    let child: Box<Node<T>> = Box::new(Node {
349                        path: Vec::new(),
350                        wild_child: false,
351                        n_type: NodeType::Static,
352                        max_params: num_params,
353                        indices: Vec::new(),
354                        children: Vec::new(),
355                        handle: None,
356                        priority: 1,
357                    });
358
359                    self.children[0].children.push(child);
360                    self.children[0].children[0].insert_child_loop(
361                        offset,
362                        i + 1,
363                        num_params,
364                        path,
365                        full_path,
366                        handle,
367                    );
368                } else {
369                    self.children[0].insert_child_loop(
370                        offset,
371                        i + 1,
372                        num_params,
373                        path,
374                        full_path,
375                        handle,
376                    );
377                }
378            } else {
379                // CatchAll
380                if end != max || num_params > 1 {
381                    panic!(
382                        "catch-all routes are only allowed at the end of the path in path '{}'",
383                        full_path
384                    );
385                }
386
387                if self.path.len() > 0 && self.path[self.path.len() - 1] == b'/' {
388                    panic!(
389                        "catch-all conflicts with existing handle for the path segment root in path '{}'", 
390                        full_path
391                    );
392                }
393
394                // currently fixed width 1 for '/'
395                i -= 1;
396                if path[i] != b'/' {
397                    panic!("no / before catch-all in path '{}'", full_path);
398                }
399
400                self.path = path[offset..i].to_vec();
401
402                // first node: catchAll node with empty path
403                let child = Box::new(Node {
404                    path: Vec::new(),
405                    wild_child: true,
406                    n_type: NodeType::CatchAll,
407                    max_params: 1,
408                    indices: Vec::new(),
409                    children: Vec::new(),
410                    handle: None,
411                    priority: 0,
412                });
413
414                self.children = vec![child];
415
416                self.indices = vec![path[i]];
417
418                self.children[0].priority += 1;
419
420                // second node: node holding the variable
421                let child: Box<Node<T>> = Box::new(Node {
422                    path: path[i..].to_vec(),
423                    wild_child: false,
424                    n_type: NodeType::CatchAll,
425                    max_params: 1,
426                    indices: Vec::new(),
427                    children: Vec::new(),
428                    handle: Some(handle),
429                    priority: 1,
430                });
431
432                self.children[0].children.push(child);
433
434                return;
435            }
436        } else {
437            // insert remaining path part and handle to the leaf
438            self.path = path[offset..].to_vec();
439            self.handle = Some(handle);
440        }
441    }
442
443    /// Returns the handle registered with the given path (key). The values of
444    /// wildcards are saved to a map.
445    /// If no handle can be found, a TSR (trailing slash redirect) recommendation is
446    /// made if a handle exists with an extra (without the) trailing slash for the
447    /// given path.
448    pub fn get_value(&self, path: &str) -> (Option<&T>, Params, bool) {
449        // let mut handle = None;
450        self.get_value_loop(path.as_ref(), Params::new())
451    }
452
453    /// outer loop for walking the tree
454    fn get_value_loop(&self, mut path: &[u8], p: Params) -> (Option<&T>, Params, bool) {
455        if path.len() > self.path.len() {
456            if self.path == &path[..self.path.len()] {
457                path = &path[self.path.len()..];
458                // If this node does not have a wildcard (param or catchAll)
459                // child,  we can just look up the next child node and continue
460                // to walk down the tree
461                if !self.wild_child {
462                    let c = path[0];
463                    for i in 0..self.indices.len() {
464                        if c == self.indices[i] {
465                            return self.children[i].get_value_loop(path, p);
466                        }
467                    }
468                    // Nothing found.
469                    // We can recommend to redirect to the same URL without a
470                    // trailing slash if a leaf exists for that path.
471                    let tsr = path == [b'/'] && self.handle.is_some();
472                    return (None, p, tsr);
473                }
474
475                // handle wildcard child
476                return self.children[0].handle_wildcard_child(path, p);
477            }
478        } else if self.path == path {
479            // We should have reached the node containing the handle.
480            // Check if this node has a handle registered.
481            if self.handle.is_some() {
482                return (self.handle.as_ref(), p, false);
483            }
484
485            if path == [b'/'] && self.wild_child && self.n_type != NodeType::Root {
486                // tsr = true;
487                return (self.handle.as_ref(), p, true);
488            }
489
490            // No handle found. Check if a handle for this path + a
491            // trailing slash exists for trailing slash recommendation
492            for i in 0..self.indices.len() {
493                if self.indices[i] == b'/' {
494                    let tsr = (self.path.len() == 1 && self.children[i].handle.is_some())
495                        || (self.children[i].n_type == NodeType::CatchAll
496                            && self.children[i].children[0].handle.is_some());
497                    return (self.handle.as_ref(), p, tsr);
498                }
499            }
500
501            return (self.handle.as_ref(), p, false);
502        }
503
504        // Nothing found. We can recommend to redirect to the same URL with an
505        // extra trailing slash if a leaf exists for that path
506        let tsr = (path == [b'/'])
507            || (self.path.len() == path.len() + 1
508                && self.path[path.len()] == b'/'
509                && path == &self.path[..self.path.len() - 1]
510                && self.handle.is_some());
511
512        return (None, p, tsr);
513    }
514
515    fn handle_wildcard_child(&self, mut path: &[u8], mut p: Params) -> (Option<&T>, Params, bool) {
516        match self.n_type {
517            NodeType::Param => {
518                // find param end (either '/' or path end)
519                let mut end = 0;
520                while end < path.len() && path[end] != b'/' {
521                    end += 1;
522                }
523
524                // save param value
525                if p.is_empty() {
526                    // lazy allocation
527                    p = Params(Vec::with_capacity(self.max_params as usize));
528                }
529
530                p.push(Param {
531                    key: String::from_utf8(self.path[1..].to_vec()).unwrap(),
532                    value: String::from_utf8(path[..end].to_vec()).unwrap(),
533                });
534
535                // we need to go deeper!
536                if end < path.len() {
537                    if self.children.len() > 0 {
538                        path = &path[end..];
539
540                        return self.children[0].get_value_loop(path, p);
541                    }
542
543                    // ... but we can't
544                    let tsr = path.len() == end + 1;
545                    return (None, p, tsr);
546                }
547
548                if self.handle.is_some() {
549                    return (self.handle.as_ref(), p, false);
550                } else if self.children.len() == 1 {
551                    // No handle found. Check if a handle for this path + a
552                    // trailing slash exists for TSR recommendation
553                    let tsr = self.children[0].path == &[b'/'] && self.children[0].handle.is_some();
554                    return (None, p, tsr);
555                }
556
557                return (None, p, false);
558            }
559            NodeType::CatchAll => {
560                // save param value
561                if p.is_empty() {
562                    // lazy allocation
563                    p = Params(Vec::with_capacity(self.max_params as usize));
564                }
565
566                p.push(Param {
567                    key: String::from_utf8(self.path[2..].to_vec()).unwrap(),
568                    value: String::from_utf8(path.to_vec()).unwrap(),
569                });
570
571                return (self.handle.as_ref(), p, false);
572            }
573            _ => panic!("invalid node type"),
574        }
575    }
576
577    /// Makes a case-insensitive lookup of the given path and tries to find a handler.
578    /// It can optionally also fix trailing slashes.
579    /// It returns the case-corrected path and a bool indicating whether the lookup
580    /// was successful.
581    pub fn find_case_insensitive_path(
582        &self,
583        path: &str,
584        fix_trailing_slash: bool,
585    ) -> (String, bool) {
586        let mut ci_path = Vec::with_capacity(path.len() + 1);
587        let found = self.find_case_insensitive_path_rec(
588            path.as_bytes(),
589            path.to_ascii_lowercase().as_bytes(),
590            &mut ci_path,
591            [0; 4],
592            fix_trailing_slash,
593        );
594        (String::from_utf8(ci_path).unwrap(), found)
595    }
596
597    /// recursive case-insensitive lookup function used by n.findCaseInsensitivePath
598    fn find_case_insensitive_path_rec(
599        &self,
600        mut path: &[u8],
601        mut lo_path: &[u8],
602        ci_path: &mut Vec<u8>,
603        mut rb: [u8; 4],
604        fix_trailing_slash: bool,
605    ) -> bool {
606        // println!("{:?}", self.path);
607        // let n_path = str::from_utf8(&self.path).expect("ivalid utf8").to_lowercase();
608        // let lo_n_path = n_path.as_bytes();
609        let lo_n_path: Vec<u8> = self.path.iter().map(|u| u.to_ascii_lowercase()).collect();
610
611        if lo_path.len() >= lo_n_path.len()
612            && (lo_n_path.len() == 0 || lo_path[1..lo_n_path.len()] == lo_n_path[1..])
613        {
614            // println!("self.path = {}", str::from_utf8(&self.path).unwrap());
615            ci_path.append(&mut self.path.clone());
616
617            path = &path[self.path.len()..];
618
619            if path.len() > 0 {
620                let lo_old = lo_path.clone();
621                lo_path = &lo_path[lo_n_path.len()..];
622
623                // If this node does not have a wildcard (param or catchAll) child,
624                // we can just look up the next child node and continue to walk down
625                // the tree
626                if !self.wild_child {
627                    // skip rune bytes already processed
628                    rb = shift_n_rune_bytes(rb, lo_n_path.len());
629
630                    if rb[0] != 0 {
631                        // old rune not finished
632                        for i in 0..self.indices.len() {
633                            if self.indices[i] == rb[0] {
634                                // continue with child node
635                                return self.children[i].find_case_insensitive_path_rec(
636                                    path,
637                                    lo_path,
638                                    ci_path,
639                                    rb,
640                                    fix_trailing_slash,
641                                );
642                            }
643                        }
644                    } else {
645                        // process a new rune
646                        let mut rv = 0 as char;
647
648                        // find rune start
649                        // runes are up to 4 byte long,
650                        // -4 would definitely be another rune
651                        let mut off = 0;
652                        // println!("loold {:?}", lo_old);
653                        for j in 0..min(lo_n_path.len(), 3) {
654                            let i = lo_n_path.len() - j;
655                            if rune_start(lo_old[i]) {
656                                // read rune from cached lowercase path
657                                rv = str::from_utf8(&lo_old[i..])
658                                    .unwrap()
659                                    .chars()
660                                    .next()
661                                    .unwrap();
662                                off = j;
663                                break;
664                            }
665                        }
666                        // println!("rv = {}, off = {}", rv, off);
667                        // calculate lowercase bytes of current rune
668                        rv.encode_utf8(&mut rb);
669
670                        // skipp already processed bytes
671                        rb = shift_n_rune_bytes(rb, off);
672                        // println!("rb = {:?}", rb);
673                        for i in 0..self.indices.len() {
674                            // lowercase matches
675                            if self.indices[i] == rb[0] {
676                                // must use a recursive approach since both the
677                                // uppercase byte and the lowercase byte might exist
678                                // as an index
679                                let found = self.children[i].find_case_insensitive_path_rec(
680                                    path,
681                                    lo_path,
682                                    ci_path,
683                                    rb,
684                                    fix_trailing_slash,
685                                );
686
687                                if found {
688                                    // println!("cipah = {}", str::from_utf8(&ci_path).unwrap());
689                                    return true;
690                                }
691                                if ci_path.len() > self.children[i].path.len() {
692                                    let prev_len = ci_path.len() - self.children[i].path.len();
693                                    ci_path.truncate(prev_len);
694                                }
695
696                                break;
697                            }
698                        }
699
700                        // same for uppercase rune, if it differs
701                        let up = rv.to_ascii_uppercase();
702                        if up != rv {
703                            up.encode_utf8(&mut rb);
704                            rb = shift_n_rune_bytes(rb, off);
705
706                            for i in 0..self.indices.len() {
707                                if self.indices[i] == rb[0] {
708                                    return self.children[i].find_case_insensitive_path_rec(
709                                        path,
710                                        lo_path,
711                                        ci_path,
712                                        rb,
713                                        fix_trailing_slash,
714                                    );
715                                }
716                            }
717                        }
718                    }
719
720                    // Nothing found. We can recommend to redirect to the same URL
721				    // without a trailing slash if a leaf exists for that path
722                    return fix_trailing_slash && path == [b'/'] && self.handle.is_some();
723                }
724
725                return self.children[0].find_case_insensitive_path_rec_match(
726                    path,
727                    lo_path,
728                    ci_path,
729                    rb,
730                    fix_trailing_slash,
731                );
732            } else {
733                if self.handle.is_some() {
734                    return true;
735                }
736
737                if fix_trailing_slash {
738                    for i in 0..self.indices.len() {
739                        if self.indices[i] == b'/' {
740                            if (self.children[i].path.len() == 1
741                                && self.children[i].handle.is_some())
742                                || (self.children[i].n_type == NodeType::CatchAll
743                                    && self.children[i].children[0].handle.is_some())
744                            {
745                                ci_path.push(b'/');
746                                return true;
747                            }
748                            return false;
749                        }
750                    }
751                }
752                return false;
753            }
754        }
755
756        if fix_trailing_slash {
757            if path == [b'/'] {
758                return true;
759            }
760            if lo_path.len() + 1 == lo_n_path.len()
761                && lo_n_path[lo_path.len()] == b'/'
762                && lo_path[1..] == lo_n_path[1..lo_path.len()]
763                && self.handle.is_some()
764            {
765                ci_path.append(&mut self.path.clone());
766                return true;
767            }
768        }
769
770        false
771    }
772
773    /// recursive case-insensitive lookup function used by n.findCaseInsensitivePath
774    fn find_case_insensitive_path_rec_match(
775        &self,
776        mut path: &[u8],
777        mut lo_path: &[u8],
778        ci_path: &mut Vec<u8>,
779        rb: [u8; 4],
780        fix_trailing_slash: bool,
781    ) -> bool {
782        match self.n_type {
783            NodeType::Param => {
784                let mut k = 0;
785                while k < path.len() && path[k] != b'/' {
786                    k += 1;
787                }
788                let mut path_k = path[..k].to_vec();
789                ci_path.append(&mut path_k);
790
791                if k < path.len() {
792                    if self.children.len() > 0 {
793                        lo_path = &lo_path[k..];
794                        path = &path[k..];
795
796                        return self.children[0].find_case_insensitive_path_rec(
797                            path,
798                            lo_path,
799                            ci_path,
800                            rb,
801                            fix_trailing_slash,
802                        );
803                    }
804
805                    if fix_trailing_slash && path.len() == k + 1 {
806                        return true;
807                    }
808                    return false;
809                }
810
811                if self.handle.is_some() {
812                    return true;
813                } else if fix_trailing_slash && self.children.len() == 1 {
814                    if self.children[0].path == [b'/'] && self.children[0].handle.is_some() {
815                        ci_path.push(b'/');
816                        return true;
817                    }
818                }
819
820                return false;
821            }
822            NodeType::CatchAll => {
823                ci_path.append(&mut path.to_vec());
824                return true;
825            }
826            _ => panic!("invalid node type"),
827        }
828    }
829}
830
831fn shift_n_rune_bytes(rb: [u8; 4], n: usize) -> [u8; 4] {
832    match n {
833        0 => rb,
834        1 => [rb[1], rb[2], rb[3], 0],
835        2 => [rb[2], rb[3], 0, 0],
836        3 => [rb[3], 0, 0, 0],
837        _ => [0; 4],
838    }
839}
840
841/// This function is ported from go.
842fn rune_start(b: u8) -> bool {
843    b & 0xC0 != 0x80
844}
845
846#[cfg(test)]
847mod tests {
848    use super::*;
849    // use hyper::{Body, Request, Response};
850    use router::Params;
851    use std::panic;
852    use std::sync::Mutex;
853
854    // fn print_children() {}
855
856    struct TestRequest<'a> {
857        path: &'a str,
858        nil_handler: bool,
859        route: &'a str,
860        ps: Params,
861    }
862
863    impl<'a> TestRequest<'a> {
864        pub fn new(
865            path: &'a str,
866            nil_handler: bool,
867            route: &'a str,
868            ps: Params,
869        ) -> TestRequest<'a> {
870            TestRequest {
871                path,
872                nil_handler,
873                route,
874                ps,
875            }
876        }
877    }
878
879    type TestRequests<'a> = Vec<TestRequest<'a>>;
880
881    fn check_requests<T: Fn() -> String>(tree: &mut Node<T>, requests: TestRequests) {
882        for request in requests {
883            let (handler, ps, _) = tree.get_value(request.path);
884
885            if handler.is_none() {
886                if !request.nil_handler {
887                    panic!(
888                        "handle mismatch for route '{}': Expected non-nil handle",
889                        request.path
890                    );
891                }
892            } else if request.nil_handler {
893                panic!(
894                    "handle m ismatch for route '{}': Expected nil handle",
895                    request.path
896                );
897            } else {
898                match handler {
899                    Some(h) => {
900                        let res = h();
901                        if res != request.route {
902                            panic!(
903                                "handle mismatch for route '{}': Wrong handle ({} != {})",
904                                request.path, res, request.route
905                            );
906                        }
907                    }
908                    None => {
909                        panic!("handle not found");
910                    }
911                }
912            }
913
914            if ps != request.ps {
915                panic!("Params mismatch for route '{}'", request.path);
916            }
917        }
918    }
919
920    fn check_priorities<T: Fn() -> String>(n: &mut Node<T>) -> u32 {
921        // println!("{}", str::from_utf8(&n.path).unwrap());
922        let mut prio: u32 = 0;
923        for i in 0..n.children.len() {
924            prio += check_priorities(&mut *n.children[i]);
925        }
926
927        if n.handle.is_some() {
928            prio += 1;
929        }
930
931        if n.priority != prio {
932            panic!(
933                "priority mismatch for node '{}': is {}, should be {}",
934                str::from_utf8(&n.path).unwrap(),
935                n.priority,
936                prio
937            )
938        }
939
940        prio
941    }
942
943    fn check_max_params<T: Fn() -> String>(n: &mut Node<T>) -> u8 {
944        let mut max_params: u8 = 0;
945        for i in 0..n.children.len() {
946            let params = check_max_params(&mut *n.children[i]);
947
948            if params > max_params {
949                max_params = params;
950            }
951        }
952
953        if n.n_type > NodeType::Root && !n.wild_child {
954            max_params += 1;
955        }
956
957        if n.max_params != max_params {
958            panic!(
959                "maxParams mismatch for node '{}': is {}, should be {}",
960                str::from_utf8(&n.path).unwrap(),
961                n.max_params,
962                max_params,
963            )
964        }
965
966        max_params
967    }
968
969    fn fake_handler(val: &'static str) -> impl Fn() -> String {
970        move || val.to_string()
971    }
972
973    #[test]
974    fn test_count_params() {
975        assert_eq!(
976            2,
977            count_params("/path/:param1/static/*catch-all".as_bytes())
978        );
979        assert_eq!(255, count_params("/:param".repeat(256).as_bytes()));
980    }
981
982    #[test]
983    fn test_tree_add_and_get() {
984        let mut tree = Node::new();
985
986        let routes = vec![
987            "/hi",
988            "/contact",
989            "/co",
990            "/c",
991            "/a",
992            "/ab",
993            "/doc/",
994            "/doc/go_faq.html",
995            "/doc/go1.html",
996            "/α",
997            "/β",
998        ];
999
1000        for route in routes {
1001            tree.add_route(route, fake_handler(route));
1002        }
1003
1004        check_requests(
1005            &mut tree,
1006            vec![
1007                TestRequest::new("/a", false, "/a", Params::new()),
1008                TestRequest::new("/", true, "", Params::new()),
1009                TestRequest::new("/hi", false, "/hi", Params::new()),
1010                TestRequest::new("/contact", false, "/contact", Params::new()),
1011                TestRequest::new("/co", false, "/co", Params::new()),
1012                TestRequest::new("/con", true, "", Params::new()), // key mismatch
1013                TestRequest::new("/cona", true, "", Params::new()), // key mismatch
1014                TestRequest::new("/no", true, "", Params::new()),  // no matching child
1015                TestRequest::new("/ab", false, "/ab", Params::new()),
1016                TestRequest::new("/α", false, "/α", Params::new()),
1017                TestRequest::new("/β", false, "/β", Params::new()),
1018            ],
1019        );
1020
1021        check_priorities(&mut tree);
1022        check_max_params(&mut tree);
1023    }
1024
1025    #[test]
1026    fn test_tree_wildcard() {
1027        let mut tree = Node::new();
1028
1029        let routes = vec![
1030            "/",
1031            "/cmd/:tool/:sub",
1032            "/cmd/:tool/",
1033            "/src/*filepath",
1034            "/search/",
1035            "/search/:query",
1036            "/user_:name",
1037            "/user_:name/about",
1038            "/files/:dir/*filepath",
1039            "/doc/",
1040            "/doc/go_faq.html",
1041            "/doc/go1.html",
1042            "/info/:user/public",
1043            "/info/:user/project/:project",
1044        ];
1045
1046        for route in routes {
1047            tree.add_route(route, fake_handler(route));
1048        }
1049
1050        check_requests(
1051            &mut tree,
1052            vec![
1053                TestRequest::new("/", false, "/", Params::new()),
1054                TestRequest::new(
1055                    "/cmd/test/",
1056                    false,
1057                    "/cmd/:tool/",
1058                    Params(vec![Param::new("tool", "test")]),
1059                ),
1060                TestRequest::new(
1061                    "/cmd/test",
1062                    true,
1063                    "",
1064                    Params(vec![Param::new("tool", "test")]),
1065                ),
1066                TestRequest::new(
1067                    "/cmd/test/3",
1068                    false,
1069                    "/cmd/:tool/:sub",
1070                    Params(vec![Param::new("tool", "test"), Param::new("sub", "3")]),
1071                ),
1072                TestRequest::new(
1073                    "/src/",
1074                    false,
1075                    "/src/*filepath",
1076                    Params(vec![Param::new("filepath", "/")]),
1077                ),
1078                TestRequest::new(
1079                    "/src/some/file.png",
1080                    false,
1081                    "/src/*filepath",
1082                    Params(vec![Param::new("filepath", "/some/file.png")]),
1083                ),
1084                TestRequest::new("/search/", false, "/search/", Params::new()),
1085                TestRequest::new(
1086                    "/search/someth!ng+in+ünìcodé",
1087                    false,
1088                    "/search/:query",
1089                    Params(vec![Param::new("query", "someth!ng+in+ünìcodé")]),
1090                ),
1091                TestRequest::new(
1092                    "/search/someth!ng+in+ünìcodé/",
1093                    true,
1094                    "",
1095                    Params(vec![Param::new("query", "someth!ng+in+ünìcodé")]),
1096                ),
1097                TestRequest::new(
1098                    "/user_gopher",
1099                    false,
1100                    "/user_:name",
1101                    Params(vec![Param::new("name", "gopher")]),
1102                ),
1103                TestRequest::new(
1104                    "/user_gopher/about",
1105                    false,
1106                    "/user_:name/about",
1107                    Params(vec![Param::new("name", "gopher")]),
1108                ),
1109                TestRequest::new(
1110                    "/files/js/inc/framework.js",
1111                    false,
1112                    "/files/:dir/*filepath",
1113                    Params(vec![
1114                        Param::new("dir", "js"),
1115                        Param::new("filepath", "/inc/framework.js"),
1116                    ]),
1117                ),
1118                TestRequest::new(
1119                    "/info/gordon/public",
1120                    false,
1121                    "/info/:user/public",
1122                    Params(vec![Param::new("user", "gordon")]),
1123                ),
1124                TestRequest::new(
1125                    "/info/gordon/project/go",
1126                    false,
1127                    "/info/:user/project/:project",
1128                    Params(vec![
1129                        Param::new("user", "gordon"),
1130                        Param::new("project", "go"),
1131                    ]),
1132                ),
1133            ],
1134        );
1135
1136        check_priorities(&mut tree);
1137        check_max_params(&mut tree);
1138    }
1139
1140    // path: &str, conflict: bool
1141    type TestRoute = (&'static str, bool);
1142
1143    fn test_routes(routes: Vec<TestRoute>) {
1144        let tree = Mutex::new(Node::new());
1145        // let mut tree = Node::new();
1146
1147        for route in routes {
1148            let recv = panic::catch_unwind(|| {
1149                let mut guard = match tree.lock() {
1150                    Ok(guard) => guard,
1151                    Err(poisoned) => poisoned.into_inner(),
1152                };
1153                guard.add_route(route.0, ());
1154            });
1155
1156            if route.1 {
1157                if recv.is_ok() {
1158                    panic!("no panic for conflicting route '{}'", route.0);
1159                }
1160            } else if recv.is_err() {
1161                panic!("unexpected panic for route '{}': {:?}", route.0, recv);
1162            }
1163        }
1164    }
1165
1166    #[test]
1167    fn test_tree_wildcard_conflict() {
1168        let routes = vec![
1169            ("/cmd/:tool/:sub", false),
1170            ("/cmd/vet", true),
1171            ("/src/*filepath", false),
1172            ("/src/*filepathx", true),
1173            ("/src/", true),
1174            ("/src1/", false),
1175            ("/src1/*filepath", true),
1176            ("/src2*filepath", true),
1177            ("/search/:query", false),
1178            ("/search/invalid", true),
1179            ("/user_:name", false),
1180            ("/user_x", true),
1181            // ("/user_:name", false),
1182            ("/user_:name", true), // Rust is different. Nil handler was not allowed. Or maybe it is a feature?
1183            ("/id:id", false),
1184            ("/id/:id", true),
1185        ];
1186        test_routes(routes);
1187    }
1188
1189    #[test]
1190    fn test_tree_child_conflict() {
1191        let routes = vec![
1192            ("/cmd/vet", false),
1193            ("/cmd/:tool/:sub", true),
1194            ("/src/AUTHORS", false),
1195            ("/src/*filepath", true),
1196            ("/user_x", false),
1197            ("/user_:name", true),
1198            ("/id/:id", false),
1199            ("/id:id", true),
1200            ("/:id", true),
1201            ("/*filepath", true),
1202        ];
1203
1204        test_routes(routes);
1205    }
1206
1207    #[test]
1208    fn test_tree_duplicate_path() {
1209        let tree = Mutex::new(Node::new());
1210
1211        let routes = vec![
1212            "/",
1213            "/doc/",
1214            "/src/*filepath",
1215            "/search/:query",
1216            "/user_:name",
1217        ];
1218
1219        for route in routes {
1220            let mut recv = panic::catch_unwind(|| {
1221                let mut guard = match tree.lock() {
1222                    Ok(guard) => guard,
1223                    Err(poisoned) => poisoned.into_inner(),
1224                };
1225                guard.add_route(route, fake_handler(route));
1226            });
1227
1228            if recv.is_err() {
1229                panic!("panic inserting route '{}': {:?}", route, recv);
1230            }
1231
1232            recv = panic::catch_unwind(|| {
1233                let mut guard = match tree.lock() {
1234                    Ok(guard) => guard,
1235                    Err(poisoned) => poisoned.into_inner(),
1236                };
1237                guard.add_route(route, fake_handler(route));
1238            });
1239
1240            if recv.is_ok() {
1241                panic!("no panic while inserting duplicate route '{}'", route);
1242            }
1243        }
1244
1245        check_requests(
1246            &mut tree.lock().unwrap_or_else(|poisoned| poisoned.into_inner()),
1247            vec![
1248                TestRequest::new("/", false, "/", Params::new()),
1249                TestRequest::new("/doc/", false, "/doc/", Params::new()),
1250                TestRequest::new(
1251                    "/src/some/file.png",
1252                    false,
1253                    "/src/*filepath",
1254                    Params(vec![Param::new("filepath", "/some/file.png")]),
1255                ),
1256                TestRequest::new(
1257                    "/search/someth!ng+in+ünìcodé",
1258                    false,
1259                    "/search/:query",
1260                    Params(vec![Param::new("query", "someth!ng+in+ünìcodé")]),
1261                ),
1262                TestRequest::new(
1263                    "/user_gopher",
1264                    false,
1265                    "/user_:name",
1266                    Params(vec![Param::new("name", "gopher")]),
1267                ),
1268            ],
1269        );
1270    }
1271
1272    #[test]
1273    fn test_empty_wildcard_name() {
1274        let tree = Mutex::new(Node::new());
1275        let routes = vec!["/user:", "/user:/", "/cmd/:/", "/src/*"];
1276
1277        for route in routes {
1278            let mut recv = panic::catch_unwind(|| {
1279                let mut guard = match tree.lock() {
1280                    Ok(guard) => guard,
1281                    Err(poisoned) => poisoned.into_inner(),
1282                };
1283                guard.add_route(route, fake_handler(route));
1284            });
1285
1286            if recv.is_ok() {
1287                panic!(
1288                    "no panic while inserting route with empty wildcard name '{}",
1289                    route
1290                );
1291            }
1292        }
1293    }
1294
1295    #[test]
1296    fn test_tree_catch_all_conflict() {
1297        let routes = vec![
1298            ("/src/*filepath/x", true),
1299            ("/src2/", false),
1300            ("/src2/*filepath/x", true),
1301        ];
1302
1303        test_routes(routes);
1304    }
1305
1306    #[test]
1307    fn test_tree_catch_all_conflict_root() {
1308        let routes = vec![("/", false), ("/*filepath", true)];
1309
1310        test_routes(routes);
1311    }
1312
1313    #[test]
1314    fn test_tree_double_wildcard() {
1315        let panic_msg = "only one wildcard per path segment is allowed";
1316        let routes = vec!["/:foo:bar", "/:foo:bar/", "/:foo*bar"];
1317
1318        for route in routes {
1319            let tree = Mutex::new(Node::new());
1320            let mut recv = panic::catch_unwind(|| {
1321                let mut guard = match tree.lock() {
1322                    Ok(guard) => guard,
1323                    Err(poisoned) => poisoned.into_inner(),
1324                };
1325                guard.add_route(route, fake_handler(route));
1326            });
1327
1328            // [TODO] Not strict enough
1329            if recv.is_ok() {
1330                panic!(panic_msg);
1331            }
1332        }
1333    }
1334
1335    #[test]
1336    fn test_tree_trailing_slash_redirect() {
1337        let tree = Mutex::new(Node::new());
1338        let routes = vec![
1339            "/hi",
1340            "/b/",
1341            "/search/:query",
1342            "/cmd/:tool/",
1343            "/src/*filepath",
1344            "/x",
1345            "/x/y",
1346            "/y/",
1347            "/y/z",
1348            "/0/:id",
1349            "/0/:id/1",
1350            "/1/:id/",
1351            "/1/:id/2",
1352            "/aa",
1353            "/a/",
1354            "/admin",
1355            "/admin/:category",
1356            "/admin/:category/:page",
1357            "/doc",
1358            "/doc/go_faq.html",
1359            "/doc/go1.html",
1360            "/no/a",
1361            "/no/b",
1362            "/api/hello/:name",
1363        ];
1364
1365        for route in routes {
1366            let mut recv = panic::catch_unwind(|| {
1367                let mut guard = match tree.lock() {
1368                    Ok(guard) => guard,
1369                    Err(poisoned) => poisoned.into_inner(),
1370                };
1371                guard.add_route(route, fake_handler(route));
1372            });
1373
1374            if recv.is_err() {
1375                panic!("panic inserting route '{}': {:?}", route, recv);
1376            }
1377        }
1378
1379        let tsr_routes = vec![
1380            "/hi/",
1381            "/b",
1382            "/search/gopher/",
1383            "/cmd/vet",
1384            "/src",
1385            "/x/",
1386            "/y",
1387            "/0/go/",
1388            "/1/go",
1389            "/a",
1390            "/admin/",
1391            "/admin/config/",
1392            "/admin/config/permissions/",
1393            "/doc/",
1394        ];
1395
1396        for route in tsr_routes {
1397            let mut guard = match tree.lock() {
1398                Ok(guard) => guard,
1399                Err(poisoned) => poisoned.into_inner(),
1400            };
1401            let (handler, _, tsr) = guard.get_value(route);
1402
1403            if handler.is_some() {
1404                panic!("non-nil handler for TSR route '{}'", route);
1405            } else if !tsr {
1406                panic!("expected TSR recommendation for route '{}'", route);
1407            }
1408        }
1409
1410        let no_tsr_routes = vec!["/", "/no", "/no/", "/_", "/_/", "/api/world/abc"];
1411
1412        for route in no_tsr_routes {
1413            let mut guard = match tree.lock() {
1414                Ok(guard) => guard,
1415                Err(poisoned) => poisoned.into_inner(),
1416            };
1417            let (handler, _, tsr) = guard.get_value(route);
1418
1419            if handler.is_some() {
1420                panic!("non-nil handler for TSR route '{}'", route);
1421            } else if tsr {
1422                panic!("expected TSR recommendation for route '{}'", route);
1423            }
1424        }
1425    }
1426
1427    #[test]
1428    fn test_tree_root_trailing_slash_redirect() {
1429        let tree = Mutex::new(Node::new());
1430
1431        let recv = panic::catch_unwind(|| {
1432            let mut guard = match tree.lock() {
1433                Ok(guard) => guard,
1434                Err(poisoned) => poisoned.into_inner(),
1435            };
1436            guard.add_route("/:test", fake_handler("/:test"));
1437        });
1438
1439        if recv.is_err() {
1440            panic!("panic inserting test route: {:?}", recv);
1441        }
1442
1443        let guard = match tree.lock() {
1444            Ok(guard) => guard,
1445            Err(poisoned) => poisoned.into_inner(),
1446        };
1447        let (handler, _, tsr) = guard.get_value("/");
1448
1449        if handler.is_some() {
1450            panic!("non-nil handler");
1451        } else if tsr {
1452            panic!("expected no TSR recommendation");
1453        }
1454    }
1455
1456    #[test]
1457    fn test_tree_find_case_insensitive_path() {
1458        // let tree = Mutex::new(Node::new());
1459        let mut tree = Node::new();
1460
1461        let routes = vec![
1462            "/hi",
1463            "/b/",
1464            "/ABC/",
1465            "/search/:query",
1466            "/cmd/:tool/",
1467            "/src/*filepath",
1468            "/x",
1469            "/x/y",
1470            "/y/",
1471            "/y/z",
1472            "/0/:id",
1473            "/0/:id/1",
1474            "/1/:id/",
1475            "/1/:id/2",
1476            "/aa",
1477            "/a/",
1478            "/doc",
1479            "/doc/go_faq.html",
1480            "/doc/go1.html",
1481            "/doc/go/away",
1482            "/no/a",
1483            "/no/b",
1484            "/Π",
1485            "/u/apfêl/",
1486            "/u/äpfêl/",
1487            "/u/öpfêl",
1488            "/v/Äpfêl/",
1489            "/v/Öpfêl",
1490            "/w/♬",   // 3 byte
1491            "/w/♭/",  // 3 byte, last byte differs
1492            "/w/𠜎",  // 4 byte
1493            "/w/𠜏/", // 4 byte
1494        ];
1495
1496        for route in &routes {
1497            // let mut recv = panic::catch_unwind(|| {
1498            //     let mut guard = match tree.lock() {
1499            //         Ok(guard) => guard,
1500            //         Err(poisoned) => poisoned.into_inner(),
1501            //     };
1502            //     guard.add_route(route, fake_handler(route));
1503            // });
1504
1505            // if recv.is_err() {
1506            //     panic!("panic inserting route '{}': {:?}", route, recv);
1507            // }
1508            tree.add_route(route, fake_handler(route));
1509        }
1510
1511        for route in &routes {
1512            // let mut guard = match tree.lock() {
1513            //     Ok(guard) => guard,
1514            //     Err(poisoned) => poisoned.into_inner(),
1515            // };
1516            // let (out, found) = guard.find_case_insensitive_path(route, false);
1517            let (out, found) = tree.find_case_insensitive_path(route, false);
1518            // println!("{},{}", str::from_utf8(&out).unwrap(), found);
1519            if !found {
1520                panic!("Route '{}' not found!", route);
1521            // println!("Route '{}' not found!", route);
1522            } else if out != *route {
1523                panic!("Wrong result for route '{}': {}", route, out);
1524            }
1525        }
1526    }
1527}