1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! # `wayfind`
//!
//! A speedy, flexible router.
//!
//! ## Syntax
//!
//! ### Static
//!
//! Static template parts are treated as-is.
//!
//! - No percent-decoding occurs.
//! - Templates are case-sensitive.
//!
//! The leading static part of a template must start with a `/`.
//!
//! #### Example
//!
//! ```rust
//! use wayfind::RouterBuilder;
//!
//! let mut builder = RouterBuilder::new();
//! builder.insert("/hello", 1)?;
//! builder.insert("/hello/world", 2)?;
//!
//! let router = builder.build();
//!
//! let search = router.search("/hello").unwrap();
//! assert_eq!(search.data(), &1);
//! assert_eq!(search.template(), "/hello");
//!
//! let search = router.search("/hello/world").unwrap();
//! assert_eq!(search.data(), &2);
//! assert_eq!(search.template(), "/hello/world");
//!
//! assert!(router.search("/world").is_none());
//! # Ok::<_, Box<dyn core::error::Error>>(())
//!```
//!
//! ### Dynamic
//!
//! Dynamic parameters can match any byte, **excluding** the path delimiter `/`.
//!
//! Supported forms:
//! - whole segment parameters: `/<name>/`
//! - inline parameters: `/<name>.txt`
//!
//! #### Example
//!
//! ```rust
//! use wayfind::RouterBuilder;
//!
//! let mut builder = RouterBuilder::new();
//! builder.insert("/users/<id>", 1)?;
//! builder.insert("/users/<id>/files/<filename>.pdf", 2)?;
//!
//! let router = builder.build();
//!
//! let search = router.search("/users/123").unwrap();
//! assert_eq!(search.data(), &1);
//! assert_eq!(search.template(), "/users/<id>");
//! assert_eq!(search.parameters(), &[("id", "123")]);
//!
//! let search = router.search("/users/123/files/my.document.pdf").unwrap();
//! assert_eq!(search.data(), &2);
//! assert_eq!(search.template(), "/users/<id>/files/<filename>.pdf");
//! assert_eq!(search.parameters(), &[("id", "123"), ("filename", "my.document")]);
//! # Ok::<_, Box<dyn core::error::Error>>(())
//!```
//!
//! ### Wildcard
//!
//! Wildcard parameters can match any byte, **including** the path delimiter `/`.
//!
//! Supported forms:
//! - inline wildcards: `/<*path>.html`
//! - mid-route wildcards: `/api/<*path>/help`
//! - end-route catch-all: `/<*catch_all>`
//!
//! #### Example
//!
//! ```rust
//! use wayfind::RouterBuilder;
//!
//! let mut builder = RouterBuilder::new();
//! builder.insert("/files/<*slug>/delete", 1)?;
//! builder.insert("/<*catch_all>", 2)?;
//!
//! let router = builder.build();
//!
//! let search = router.search("/files/documents/reports/annual.pdf/delete").unwrap();
//! assert_eq!(search.data(), &1);
//! assert_eq!(search.template(), "/files/<*slug>/delete");
//! assert_eq!(search.parameters(), &[("slug", "documents/reports/annual.pdf")]);
//!
//! let search = router.search("/any/other/path").unwrap();
//! assert_eq!(search.data(), &2);
//! assert_eq!(search.template(), "/<*catch_all>");
//! assert_eq!(search.parameters(), &[("catch_all", "any/other/path")]);
//! # Ok::<_, Box<dyn core::error::Error>>(())
//! ```
//!
//! ## Priority
//!
//! When searching, each node tries its children in priority order:
//! 1. Static: `/users`
//! 2. Dynamic: `/<id>`
//! 3. Wildcard: `/<*path>`
//!
//! All parameters are greedy, consuming as much of the path as possible.
//!
//! ## Display
//!
//! The router can be printed as a tree, via a [`Display`](core::fmt::Display) implementation.
extern crate alloc;
pub use RouterBuilder;
pub use InsertError;
pub use ;