📦 ibraheemdev / matchit

A high performance, zero-copy URL router.

511 stars 46 forks 👁 511 watching ⚖️ MIT License
prefix-treeradix-treerouterurl
📥 Clone https://github.com/ibraheemdev/matchit.git
HTTPS git clone https://github.com/ibraheemdev/matchit.git
SSH git clone git@github.com:ibraheemdev/matchit.git
CLI gh repo clone ibraheemdev/matchit
iksuddle iksuddle fix false conflict 500698f 22 days ago 📝 History
📂 master View all commits →
📁 .github
📁 benches
📁 examples
📁 fuzz
📁 src
📁 tests
📄 .gitignore
📄 Cargo.toml
📄 LICENSE
📄 README.md
📄 README.md

matchit

crates.io github docs.rs

A high performance, zero-copy URL router.

use matchit::Router;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut router = Router::new();
    router.insert("/home", "Welcome!")?;
    router.insert("/users/{id}", "A User")?;

    let matched = router.at("/users/978")?;
    assert_eq!(matched.params.get("id"), Some("978"));
    assert_eq!(*matched.value, "A User");

    Ok(())
}

Parameters

The router supports dynamic route segments. These can either be named or catch-all parameters.

Named parameters like /{id} match anything until the next static segment or the end of the path.

``rust,ignore let mut router = Router::new(); router.insert("/users/{id}", 42)?; let matched = router.at("/users/1")?; assert_eq!(matched.params.get("id"), Some("1")); let matched = router.at("/users/23")?; assert_eq!(matched.params.get("id"), Some("23")); assert!(router.at("/users").is_err()); %%CODEBLOCK1%%rust,ignore let mut router = Router::new(); router.insert("/images/img-{id}.png", true)?; let matched = router.at("/images/img-1.png")?; assert_eq!(matched.params.get("id"), Some("1")); assert!(router.at("/images/img-1.jpg").is_err()); %%CODEBLOCK2%%rust,ignore let mut router = Router::new(); router.insert("/{*rest}", true)?; let matched = router.at("/foo.html")?; assert_eq!(matched.params.get("rest"), Some("foo.html")); let matched = router.at("/static/bar.css")?; assert_eq!(matched.params.get("rest"), Some("static/bar.css")); // Note that this would lead to an empty parameter value. assert!(router.at("/").is_err()); %%CODEBLOCK3%%rust,ignore let mut router = Router::new(); router.insert("/{{hello}}", true)?; router.insert("/{hello}", true)?; // Match the static route. let matched = router.at("/{hello}")?; assert!(matched.params.is_empty()); // Match the dynamic route. let matched = router.at("/hello")?; assert_eq!(matched.params.get("hello"), Some("hello")); %%CODEBLOCK4%%rust,ignore let mut router = Router::new(); router.insert("/", "Welcome!").unwrap(); // Priority: 1 router.insert("/about", "About Me").unwrap(); // Priority: 1 router.insert("/{*filepath}", "...").unwrap(); // Priority: 2 %%CODEBLOCK5%%text Priority Path Value 9 \ 1 3 ├s None 2 |├earch\ 2 1 |└upport\ 3 2 ├blog\ 4 1 | └{post} None 1 | └\ 5 2 ├about-us\ 6 1 | └team\ 7 1 └contact\ 8 %%CODEBLOCK6%%text Compare Routers/matchit time: [2.4451 µs 2.4456 µs 2.4462 µs] Compare Routers/gonzales time: [4.2618 µs 4.2632 µs 4.2646 µs] Compare Routers/path-tree time: [4.8666 µs 4.8696 µs 4.8728 µs] Compare Routers/wayfind time: [4.9440 µs 4.9539 µs 4.9668 µs] Compare Routers/route-recognizer time: [49.203 µs 49.214 µs 49.226 µs] Compare Routers/routefinder time: [70.598 µs 70.636 µs 70.670 µs] Compare Routers/actix time: [453.91 µs 454.01 µs 454.11 µs] Compare Routers/regex time: [421.76 µs 421.82 µs 421.89 µs] ` ## Credits A lot of the code in this package was inspired by Julien Schmidt's [httprouter`](https://github.com/julienschmidt/httprouter).