#radix #tree #path #router

path-tree

path-tree is a lightweight high performance HTTP request router for Rust

31 releases (7 breaking)

0.7.1 Oct 30, 2022
0.6.0 Sep 27, 2022
0.4.0 Jul 15, 2022
0.2.2 Oct 24, 2021
0.1.4 Mar 17, 2019

#51 in HTTP server

Download history 331/week @ 2022-10-13 446/week @ 2022-10-20 497/week @ 2022-10-27 581/week @ 2022-11-03 558/week @ 2022-11-10 484/week @ 2022-11-17 421/week @ 2022-11-24 461/week @ 2022-12-01 568/week @ 2022-12-08 392/week @ 2022-12-15 338/week @ 2022-12-22 468/week @ 2022-12-29 906/week @ 2023-01-05 1061/week @ 2023-01-12 1619/week @ 2023-01-19 975/week @ 2023-01-26

4,641 downloads per month
Used in 15 crates (11 directly)

MIT/Apache

48KB
756 lines

path-tree

A lightweight high performance HTTP request router for Rust

Parameters Syntax

Pattern Kind Description
:name Normal Matches a path piece, excludes /
:name? Optional Matches an optional path piece, excludes /
/:name?/ /:name? OptionalSegment Matches an optional path segment, excludes /, prefix or suffix should be /
+ :name+ OneOrMore Matches a path piece, includes /
* :name* ZeroOrMore Matches an optional path piece, includes /
/*/ /* /:name*/ /:name* ZeroOrMoreSegment Matches zero or more path segments, prefix or suffix should be /

Supports

Case Parameters
:a:b a b
:a:b? a b
:a-:b :a.:b :a~:b a b
:a_a-:b_b a_a b_b
:a\\: :a\\_ a
:a\\::b :a\\_:b a b
:a* a
* *1
*.* *1 *2
:a+ a
+ +1
+.+ +1 +2
/*/abc/+/def/g *1 +2

Examples

use path_tree::PathTree;

/*
/ •0
├── api/
│   └── + •13
├── login •1
├── public/
│   └── ** •7
├── s
│   ├── ettings •3
│   │   └── /
│   │       └── : •4
│   └── ignup •2
└── : •5
    └── /
        └── : •6
            └── /
                ├── actions/
                │   └── :
                │       └── \:
                │           └── : •10
                ├── releases/download/
                │   └── :
                │       └── /
                │           └── :
                │               └── .
                │                   └── : •8
                ├── tags/
                │   └── :
                │       └── -
                │           └── :
                │               └── -
                │                   └── : •9
                ├── : •11
                └── ** •12
*/
let mut tree = PathTree::new();

tree.insert("/", 0);
tree.insert("/login", 1);
tree.insert("/signup", 2);
tree.insert("/settings", 3);
tree.insert("/settings/:page", 4);
tree.insert("/:user", 5);
tree.insert("/:user/:repo", 6);
tree.insert("/public/:any*", 7);
tree.insert("/:org/:repo/releases/download/:tag/:filename.:ext", 8);
tree.insert("/:org/:repo/tags/:day-:month-:year", 9);
tree.insert("/:org/:repo/actions/:name\\::verb", 10);
tree.insert("/:org/:repo/:page", 11);
tree.insert("/:org/:repo/*", 12);
tree.insert("/api/+", 13);

let (h, p) = tree.find("/").unwrap();
assert_eq!(h, &0);
assert_eq!(p.params(), vec![]);

let (h, p) = tree.find("/login").unwrap();
assert_eq!(h, &1);
assert_eq!(p.params(), vec![]);

let (h, p) = tree.find("/settings/admin").unwrap();
assert_eq!(h, &4);
assert_eq!(p.params(), vec![("page", "admin")]);

let (h, p) = tree.find("/viz-rs").unwrap();
assert_eq!(h, &5);
assert_eq!(p.params(), vec![("user", "viz-rs")]);

let (h, p) = tree.find("/viz-rs/path-tree").unwrap();
assert_eq!(h, &6);
assert_eq!(p.params(), vec![("user", "viz-rs"), ("repo", "path-tree")]);

let (h, p) = tree.find("/rust-lang/rust-analyzer/releases/download/2022-09-12/rust-analyzer-aarch64-apple-darwin.gz").unwrap();
assert_eq!(h, &8);
assert_eq!(
    p.params(),
    vec![
        ("org", "rust-lang"),
        ("repo", "rust-analyzer"),
        ("tag", "2022-09-12"),
        ("filename", "rust-analyzer-aarch64-apple-darwin"),
        ("ext", "gz")
    ]
);

let (h, p) = tree.find("/rust-lang/rust-analyzer/tags/2022-09-12").unwrap();
assert_eq!(h, &9);
assert_eq!(
    p.params(),
    vec![
        ("org", "rust-lang"),
        ("repo", "rust-analyzer"),
        ("day", "2022"),
        ("month", "09"),
        ("year", "12")
    ]
);

let (h, p) = tree.find("/rust-lang/rust-analyzer/actions/ci:bench").unwrap();
assert_eq!(h, &10);
assert_eq!(
    p.params(),
    vec![
        ("org", "rust-lang"),
        ("repo", "rust-analyzer"),
        ("name", "ci"),
        ("verb", "bench"),
    ]
);

let (h, p) = tree.find("/rust-lang/rust-analyzer/stargazers").unwrap();
assert_eq!(h, &11);
assert_eq!(p.params(), vec![("org", "rust-lang"), ("repo", "rust-analyzer"), ("page", "stargazers")]);

let (h, p) = tree.find("/rust-lang/rust-analyzer/stargazers/404").unwrap();
assert_eq!(h, &12);
assert_eq!(p.params(), vec![("org", "rust-lang"), ("repo", "rust-analyzer"), ("*1", "stargazers/404")]);

let (h, p) = tree.find("/public/js/main.js").unwrap();
assert_eq!(h, &7);
assert_eq!(p.params(), vec![("any", "js/main.js")]);

let (h, p) = tree.find("/api/v1").unwrap();
assert_eq!(h, &13);
assert_eq!(p.params(), vec![("+1", "v1")]);

Hyper hello example can be found here.

Benchmark

$ cargo bench

Acknowledgements

It is inspired by the:

Other languages

Wrappers for path-tree in other languages:

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~75KB