mirror of https://github.com/fafhrd91/actix-net
Merge branch 'master' into patch-1
This commit is contained in:
commit
30450a7b84
|
@ -1,3 +1,3 @@
|
|||
[alias]
|
||||
chk = "hack check --workspace --all-features --tests --examples"
|
||||
lint = "hack --clean-per-run clippy --workspace --tests --examples"
|
||||
chk = "check --workspace --all-features --tests --examples --bins"
|
||||
lint = "clippy --workspace --all-features --tests --examples --bins -- -Dclippy::todo"
|
||||
|
|
|
@ -39,4 +39,4 @@ jobs:
|
|||
uses: actions-rs/clippy-check@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --workspace --tests --all-features
|
||||
args: --workspace --all-features --tests --examples --bins -- -Dclippy::todo
|
||||
|
|
|
@ -27,3 +27,8 @@ actix-utils = { path = "actix-utils" }
|
|||
bytestring = { path = "bytestring" }
|
||||
local-channel = { path = "local-channel" }
|
||||
local-waker = { path = "local-waker" }
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
opt-level = 3
|
||||
codegen-units = 1
|
||||
|
|
|
@ -1,12 +1,37 @@
|
|||
# Changes
|
||||
|
||||
## Unreleased - 2021-xx-xx
|
||||
* Introduce `ResourceDef::join`. [#380]
|
||||
|
||||
[#380]: https://github.com/actix/actix-net/pull/380
|
||||
|
||||
|
||||
## 0.5.0-beta.1 - 2021-07-20
|
||||
* Fix a bug in multi-patterns where static patterns are interpreted as regex. [#366]
|
||||
* Introduce `ResourceDef::pattern_iter` to get an iterator over all patterns in a multi-pattern resource. [#373]
|
||||
* Fix segment interpolation leaving `Path` in unintended state after matching. [#368]
|
||||
* Path tail pattern now works as expected after a dynamic segment (e.g. `/user/{uid}/*`). [#366]
|
||||
* Fixed a bug where, in multi-patterns, static patterns are interpreted as regex. [#366]
|
||||
* Fix `ResourceDef` `PartialEq` implementation. [#373]
|
||||
* Re-work `IntoPatterns` trait, adding a `Patterns` enum. [#372]
|
||||
* Implement `IntoPatterns` for `bytestring::ByteString`. [#372]
|
||||
* Rename `Path::{len => segment_count}` to be more descriptive of it's purpose. [#370]
|
||||
* Rename `ResourceDef::{resource_path => resource_path_from_iter}`. [#371]
|
||||
* `ResourceDef::resource_path_from_iter` now takes an `IntoIterator`. [#373]
|
||||
* Rename `ResourceDef::{resource_path_named => resource_path_from_map}`. [#371]
|
||||
* Rename `ResourceDef::{is_prefix_match => find_match}`. [#373]
|
||||
* Rename `ResourceDef::{match_path => capture_match_info}`. [#373]
|
||||
* Rename `ResourceDef::{match_path_checked => capture_match_info_fn}`. [#373]
|
||||
* Remove `ResourceDef::name_mut` and introduce `ResourceDef::set_name`. [#373]
|
||||
* Rename `Router::{*_checked => *_fn}`. [#373]
|
||||
* Return type of `ResourceDef::name` is now `Option<&str>`. [#373]
|
||||
* Return type of `ResourceDef::pattern` is now `Option<&str>`. [#373]
|
||||
|
||||
[#368]: https://github.com/actix/actix-net/pull/368
|
||||
[#366]: https://github.com/actix/actix-net/pull/366
|
||||
[#368]: https://github.com/actix/actix-net/pull/368
|
||||
[#370]: https://github.com/actix/actix-net/pull/370
|
||||
[#371]: https://github.com/actix/actix-net/pull/371
|
||||
[#372]: https://github.com/actix/actix-net/pull/372
|
||||
[#373]: https://github.com/actix/actix-net/pull/373
|
||||
|
||||
|
||||
## 0.4.0 - 2021-06-06
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
[package]
|
||||
name = "actix-router"
|
||||
version = "0.4.0"
|
||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||
description = "Resource path matching library"
|
||||
version = "0.5.0-beta.1"
|
||||
authors = [
|
||||
"Nikolay Kim <fafhrd91@gmail.com>",
|
||||
"Ali MJ Al-Nasrawy <alimjalnasrawy@gmail.com>",
|
||||
"Rob Ede <robjtede@icloud.com>",
|
||||
]
|
||||
description = "Resource path matching and router"
|
||||
keywords = ["actix", "router", "routing"]
|
||||
repository = "https://github.com/actix/actix-net"
|
||||
repository = "https://github.com/actix/actix-net.git"
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
|
@ -16,12 +20,19 @@ path = "src/lib.rs"
|
|||
default = ["http"]
|
||||
|
||||
[dependencies]
|
||||
regex = "1.3.1"
|
||||
serde = "1.0.104"
|
||||
bytestring = ">=0.1.5, <2"
|
||||
log = "0.4.8"
|
||||
http = { version = "0.2.2", optional = true }
|
||||
firestorm = "0.4"
|
||||
http = { version = "0.2.3", optional = true }
|
||||
log = "0.4"
|
||||
regex = "1.5"
|
||||
serde = "1"
|
||||
|
||||
[dev-dependencies]
|
||||
http = "0.2.2"
|
||||
serde_derive = "1.0"
|
||||
criterion = { version = "0.3", features = ["html_reports"] }
|
||||
firestorm = { version = "0.4", features = ["enable_system_time"] }
|
||||
http = "0.2.3"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
|
||||
[[bench]]
|
||||
name = "router"
|
||||
harness = false
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
//! Based on https://github.com/ibraheemdev/matchit/blob/master/benches/bench.rs
|
||||
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
|
||||
macro_rules! register {
|
||||
(colon) => {{
|
||||
register!(finish => ":p1", ":p2", ":p3", ":p4")
|
||||
}};
|
||||
(brackets) => {{
|
||||
register!(finish => "{p1}", "{p2}", "{p3}", "{p4}")
|
||||
}};
|
||||
(regex) => {{
|
||||
register!(finish => "(.*)", "(.*)", "(.*)", "(.*)")
|
||||
}};
|
||||
(finish => $p1:literal, $p2:literal, $p3:literal, $p4:literal) => {{
|
||||
let arr = [
|
||||
concat!("/authorizations"),
|
||||
concat!("/authorizations/", $p1),
|
||||
concat!("/applications/", $p1, "/tokens/", $p2),
|
||||
concat!("/events"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/events"),
|
||||
concat!("/networks/", $p1, "/", $p2, "/events"),
|
||||
concat!("/orgs/", $p1, "/events"),
|
||||
concat!("/users/", $p1, "/received_events"),
|
||||
concat!("/users/", $p1, "/received_events/public"),
|
||||
concat!("/users/", $p1, "/events"),
|
||||
concat!("/users/", $p1, "/events/public"),
|
||||
concat!("/users/", $p1, "/events/orgs/", $p2),
|
||||
concat!("/feeds"),
|
||||
concat!("/notifications"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/notifications"),
|
||||
concat!("/notifications/threads/", $p1),
|
||||
concat!("/notifications/threads/", $p1, "/subscription"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/stargazers"),
|
||||
concat!("/users/", $p1, "/starred"),
|
||||
concat!("/user/starred"),
|
||||
concat!("/user/starred/", $p1, "/", $p2),
|
||||
concat!("/repos/", $p1, "/", $p2, "/subscribers"),
|
||||
concat!("/users/", $p1, "/subscriptions"),
|
||||
concat!("/user/subscriptions"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/subscription"),
|
||||
concat!("/user/subscriptions/", $p1, "/", $p2),
|
||||
concat!("/users/", $p1, "/gists"),
|
||||
concat!("/gists"),
|
||||
concat!("/gists/", $p1),
|
||||
concat!("/gists/", $p1, "/star"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/git/blobs/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/git/commits/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/git/refs"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/git/tags/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/git/trees/", $p3),
|
||||
concat!("/issues"),
|
||||
concat!("/user/issues"),
|
||||
concat!("/orgs/", $p1, "/issues"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/issues"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/issues/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/assignees"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/assignees/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/issues/", $p3, "/comments"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/issues/", $p3, "/events"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/labels"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/labels/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/issues/", $p3, "/labels"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/milestones/", $p3, "/labels"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/milestones/"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/milestones/", $p3),
|
||||
concat!("/emojis"),
|
||||
concat!("/gitignore/templates"),
|
||||
concat!("/gitignore/templates/", $p1),
|
||||
concat!("/meta"),
|
||||
concat!("/rate_limit"),
|
||||
concat!("/users/", $p1, "/orgs"),
|
||||
concat!("/user/orgs"),
|
||||
concat!("/orgs/", $p1),
|
||||
concat!("/orgs/", $p1, "/members"),
|
||||
concat!("/orgs/", $p1, "/members", $p2),
|
||||
concat!("/orgs/", $p1, "/public_members"),
|
||||
concat!("/orgs/", $p1, "/public_members/", $p2),
|
||||
concat!("/orgs/", $p1, "/teams"),
|
||||
concat!("/teams/", $p1),
|
||||
concat!("/teams/", $p1, "/members"),
|
||||
concat!("/teams/", $p1, "/members", $p2),
|
||||
concat!("/teams/", $p1, "/repos"),
|
||||
concat!("/teams/", $p1, "/repos/", $p2, "/", $p3),
|
||||
concat!("/user/teams"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/pulls"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/pulls/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/pulls/", $p3, "/commits"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/pulls/", $p3, "/files"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/pulls/", $p3, "/merge"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/pulls/", $p3, "/comments"),
|
||||
concat!("/user/repos"),
|
||||
concat!("/users/", $p1, "/repos"),
|
||||
concat!("/orgs/", $p1, "/repos"),
|
||||
concat!("/repositories"),
|
||||
concat!("/repos/", $p1, "/", $p2),
|
||||
concat!("/repos/", $p1, "/", $p2, "/contributors"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/languages"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/teams"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/tags"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/branches"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/branches/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/collaborators"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/collaborators/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/comments"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/commits/", $p3, "/comments"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/commits"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/commits/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/readme"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/keys"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/keys", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/downloads"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/downloads", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/forks"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/hooks"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/hooks", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/releases"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/releases/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/releases/", $p3, "/assets"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/stats/contributors"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/stats/commit_activity"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/stats/code_frequency"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/stats/participation"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/stats/punch_card"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/statuses/", $p3),
|
||||
concat!("/search/repositories"),
|
||||
concat!("/search/code"),
|
||||
concat!("/search/issues"),
|
||||
concat!("/search/users"),
|
||||
concat!("/legacy/issues/search/", $p1, "/", $p2, "/", $p3, "/", $p4),
|
||||
concat!("/legacy/repos/search/", $p1),
|
||||
concat!("/legacy/user/search/", $p1),
|
||||
concat!("/legacy/user/email/", $p1),
|
||||
concat!("/users/", $p1),
|
||||
concat!("/user"),
|
||||
concat!("/users"),
|
||||
concat!("/user/emails"),
|
||||
concat!("/users/", $p1, "/followers"),
|
||||
concat!("/user/followers"),
|
||||
concat!("/users/", $p1, "/following"),
|
||||
concat!("/user/following"),
|
||||
concat!("/user/following/", $p1),
|
||||
concat!("/users/", $p1, "/following", $p2),
|
||||
concat!("/users/", $p1, "/keys"),
|
||||
concat!("/user/keys"),
|
||||
concat!("/user/keys/", $p1),
|
||||
];
|
||||
std::array::IntoIter::new(arr)
|
||||
}};
|
||||
}
|
||||
|
||||
fn call() -> impl Iterator<Item = &'static str> {
|
||||
let arr = [
|
||||
"/authorizations",
|
||||
"/user/repos",
|
||||
"/repos/rust-lang/rust/stargazers",
|
||||
"/orgs/rust-lang/public_members/nikomatsakis",
|
||||
"/repos/rust-lang/rust/releases/1.51.0",
|
||||
];
|
||||
|
||||
std::array::IntoIter::new(arr)
|
||||
}
|
||||
|
||||
fn compare_routers(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("Compare Routers");
|
||||
|
||||
let mut actix = actix_router::Router::<bool>::build();
|
||||
for route in register!(brackets) {
|
||||
actix.path(route, true);
|
||||
}
|
||||
let actix = actix.finish();
|
||||
group.bench_function("actix", |b| {
|
||||
b.iter(|| {
|
||||
for route in call() {
|
||||
let mut path = actix_router::Path::new(route);
|
||||
black_box(actix.recognize(&mut path).unwrap());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
let regex_set = regex::RegexSet::new(register!(regex)).unwrap();
|
||||
group.bench_function("regex", |b| {
|
||||
b.iter(|| {
|
||||
for route in call() {
|
||||
black_box(regex_set.matches(route));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group!(benches, compare_routers);
|
||||
criterion_main!(benches);
|
|
@ -0,0 +1,169 @@
|
|||
macro_rules! register {
|
||||
(brackets) => {{
|
||||
register!(finish => "{p1}", "{p2}", "{p3}", "{p4}")
|
||||
}};
|
||||
(finish => $p1:literal, $p2:literal, $p3:literal, $p4:literal) => {{
|
||||
let arr = [
|
||||
concat!("/authorizations"),
|
||||
concat!("/authorizations/", $p1),
|
||||
concat!("/applications/", $p1, "/tokens/", $p2),
|
||||
concat!("/events"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/events"),
|
||||
concat!("/networks/", $p1, "/", $p2, "/events"),
|
||||
concat!("/orgs/", $p1, "/events"),
|
||||
concat!("/users/", $p1, "/received_events"),
|
||||
concat!("/users/", $p1, "/received_events/public"),
|
||||
concat!("/users/", $p1, "/events"),
|
||||
concat!("/users/", $p1, "/events/public"),
|
||||
concat!("/users/", $p1, "/events/orgs/", $p2),
|
||||
concat!("/feeds"),
|
||||
concat!("/notifications"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/notifications"),
|
||||
concat!("/notifications/threads/", $p1),
|
||||
concat!("/notifications/threads/", $p1, "/subscription"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/stargazers"),
|
||||
concat!("/users/", $p1, "/starred"),
|
||||
concat!("/user/starred"),
|
||||
concat!("/user/starred/", $p1, "/", $p2),
|
||||
concat!("/repos/", $p1, "/", $p2, "/subscribers"),
|
||||
concat!("/users/", $p1, "/subscriptions"),
|
||||
concat!("/user/subscriptions"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/subscription"),
|
||||
concat!("/user/subscriptions/", $p1, "/", $p2),
|
||||
concat!("/users/", $p1, "/gists"),
|
||||
concat!("/gists"),
|
||||
concat!("/gists/", $p1),
|
||||
concat!("/gists/", $p1, "/star"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/git/blobs/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/git/commits/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/git/refs"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/git/tags/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/git/trees/", $p3),
|
||||
concat!("/issues"),
|
||||
concat!("/user/issues"),
|
||||
concat!("/orgs/", $p1, "/issues"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/issues"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/issues/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/assignees"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/assignees/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/issues/", $p3, "/comments"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/issues/", $p3, "/events"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/labels"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/labels/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/issues/", $p3, "/labels"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/milestones/", $p3, "/labels"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/milestones/"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/milestones/", $p3),
|
||||
concat!("/emojis"),
|
||||
concat!("/gitignore/templates"),
|
||||
concat!("/gitignore/templates/", $p1),
|
||||
concat!("/meta"),
|
||||
concat!("/rate_limit"),
|
||||
concat!("/users/", $p1, "/orgs"),
|
||||
concat!("/user/orgs"),
|
||||
concat!("/orgs/", $p1),
|
||||
concat!("/orgs/", $p1, "/members"),
|
||||
concat!("/orgs/", $p1, "/members", $p2),
|
||||
concat!("/orgs/", $p1, "/public_members"),
|
||||
concat!("/orgs/", $p1, "/public_members/", $p2),
|
||||
concat!("/orgs/", $p1, "/teams"),
|
||||
concat!("/teams/", $p1),
|
||||
concat!("/teams/", $p1, "/members"),
|
||||
concat!("/teams/", $p1, "/members", $p2),
|
||||
concat!("/teams/", $p1, "/repos"),
|
||||
concat!("/teams/", $p1, "/repos/", $p2, "/", $p3),
|
||||
concat!("/user/teams"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/pulls"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/pulls/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/pulls/", $p3, "/commits"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/pulls/", $p3, "/files"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/pulls/", $p3, "/merge"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/pulls/", $p3, "/comments"),
|
||||
concat!("/user/repos"),
|
||||
concat!("/users/", $p1, "/repos"),
|
||||
concat!("/orgs/", $p1, "/repos"),
|
||||
concat!("/repositories"),
|
||||
concat!("/repos/", $p1, "/", $p2),
|
||||
concat!("/repos/", $p1, "/", $p2, "/contributors"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/languages"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/teams"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/tags"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/branches"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/branches/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/collaborators"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/collaborators/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/comments"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/commits/", $p3, "/comments"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/commits"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/commits/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/readme"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/keys"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/keys", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/downloads"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/downloads", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/forks"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/hooks"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/hooks", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/releases"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/releases/", $p3),
|
||||
concat!("/repos/", $p1, "/", $p2, "/releases/", $p3, "/assets"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/stats/contributors"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/stats/commit_activity"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/stats/code_frequency"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/stats/participation"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/stats/punch_card"),
|
||||
concat!("/repos/", $p1, "/", $p2, "/statuses/", $p3),
|
||||
concat!("/search/repositories"),
|
||||
concat!("/search/code"),
|
||||
concat!("/search/issues"),
|
||||
concat!("/search/users"),
|
||||
concat!("/legacy/issues/search/", $p1, "/", $p2, "/", $p3, "/", $p4),
|
||||
concat!("/legacy/repos/search/", $p1),
|
||||
concat!("/legacy/user/search/", $p1),
|
||||
concat!("/legacy/user/email/", $p1),
|
||||
concat!("/users/", $p1),
|
||||
concat!("/user"),
|
||||
concat!("/users"),
|
||||
concat!("/user/emails"),
|
||||
concat!("/users/", $p1, "/followers"),
|
||||
concat!("/user/followers"),
|
||||
concat!("/users/", $p1, "/following"),
|
||||
concat!("/user/following"),
|
||||
concat!("/user/following/", $p1),
|
||||
concat!("/users/", $p1, "/following", $p2),
|
||||
concat!("/users/", $p1, "/keys"),
|
||||
concat!("/user/keys"),
|
||||
concat!("/user/keys/", $p1),
|
||||
];
|
||||
|
||||
arr.to_vec()
|
||||
}};
|
||||
}
|
||||
|
||||
static PATHS: [&str; 5] = [
|
||||
"/authorizations",
|
||||
"/user/repos",
|
||||
"/repos/rust-lang/rust/stargazers",
|
||||
"/orgs/rust-lang/public_members/nikomatsakis",
|
||||
"/repos/rust-lang/rust/releases/1.51.0",
|
||||
];
|
||||
|
||||
fn main() {
|
||||
let mut router = actix_router::Router::<bool>::build();
|
||||
|
||||
for route in register!(brackets) {
|
||||
router.path(route, true);
|
||||
}
|
||||
|
||||
let actix = router.finish();
|
||||
|
||||
if firestorm::enabled() {
|
||||
firestorm::bench("target", || {
|
||||
for &route in &PATHS {
|
||||
let mut path = actix_router::Path::new(route);
|
||||
actix.recognize(&mut path).unwrap();
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
|
@ -24,10 +24,13 @@ macro_rules! parse_single_value {
|
|||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
if self.path.len() != 1 {
|
||||
if self.path.segment_count() != 1 {
|
||||
Err(de::value::Error::custom(
|
||||
format!("wrong number of parameters: {} expected 1", self.path.len())
|
||||
.as_str(),
|
||||
format!(
|
||||
"wrong number of parameters: {} expected 1",
|
||||
self.path.segment_count()
|
||||
)
|
||||
.as_str(),
|
||||
))
|
||||
} else {
|
||||
let v = self.path[0].parse().map_err(|_| {
|
||||
|
@ -110,11 +113,11 @@ impl<'de, T: ResourcePath + 'de> Deserializer<'de> for PathDeserializer<'de, T>
|
|||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
if self.path.len() < len {
|
||||
if self.path.segment_count() < len {
|
||||
Err(de::value::Error::custom(
|
||||
format!(
|
||||
"wrong number of parameters: {} expected {}",
|
||||
self.path.len(),
|
||||
self.path.segment_count(),
|
||||
len
|
||||
)
|
||||
.as_str(),
|
||||
|
@ -135,11 +138,11 @@ impl<'de, T: ResourcePath + 'de> Deserializer<'de> for PathDeserializer<'de, T>
|
|||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
if self.path.len() < len {
|
||||
if self.path.segment_count() < len {
|
||||
Err(de::value::Error::custom(
|
||||
format!(
|
||||
"wrong number of parameters: {} expected {}",
|
||||
self.path.len(),
|
||||
self.path.segment_count(),
|
||||
len
|
||||
)
|
||||
.as_str(),
|
||||
|
@ -173,9 +176,13 @@ impl<'de, T: ResourcePath + 'de> Deserializer<'de> for PathDeserializer<'de, T>
|
|||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
if self.path.len() != 1 {
|
||||
if self.path.segment_count() != 1 {
|
||||
Err(de::value::Error::custom(
|
||||
format!("wrong number of parameters: {} expected 1", self.path.len()).as_str(),
|
||||
format!(
|
||||
"wrong number of parameters: {} expected 1",
|
||||
self.path.segment_count()
|
||||
)
|
||||
.as_str(),
|
||||
))
|
||||
} else {
|
||||
visitor.visit_str(&self.path[0])
|
||||
|
@ -485,8 +492,7 @@ impl<'de> de::VariantAccess<'de> for UnitVariant {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde::de;
|
||||
use serde_derive::Deserialize;
|
||||
use serde::{de, Deserialize};
|
||||
|
||||
use super::*;
|
||||
use crate::path::Path;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//! Resource path matching library.
|
||||
//! Resource path matching and router.
|
||||
|
||||
#![deny(rust_2018_idioms, nonstandard_style)]
|
||||
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
||||
|
@ -14,6 +14,8 @@ pub use self::path::Path;
|
|||
pub use self::resource::ResourceDef;
|
||||
pub use self::router::{ResourceInfo, Router, RouterBuilder};
|
||||
|
||||
// TODO: this trait is necessary, document it
|
||||
// see impl Resource for ServiceRequest
|
||||
pub trait Resource<T: ResourcePath> {
|
||||
fn resource_path(&mut self) -> &mut Path<T>;
|
||||
}
|
||||
|
@ -40,98 +42,92 @@ impl ResourcePath for bytestring::ByteString {
|
|||
}
|
||||
}
|
||||
|
||||
/// Helper trait for type that could be converted to path pattern
|
||||
pub trait IntoPattern {
|
||||
fn is_single(&self) -> bool;
|
||||
|
||||
fn patterns(&self) -> Vec<String>;
|
||||
/// One or many patterns.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Patterns {
|
||||
Single(String),
|
||||
List(Vec<String>),
|
||||
}
|
||||
|
||||
impl IntoPattern for String {
|
||||
fn is_single(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn patterns(&self) -> Vec<String> {
|
||||
vec![self.clone()]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoPattern for &'a String {
|
||||
fn is_single(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn patterns(&self) -> Vec<String> {
|
||||
vec![self.as_str().to_string()]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoPattern for &'a str {
|
||||
fn is_single(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn patterns(&self) -> Vec<String> {
|
||||
vec![(*self).to_string()]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<str>> IntoPattern for Vec<T> {
|
||||
fn is_single(&self) -> bool {
|
||||
self.len() == 1
|
||||
}
|
||||
|
||||
fn patterns(&self) -> Vec<String> {
|
||||
self.iter().map(|v| v.as_ref().to_string()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! array_patterns (($tp:ty, $num:tt) => {
|
||||
impl IntoPattern for [$tp; $num] {
|
||||
fn is_single(&self) -> bool {
|
||||
$num == 1
|
||||
impl Patterns {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
match self {
|
||||
Patterns::Single(_) => false,
|
||||
Patterns::List(pats) => pats.is_empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn patterns(&self) -> Vec<String> {
|
||||
self.iter().map(|v| v.to_string()).collect()
|
||||
/// Helper trait for type that could be converted to one or more path pattern.
|
||||
pub trait IntoPatterns {
|
||||
fn patterns(&self) -> Patterns;
|
||||
}
|
||||
|
||||
impl IntoPatterns for String {
|
||||
fn patterns(&self) -> Patterns {
|
||||
Patterns::Single(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoPatterns for &'a String {
|
||||
fn patterns(&self) -> Patterns {
|
||||
Patterns::Single((*self).clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoPatterns for &'a str {
|
||||
fn patterns(&self) -> Patterns {
|
||||
Patterns::Single((*self).to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoPatterns for bytestring::ByteString {
|
||||
fn patterns(&self) -> Patterns {
|
||||
Patterns::Single(self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoPatterns for Patterns {
|
||||
fn patterns(&self) -> Patterns {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<str>> IntoPatterns for Vec<T> {
|
||||
fn patterns(&self) -> Patterns {
|
||||
let mut patterns = self.iter().map(|v| v.as_ref().to_owned());
|
||||
|
||||
match patterns.size_hint() {
|
||||
(1, _) => Patterns::Single(patterns.next().unwrap()),
|
||||
_ => Patterns::List(patterns.collect()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! array_patterns_single (($tp:ty) => {
|
||||
impl IntoPatterns for [$tp; 1] {
|
||||
fn patterns(&self) -> Patterns {
|
||||
Patterns::Single(self[0].to_owned())
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
array_patterns!(&str, 1);
|
||||
array_patterns!(&str, 2);
|
||||
array_patterns!(&str, 3);
|
||||
array_patterns!(&str, 4);
|
||||
array_patterns!(&str, 5);
|
||||
array_patterns!(&str, 6);
|
||||
array_patterns!(&str, 7);
|
||||
array_patterns!(&str, 8);
|
||||
array_patterns!(&str, 9);
|
||||
array_patterns!(&str, 10);
|
||||
array_patterns!(&str, 11);
|
||||
array_patterns!(&str, 12);
|
||||
array_patterns!(&str, 13);
|
||||
array_patterns!(&str, 14);
|
||||
array_patterns!(&str, 15);
|
||||
array_patterns!(&str, 16);
|
||||
macro_rules! array_patterns_multiple (($tp:ty, $str_fn:expr, $($num:tt) +) => {
|
||||
// for each array length specified in $num
|
||||
$(
|
||||
impl IntoPatterns for [$tp; $num] {
|
||||
fn patterns(&self) -> Patterns {
|
||||
Patterns::List(self.iter().map($str_fn).collect())
|
||||
}
|
||||
}
|
||||
)+
|
||||
});
|
||||
|
||||
array_patterns!(String, 1);
|
||||
array_patterns!(String, 2);
|
||||
array_patterns!(String, 3);
|
||||
array_patterns!(String, 4);
|
||||
array_patterns!(String, 5);
|
||||
array_patterns!(String, 6);
|
||||
array_patterns!(String, 7);
|
||||
array_patterns!(String, 8);
|
||||
array_patterns!(String, 9);
|
||||
array_patterns!(String, 10);
|
||||
array_patterns!(String, 11);
|
||||
array_patterns!(String, 12);
|
||||
array_patterns!(String, 13);
|
||||
array_patterns!(String, 14);
|
||||
array_patterns!(String, 15);
|
||||
array_patterns!(String, 16);
|
||||
array_patterns_single!(&str);
|
||||
array_patterns_multiple!(&str, |&v| v.to_owned(), 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16);
|
||||
|
||||
array_patterns_single!(String);
|
||||
array_patterns_multiple!(String, |v| v.clone(), 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16);
|
||||
|
||||
#[cfg(feature = "http")]
|
||||
mod url;
|
||||
|
@ -140,10 +136,11 @@ mod url;
|
|||
pub use self::url::{Quoter, Url};
|
||||
|
||||
#[cfg(feature = "http")]
|
||||
mod http_support {
|
||||
use super::ResourcePath;
|
||||
mod http_impls {
|
||||
use http::Uri;
|
||||
|
||||
use super::ResourcePath;
|
||||
|
||||
impl ResourcePath for Uri {
|
||||
fn path(&self) -> &str {
|
||||
self.path()
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use std::borrow::Cow;
|
||||
use std::ops::Index;
|
||||
|
||||
use firestorm::profile_method;
|
||||
use serde::de;
|
||||
|
||||
use crate::de::PathDeserializer;
|
||||
use crate::{Resource, ResourcePath};
|
||||
use crate::{de::PathDeserializer, Resource, ResourcePath};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum PathItem {
|
||||
|
@ -18,36 +18,16 @@ impl Default for PathItem {
|
|||
}
|
||||
}
|
||||
|
||||
/// Resource path match information
|
||||
/// Resource path match information.
|
||||
///
|
||||
/// If resource path contains variable patterns, `Path` stores them.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Path<T> {
|
||||
path: T,
|
||||
pub(crate) skip: u16,
|
||||
pub(crate) segments: Vec<(Cow<'static, str>, PathItem)>,
|
||||
}
|
||||
|
||||
impl<T: Default> Default for Path<T> {
|
||||
fn default() -> Self {
|
||||
Path {
|
||||
path: T::default(),
|
||||
skip: 0,
|
||||
segments: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> Clone for Path<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Path {
|
||||
path: self.path.clone(),
|
||||
skip: self.skip,
|
||||
segments: self.segments.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ResourcePath> Path<T> {
|
||||
pub fn new(path: T) -> Path<T> {
|
||||
Path {
|
||||
|
@ -57,21 +37,23 @@ impl<T: ResourcePath> Path<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get reference to inner path instance
|
||||
/// Get reference to inner path instance.
|
||||
#[inline]
|
||||
pub fn get_ref(&self) -> &T {
|
||||
&self.path
|
||||
}
|
||||
|
||||
/// Get mutable reference to inner path instance
|
||||
/// Get mutable reference to inner path instance.
|
||||
#[inline]
|
||||
pub fn get_mut(&mut self) -> &mut T {
|
||||
&mut self.path
|
||||
}
|
||||
|
||||
/// Path
|
||||
/// Path.
|
||||
#[inline]
|
||||
pub fn path(&self) -> &str {
|
||||
profile_method!(path);
|
||||
|
||||
let skip = self.skip as usize;
|
||||
let path = self.path.path();
|
||||
if skip <= path.len() {
|
||||
|
@ -81,7 +63,7 @@ impl<T: ResourcePath> Path<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Set new path
|
||||
/// Set new path.
|
||||
#[inline]
|
||||
pub fn set(&mut self, path: T) {
|
||||
self.skip = 0;
|
||||
|
@ -89,20 +71,22 @@ impl<T: ResourcePath> Path<T> {
|
|||
self.segments.clear();
|
||||
}
|
||||
|
||||
/// Reset state
|
||||
/// Reset state.
|
||||
#[inline]
|
||||
pub fn reset(&mut self) {
|
||||
self.skip = 0;
|
||||
self.segments.clear();
|
||||
}
|
||||
|
||||
/// Skip first `n` chars in path
|
||||
/// Skip first `n` chars in path.
|
||||
#[inline]
|
||||
pub fn skip(&mut self, n: u16) {
|
||||
self.skip += n;
|
||||
}
|
||||
|
||||
pub(crate) fn add(&mut self, name: impl Into<Cow<'static, str>>, value: PathItem) {
|
||||
profile_method!(add);
|
||||
|
||||
match value {
|
||||
PathItem::Static(s) => self.segments.push((name.into(), PathItem::Static(s))),
|
||||
PathItem::Segment(begin, end) => self.segments.push((
|
||||
|
@ -122,35 +106,34 @@ impl<T: ResourcePath> Path<T> {
|
|||
.push((name.into(), PathItem::Static(value.into())));
|
||||
}
|
||||
|
||||
/// Check if there are any matched patterns
|
||||
/// Check if there are any matched patterns.
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.segments.is_empty()
|
||||
}
|
||||
|
||||
/// Check number of extracted parameters
|
||||
/// Returns number of interpolated segments.
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
pub fn segment_count(&self) -> usize {
|
||||
self.segments.len()
|
||||
}
|
||||
|
||||
/// Get matched parameter by name without type conversion
|
||||
pub fn get(&self, key: &str) -> Option<&str> {
|
||||
for item in self.segments.iter() {
|
||||
if key == item.0 {
|
||||
return match item.1 {
|
||||
pub fn get(&self, name: &str) -> Option<&str> {
|
||||
profile_method!(get);
|
||||
|
||||
for (seg_name, val) in self.segments.iter() {
|
||||
if name == seg_name {
|
||||
return match val {
|
||||
PathItem::Static(ref s) => Some(&s),
|
||||
PathItem::Segment(s, e) => {
|
||||
Some(&self.path.path()[(s as usize)..(e as usize)])
|
||||
Some(&self.path.path()[(*s as usize)..(*e as usize)])
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
if key == "tail" {
|
||||
Some(&self.path.path()[(self.skip as usize)..])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Get unprocessed part of the path
|
||||
|
@ -160,9 +143,10 @@ impl<T: ResourcePath> Path<T> {
|
|||
|
||||
/// Get matched parameter by name.
|
||||
///
|
||||
/// If keyed parameter is not available empty string is used as default
|
||||
/// value.
|
||||
/// If keyed parameter is not available empty string is used as default value.
|
||||
pub fn query(&self, key: &str) -> &str {
|
||||
profile_method!(query);
|
||||
|
||||
if let Some(s) = self.get(key) {
|
||||
s
|
||||
} else {
|
||||
|
@ -170,7 +154,7 @@ impl<T: ResourcePath> Path<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Return iterator to items in parameter container
|
||||
/// Return iterator to items in parameter container.
|
||||
pub fn iter(&self) -> PathIter<'_, T> {
|
||||
PathIter {
|
||||
idx: 0,
|
||||
|
@ -180,6 +164,7 @@ impl<T: ResourcePath> Path<T> {
|
|||
|
||||
/// Try to deserialize matching parameters to a specified type `U`
|
||||
pub fn load<'de, U: serde::Deserialize<'de>>(&'de self) -> Result<U, de::value::Error> {
|
||||
profile_method!(load);
|
||||
de::Deserialize::deserialize(PathDeserializer::new(self))
|
||||
}
|
||||
}
|
||||
|
@ -195,7 +180,7 @@ impl<'a, T: ResourcePath> Iterator for PathIter<'a, T> {
|
|||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<(&'a str, &'a str)> {
|
||||
if self.idx < self.params.len() {
|
||||
if self.idx < self.params.segment_count() {
|
||||
let idx = self.idx;
|
||||
let res = match self.params.segments[idx].1 {
|
||||
PathItem::Static(ref s) => &s,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,6 @@
|
|||
use crate::{IntoPattern, Resource, ResourceDef, ResourcePath};
|
||||
use firestorm::profile_method;
|
||||
|
||||
use crate::{IntoPatterns, Resource, ResourceDef, ResourcePath};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub struct ResourceId(pub u16);
|
||||
|
@ -10,7 +12,11 @@ pub struct ResourceInfo {
|
|||
}
|
||||
|
||||
/// Resource router.
|
||||
pub struct Router<T, U = ()>(Vec<(ResourceDef, T, Option<U>)>);
|
||||
// T is the resource itself
|
||||
// U is any other data needed for routing like method guards
|
||||
pub struct Router<T, U = ()> {
|
||||
routes: Vec<(ResourceDef, T, Option<U>)>,
|
||||
}
|
||||
|
||||
impl<T, U> Router<T, U> {
|
||||
pub fn build() -> RouterBuilder<T, U> {
|
||||
|
@ -24,11 +30,14 @@ impl<T, U> Router<T, U> {
|
|||
R: Resource<P>,
|
||||
P: ResourcePath,
|
||||
{
|
||||
for item in self.0.iter() {
|
||||
if item.0.match_path(resource.resource_path()) {
|
||||
profile_method!(recognize);
|
||||
|
||||
for item in self.routes.iter() {
|
||||
if item.0.capture_match_info(resource.resource_path()) {
|
||||
return Some((&item.1, ResourceId(item.0.id())));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
|
@ -37,33 +46,35 @@ impl<T, U> Router<T, U> {
|
|||
R: Resource<P>,
|
||||
P: ResourcePath,
|
||||
{
|
||||
for item in self.0.iter_mut() {
|
||||
if item.0.match_path(resource.resource_path()) {
|
||||
profile_method!(recognize_mut);
|
||||
|
||||
for item in self.routes.iter_mut() {
|
||||
if item.0.capture_match_info(resource.resource_path()) {
|
||||
return Some((&mut item.1, ResourceId(item.0.id())));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn recognize_checked<R, P, F>(
|
||||
&self,
|
||||
resource: &mut R,
|
||||
check: F,
|
||||
) -> Option<(&T, ResourceId)>
|
||||
pub fn recognize_fn<R, P, F>(&self, resource: &mut R, check: F) -> Option<(&T, ResourceId)>
|
||||
where
|
||||
F: Fn(&R, &Option<U>) -> bool,
|
||||
R: Resource<P>,
|
||||
P: ResourcePath,
|
||||
{
|
||||
for item in self.0.iter() {
|
||||
if item.0.match_path_checked(resource, &check, &item.2) {
|
||||
profile_method!(recognize_checked);
|
||||
|
||||
for item in self.routes.iter() {
|
||||
if item.0.capture_match_info_fn(resource, &check, &item.2) {
|
||||
return Some((&item.1, ResourceId(item.0.id())));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn recognize_mut_checked<R, P, F>(
|
||||
pub fn recognize_mut_fn<R, P, F>(
|
||||
&mut self,
|
||||
resource: &mut R,
|
||||
check: F,
|
||||
|
@ -73,11 +84,14 @@ impl<T, U> Router<T, U> {
|
|||
R: Resource<P>,
|
||||
P: ResourcePath,
|
||||
{
|
||||
for item in self.0.iter_mut() {
|
||||
if item.0.match_path_checked(resource, &check, &item.2) {
|
||||
profile_method!(recognize_mut_checked);
|
||||
|
||||
for item in self.routes.iter_mut() {
|
||||
if item.0.capture_match_info_fn(resource, &check, &item.2) {
|
||||
return Some((&mut item.1, ResourceId(item.0.id())));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -88,11 +102,13 @@ pub struct RouterBuilder<T, U = ()> {
|
|||
|
||||
impl<T, U> RouterBuilder<T, U> {
|
||||
/// Register resource for specified path.
|
||||
pub fn path<P: IntoPattern>(
|
||||
pub fn path<P: IntoPatterns>(
|
||||
&mut self,
|
||||
path: P,
|
||||
resource: T,
|
||||
) -> &mut (ResourceDef, T, Option<U>) {
|
||||
profile_method!(path);
|
||||
|
||||
self.resources
|
||||
.push((ResourceDef::new(path), resource, None));
|
||||
self.resources.last_mut().unwrap()
|
||||
|
@ -100,6 +116,8 @@ impl<T, U> RouterBuilder<T, U> {
|
|||
|
||||
/// Register resource for specified path prefix.
|
||||
pub fn prefix(&mut self, prefix: &str, resource: T) -> &mut (ResourceDef, T, Option<U>) {
|
||||
profile_method!(prefix);
|
||||
|
||||
self.resources
|
||||
.push((ResourceDef::prefix(prefix), resource, None));
|
||||
self.resources.last_mut().unwrap()
|
||||
|
@ -107,13 +125,17 @@ impl<T, U> RouterBuilder<T, U> {
|
|||
|
||||
/// Register resource for ResourceDef
|
||||
pub fn rdef(&mut self, rdef: ResourceDef, resource: T) -> &mut (ResourceDef, T, Option<U>) {
|
||||
profile_method!(rdef);
|
||||
|
||||
self.resources.push((rdef, resource, None));
|
||||
self.resources.last_mut().unwrap()
|
||||
}
|
||||
|
||||
/// Finish configuration and create router instance.
|
||||
pub fn finish(self) -> Router<T, U> {
|
||||
Router(self.resources)
|
||||
Router {
|
||||
routes: self.resources,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -206,12 +206,12 @@ mod tests {
|
|||
let re = ResourceDef::new(pattern);
|
||||
let uri = Uri::try_from(url.as_ref()).unwrap();
|
||||
let mut path = Path::new(Url::new(uri));
|
||||
assert!(re.match_path(&mut path));
|
||||
assert!(re.capture_match_info(&mut path));
|
||||
path
|
||||
}
|
||||
|
||||
fn percent_encode(data: &[u8]) -> String {
|
||||
data.into_iter().map(|c| format!("%{:02X}", c)).collect()
|
||||
data.iter().map(|c| format!("%{:02X}", c)).collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -221,7 +221,7 @@ mod tests {
|
|||
let path = match_url(re, "/user/2345/test");
|
||||
assert_eq!(path.get("id").unwrap(), "2345");
|
||||
|
||||
// "%25" should never be decoded into '%' to gurantee the output is a valid
|
||||
// "%25" should never be decoded into '%' to guarantee the output is a valid
|
||||
// percent-encoded format
|
||||
let path = match_url(re, "/user/qwe%25/test");
|
||||
assert_eq!(path.get("id").unwrap(), "qwe%25");
|
||||
|
|
|
@ -287,7 +287,7 @@ fn new_arbiter_with_tokio() {
|
|||
|
||||
arb.join().unwrap();
|
||||
|
||||
assert_eq!(false, counter.load(Ordering::SeqCst));
|
||||
assert!(!counter.load(Ordering::SeqCst));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -73,7 +73,7 @@ fn handle_pair(
|
|||
/// On reaching counter limit worker would use `mio::Waker` and `WakerQueue` to wake up `Accept`
|
||||
/// and notify it to update cached `Availability` again to mark worker as able to accept work again.
|
||||
///
|
||||
/// Hense a wake up would only happen after `Accept` increment it to limit.
|
||||
/// Hence, a wake up would only happen after `Accept` increment it to limit.
|
||||
/// And a decrement to limit always wake up `Accept`.
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Counter {
|
||||
|
@ -179,8 +179,9 @@ impl WorkerHandleAccept {
|
|||
/// Handle to worker than can send stop message to worker.
|
||||
///
|
||||
/// Held by [ServerBuilder](crate::builder::ServerBuilder).
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct WorkerHandleServer {
|
||||
pub idx: usize,
|
||||
idx: usize,
|
||||
tx: UnboundedSender<Stop>,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
/// An implementation of [`poll_ready`]() that always signals readiness.
|
||||
///
|
||||
/// This should only be used for basic leaf services that have no concept of un-readiness.
|
||||
/// For wrapper or other serivice types, use [`forward_ready!`] for simple cases or write a bespoke
|
||||
/// `poll_ready` implementation.
|
||||
///
|
||||
/// [`poll_ready`]: crate::Service::poll_ready
|
||||
///
|
||||
/// # Examples
|
||||
|
|
Loading…
Reference in New Issue