matchit/lib.rs
1//! # `matchit`
2//!
3//! [](https://docs.rs/matchit)
4//! [](https://crates.io/crates/matchit)
5//! [](https://crates.io/crates/matchit)
6//! [](https://github.com/ibraheemdev/matchit/actions)
7//!
8//! A blazing fast URL router.
9//!
10//! ```rust
11//! use matchit::Router;
12//!
13//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
14//! let mut router = Router::new();
15//! router.insert("/home", "Welcome!")?;
16//! router.insert("/users/:id", "A User")?;
17//!
18//! let matched = router.at("/users/978")?;
19//! assert_eq!(matched.params.get("id"), Some("978"));
20//! assert_eq!(*matched.value, "A User");
21//! # Ok(())
22//! # }
23//! ```
24//!
25//! ## Parameters
26//!
27//! Along with static routes, the router also supports dynamic route segments. These can either be named or catch-all parameters:
28//!
29//! ### Named Parameters
30//!
31//! Named parameters like `/:id` match anything until the next `/` or the end of the path:
32//!
33//! ```rust
34//! # use matchit::Router;
35//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
36//! let mut m = Router::new();
37//! m.insert("/users/:id", true)?;
38//!
39//! assert_eq!(m.at("/users/1")?.params.get("id"), Some("1"));
40//! assert_eq!(m.at("/users/23")?.params.get("id"), Some("23"));
41//! assert!(m.at("/users").is_err());
42//!
43//! # Ok(())
44//! # }
45//! ```
46//!
47//! ### Catch-all Parameters
48//!
49//! Catch-all parameters start with `*` and match everything after the `/`. They must always be at the **end** of the route:
50//!
51//! ```rust
52//! # use matchit::Router;
53//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
54//! let mut m = Router::new();
55//! m.insert("/*p", true)?;
56//!
57//! assert_eq!(m.at("/foo.js")?.params.get("p"), Some("foo.js"));
58//! assert_eq!(m.at("/c/bar.css")?.params.get("p"), Some("c/bar.css"));
59//!
60//! # Ok(())
61//! # }
62//! ```
63//!
64//! ## Routing Priority
65//!
66//! Static and dynamic route segments are allowed to overlap. If they do, static segments will be given higher priority:
67//!
68//! ```rust
69//! # use matchit::Router;
70//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
71//! let mut m = Router::new();
72//! m.insert("/", "Welcome!").unwrap() ; // priority: 1
73//! m.insert("/about", "About Me").unwrap(); // priority: 1
74//! m.insert("/*filepath", "...").unwrap(); // priority: 2
75//!
76//! # Ok(())
77//! # }
78//! ```
79//!
80//! ## How does it work?
81//!
82//! The router takes advantage of the fact that URL routes generally follow a hierarchical structure. Routes are stored them in a radix trie that makes heavy use of common prefixes:
83//!
84//! ```text
85//! Priority Path Value
86//! 9 \ 1
87//! 3 ├s None
88//! 2 |├earch\ 2
89//! 1 |└upport\ 3
90//! 2 ├blog\ 4
91//! 1 | └:post None
92//! 1 | └\ 5
93//! 2 ├about-us\ 6
94//! 1 | └team\ 7
95//! 1 └contact\ 8
96//! ```
97//!
98//! This allows us to reduce the route search to a small number of branches. Child nodes on the same level of the tree are also prioritized
99//! by the number of children with registered values, increasing the chance of choosing the correct branch of the first try.
100#![deny(rust_2018_idioms, clippy::all)]
101
102mod error;
103mod params;
104mod router;
105mod tree;
106
107pub use error::{InsertError, MatchError};
108pub use params::{Params, ParamsIter};
109pub use router::{Match, Router};
110
111#[cfg(doctest)]
112mod test_readme {
113 macro_rules! doc_comment {
114 ($x:expr) => {
115 #[doc = $x]
116 extern "C" {}
117 };
118 }
119
120 doc_comment!(include_str!("../README.md"));
121}