mirror of
https://github.com/fafhrd91/actix-net
synced 2024-11-27 21:22:57 +01:00
add zero cost profiling to router
This commit is contained in:
parent
5687e81d9f
commit
95cba659ff
@ -21,15 +21,17 @@ default = ["http"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bytestring = ">=0.1.5, <2"
|
bytestring = ">=0.1.5, <2"
|
||||||
|
firestorm = "0.4"
|
||||||
http = { version = "0.2.3", optional = true }
|
http = { version = "0.2.3", optional = true }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
regex = "1.5"
|
regex = "1.5"
|
||||||
serde = "1"
|
serde = "1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
criterion = { version = "0.3", features = ["html_reports"] }
|
||||||
|
firestorm = { version = "0.4", features = ["enable_system_time"] }
|
||||||
http = "0.2.3"
|
http = "0.2.3"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
criterion = { version = "0.3", features = ["html_reports"] }
|
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "router"
|
name = "router"
|
||||||
|
172
actix-router/examples/flamegraph.rs
Normal file
172
actix-router/examples/flamegraph.rs
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
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),
|
||||||
|
];
|
||||||
|
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 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 call() {
|
||||||
|
let mut path = actix_router::Path::new(route);
|
||||||
|
actix.recognize(&mut path).unwrap();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::ops::Index;
|
use std::ops::Index;
|
||||||
|
|
||||||
|
use firestorm::profile_method;
|
||||||
use serde::de;
|
use serde::de;
|
||||||
|
|
||||||
use crate::de::PathDeserializer;
|
use crate::de::PathDeserializer;
|
||||||
@ -37,21 +38,23 @@ impl<T: ResourcePath> Path<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get reference to inner path instance
|
/// Get reference to inner path instance.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_ref(&self) -> &T {
|
pub fn get_ref(&self) -> &T {
|
||||||
&self.path
|
&self.path
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get mutable reference to inner path instance
|
/// Get mutable reference to inner path instance.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_mut(&mut self) -> &mut T {
|
pub fn get_mut(&mut self) -> &mut T {
|
||||||
&mut self.path
|
&mut self.path
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Path
|
/// Path.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn path(&self) -> &str {
|
pub fn path(&self) -> &str {
|
||||||
|
profile_method!(path);
|
||||||
|
|
||||||
let skip = self.skip as usize;
|
let skip = self.skip as usize;
|
||||||
let path = self.path.path();
|
let path = self.path.path();
|
||||||
if skip <= path.len() {
|
if skip <= path.len() {
|
||||||
@ -61,7 +64,7 @@ impl<T: ResourcePath> Path<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set new path
|
/// Set new path.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set(&mut self, path: T) {
|
pub fn set(&mut self, path: T) {
|
||||||
self.skip = 0;
|
self.skip = 0;
|
||||||
@ -69,20 +72,22 @@ impl<T: ResourcePath> Path<T> {
|
|||||||
self.segments.clear();
|
self.segments.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset state
|
/// Reset state.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
self.skip = 0;
|
self.skip = 0;
|
||||||
self.segments.clear();
|
self.segments.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Skip first `n` chars in path
|
/// Skip first `n` chars in path.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn skip(&mut self, n: u16) {
|
pub fn skip(&mut self, n: u16) {
|
||||||
self.skip += n;
|
self.skip += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add(&mut self, name: impl Into<Cow<'static, str>>, value: PathItem) {
|
pub(crate) fn add(&mut self, name: impl Into<Cow<'static, str>>, value: PathItem) {
|
||||||
|
profile_method!(add);
|
||||||
|
|
||||||
match value {
|
match value {
|
||||||
PathItem::Static(s) => self.segments.push((name.into(), PathItem::Static(s))),
|
PathItem::Static(s) => self.segments.push((name.into(), PathItem::Static(s))),
|
||||||
PathItem::Segment(begin, end) => self.segments.push((
|
PathItem::Segment(begin, end) => self.segments.push((
|
||||||
@ -116,6 +121,8 @@ impl<T: ResourcePath> Path<T> {
|
|||||||
|
|
||||||
/// Get matched parameter by name without type conversion
|
/// Get matched parameter by name without type conversion
|
||||||
pub fn get(&self, key: &str) -> Option<&str> {
|
pub fn get(&self, key: &str) -> Option<&str> {
|
||||||
|
profile_method!(get);
|
||||||
|
|
||||||
for item in self.segments.iter() {
|
for item in self.segments.iter() {
|
||||||
if key == item.0 {
|
if key == item.0 {
|
||||||
return match item.1 {
|
return match item.1 {
|
||||||
@ -140,9 +147,10 @@ impl<T: ResourcePath> Path<T> {
|
|||||||
|
|
||||||
/// Get matched parameter by name.
|
/// Get matched parameter by name.
|
||||||
///
|
///
|
||||||
/// If keyed parameter is not available empty string is used as default
|
/// If keyed parameter is not available empty string is used as default value.
|
||||||
/// value.
|
|
||||||
pub fn query(&self, key: &str) -> &str {
|
pub fn query(&self, key: &str) -> &str {
|
||||||
|
profile_method!(query);
|
||||||
|
|
||||||
if let Some(s) = self.get(key) {
|
if let Some(s) = self.get(key) {
|
||||||
s
|
s
|
||||||
} else {
|
} else {
|
||||||
@ -150,7 +158,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> {
|
pub fn iter(&self) -> PathIter<'_, T> {
|
||||||
PathIter {
|
PathIter {
|
||||||
idx: 0,
|
idx: 0,
|
||||||
@ -160,6 +168,7 @@ impl<T: ResourcePath> Path<T> {
|
|||||||
|
|
||||||
/// Try to deserialize matching parameters to a specified type `U`
|
/// 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> {
|
pub fn load<'de, U: serde::Deserialize<'de>>(&'de self) -> Result<U, de::value::Error> {
|
||||||
|
profile_method!(load);
|
||||||
de::Deserialize::deserialize(PathDeserializer::new(self))
|
de::Deserialize::deserialize(PathDeserializer::new(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ use std::{
|
|||||||
mem,
|
mem,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use firestorm::{profile_fn, profile_method, profile_section};
|
||||||
use regex::{escape, Regex, RegexSet};
|
use regex::{escape, Regex, RegexSet};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -78,6 +79,8 @@ impl ResourceDef {
|
|||||||
///
|
///
|
||||||
/// Panics if path pattern is malformed.
|
/// Panics if path pattern is malformed.
|
||||||
pub fn new<T: IntoPatterns>(path: T) -> Self {
|
pub fn new<T: IntoPatterns>(path: T) -> Self {
|
||||||
|
profile_method!(new);
|
||||||
|
|
||||||
match path.patterns() {
|
match path.patterns() {
|
||||||
Patterns::Single(pattern) => ResourceDef::from_single_pattern(&pattern, false),
|
Patterns::Single(pattern) => ResourceDef::from_single_pattern(&pattern, false),
|
||||||
|
|
||||||
@ -124,6 +127,7 @@ impl ResourceDef {
|
|||||||
///
|
///
|
||||||
/// Panics if path regex pattern is malformed.
|
/// Panics if path regex pattern is malformed.
|
||||||
pub fn prefix(path: &str) -> Self {
|
pub fn prefix(path: &str) -> Self {
|
||||||
|
profile_method!(prefix);
|
||||||
ResourceDef::from_single_pattern(path, true)
|
ResourceDef::from_single_pattern(path, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,6 +138,7 @@ impl ResourceDef {
|
|||||||
///
|
///
|
||||||
/// Panics if path regex pattern is malformed.
|
/// Panics if path regex pattern is malformed.
|
||||||
pub fn root_prefix(path: &str) -> Self {
|
pub fn root_prefix(path: &str) -> Self {
|
||||||
|
profile_method!(root_prefix);
|
||||||
ResourceDef::from_single_pattern(&insert_slash(path), true)
|
ResourceDef::from_single_pattern(&insert_slash(path), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,6 +154,8 @@ impl ResourceDef {
|
|||||||
|
|
||||||
/// Parse path pattern and create a new instance
|
/// Parse path pattern and create a new instance
|
||||||
fn from_single_pattern(pattern: &str, for_prefix: bool) -> Self {
|
fn from_single_pattern(pattern: &str, for_prefix: bool) -> Self {
|
||||||
|
profile_method!(from_single_pattern);
|
||||||
|
|
||||||
let pattern = pattern.to_owned();
|
let pattern = pattern.to_owned();
|
||||||
let (pat_type, elements) = ResourceDef::parse(&pattern, for_prefix, false);
|
let (pat_type, elements) = ResourceDef::parse(&pattern, for_prefix, false);
|
||||||
|
|
||||||
@ -179,6 +186,8 @@ impl ResourceDef {
|
|||||||
/// Check if path matches this pattern.
|
/// Check if path matches this pattern.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_match(&self, path: &str) -> bool {
|
pub fn is_match(&self, path: &str) -> bool {
|
||||||
|
profile_method!(is_match);
|
||||||
|
|
||||||
match self.pat_type {
|
match self.pat_type {
|
||||||
PatternType::Static(ref s) => s == path,
|
PatternType::Static(ref s) => s == path,
|
||||||
PatternType::Prefix(ref s) => path.starts_with(s),
|
PatternType::Prefix(ref s) => path.starts_with(s),
|
||||||
@ -189,6 +198,8 @@ impl ResourceDef {
|
|||||||
|
|
||||||
/// Is prefix path a match against this resource.
|
/// Is prefix path a match against this resource.
|
||||||
pub fn is_prefix_match(&self, path: &str) -> Option<usize> {
|
pub fn is_prefix_match(&self, path: &str) -> Option<usize> {
|
||||||
|
profile_method!(is_prefix_match);
|
||||||
|
|
||||||
let path_len = path.len();
|
let path_len = path.len();
|
||||||
let path = if path.is_empty() { "/" } else { path };
|
let path = if path.is_empty() { "/" } else { path };
|
||||||
|
|
||||||
@ -245,6 +256,7 @@ impl ResourceDef {
|
|||||||
|
|
||||||
/// Is the given path and parameters a match against this pattern.
|
/// Is the given path and parameters a match against this pattern.
|
||||||
pub fn match_path<T: ResourcePath>(&self, path: &mut Path<T>) -> bool {
|
pub fn match_path<T: ResourcePath>(&self, path: &mut Path<T>) -> bool {
|
||||||
|
profile_method!(match_path);
|
||||||
self.match_path_checked(path, &|_, _| true, &Some(()))
|
self.match_path_checked(path, &|_, _| true, &Some(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,11 +272,15 @@ impl ResourceDef {
|
|||||||
R: Resource<T>,
|
R: Resource<T>,
|
||||||
F: Fn(&R, &Option<U>) -> bool,
|
F: Fn(&R, &Option<U>) -> bool,
|
||||||
{
|
{
|
||||||
|
profile_method!(match_path_checked);
|
||||||
|
|
||||||
let mut segments: [PathItem; MAX_DYNAMIC_SEGMENTS] = Default::default();
|
let mut segments: [PathItem; MAX_DYNAMIC_SEGMENTS] = Default::default();
|
||||||
let path = res.resource_path();
|
let path = res.resource_path();
|
||||||
|
|
||||||
let (matched_len, matched_vars) = match self.pat_type {
|
let (matched_len, matched_vars) = match self.pat_type {
|
||||||
PatternType::Static(ref segment) => {
|
PatternType::Static(ref segment) => {
|
||||||
|
profile_section!(pattern_static);
|
||||||
|
|
||||||
if segment != path.path() {
|
if segment != path.path() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -273,6 +289,8 @@ impl ResourceDef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PatternType::Prefix(ref prefix) => {
|
PatternType::Prefix(ref prefix) => {
|
||||||
|
profile_section!(pattern_dynamic);
|
||||||
|
|
||||||
let path_str = path.path();
|
let path_str = path.path();
|
||||||
let path_len = path_str.len();
|
let path_len = path_str.len();
|
||||||
|
|
||||||
@ -300,24 +318,39 @@ impl ResourceDef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PatternType::Dynamic(ref re, ref names) => {
|
PatternType::Dynamic(ref re, ref names) => {
|
||||||
let captures = match re.captures(path.path()) {
|
profile_section!(pattern_dynamic);
|
||||||
Some(captures) => captures,
|
|
||||||
_ => return false,
|
let captures = {
|
||||||
|
profile_section!(pattern_dynamic_regex_exec);
|
||||||
|
|
||||||
|
match re.captures(path.path()) {
|
||||||
|
Some(captures) => captures,
|
||||||
|
_ => return false,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (no, name) in names.iter().enumerate() {
|
{
|
||||||
if let Some(m) = captures.name(&name) {
|
profile_section!(pattern_dynamic_extract_captures);
|
||||||
segments[no] = PathItem::Segment(m.start() as u16, m.end() as u16);
|
|
||||||
} else {
|
for (no, name) in names.iter().enumerate() {
|
||||||
log::error!("Dynamic path match but not all segments found: {}", name);
|
if let Some(m) = captures.name(&name) {
|
||||||
return false;
|
segments[no] = PathItem::Segment(m.start() as u16, m.end() as u16);
|
||||||
|
} else {
|
||||||
|
log::error!(
|
||||||
|
"Dynamic path match but not all segments found: {}",
|
||||||
|
name
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
(captures[0].len(), Some(names))
|
(captures[0].len(), Some(names))
|
||||||
}
|
}
|
||||||
|
|
||||||
PatternType::DynamicSet(ref re, ref params) => {
|
PatternType::DynamicSet(ref re, ref params) => {
|
||||||
|
profile_section!(pattern_dynamic_set);
|
||||||
|
|
||||||
let path = path.path();
|
let path = path.path();
|
||||||
let (pattern, names) = match re.matches(path).into_iter().next() {
|
let (pattern, names) = match re.matches(path).into_iter().next() {
|
||||||
Some(idx) => ¶ms[idx],
|
Some(idx) => ¶ms[idx],
|
||||||
@ -394,6 +427,7 @@ impl ResourceDef {
|
|||||||
U: Iterator<Item = I>,
|
U: Iterator<Item = I>,
|
||||||
I: AsRef<str>,
|
I: AsRef<str>,
|
||||||
{
|
{
|
||||||
|
profile_method!(resource_path_from_iter);
|
||||||
self.build_resource_path(path, |_| elements.next())
|
self.build_resource_path(path, |_| elements.next())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,6 +438,7 @@ impl ResourceDef {
|
|||||||
U: Iterator<Item = I>,
|
U: Iterator<Item = I>,
|
||||||
I: AsRef<str>,
|
I: AsRef<str>,
|
||||||
{
|
{
|
||||||
|
profile_method!(build_resource_path);
|
||||||
self.resource_path_from_iter(path, elements)
|
self.resource_path_from_iter(path, elements)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,6 +455,7 @@ impl ResourceDef {
|
|||||||
V: AsRef<str>,
|
V: AsRef<str>,
|
||||||
S: BuildHasher,
|
S: BuildHasher,
|
||||||
{
|
{
|
||||||
|
profile_method!(resource_path_from_map);
|
||||||
self.build_resource_path(path, |name| {
|
self.build_resource_path(path, |name| {
|
||||||
name.and_then(|name| elements.get(name).map(AsRef::<str>::as_ref))
|
name.and_then(|name| elements.get(name).map(AsRef::<str>::as_ref))
|
||||||
})
|
})
|
||||||
@ -458,6 +494,7 @@ impl ResourceDef {
|
|||||||
S: BuildHasher,
|
S: BuildHasher,
|
||||||
T: AsRef<str>,
|
T: AsRef<str>,
|
||||||
{
|
{
|
||||||
|
profile_method!(resource_path_from_map_with_tail);
|
||||||
self.build_resource_path(path, |name| match name {
|
self.build_resource_path(path, |name| match name {
|
||||||
Some(name) => elements.get(name).map(AsRef::<str>::as_ref),
|
Some(name) => elements.get(name).map(AsRef::<str>::as_ref),
|
||||||
None => Some(tail.as_ref()),
|
None => Some(tail.as_ref()),
|
||||||
@ -465,6 +502,8 @@ impl ResourceDef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_param(pattern: &str) -> (PatternElement, String, &str) {
|
fn parse_param(pattern: &str) -> (PatternElement, String, &str) {
|
||||||
|
profile_method!(parse_param);
|
||||||
|
|
||||||
const DEFAULT_PATTERN: &str = "[^/]+";
|
const DEFAULT_PATTERN: &str = "[^/]+";
|
||||||
const DEFAULT_PATTERN_TAIL: &str = ".*";
|
const DEFAULT_PATTERN_TAIL: &str = ".*";
|
||||||
|
|
||||||
@ -526,6 +565,8 @@ impl ResourceDef {
|
|||||||
for_prefix: bool,
|
for_prefix: bool,
|
||||||
force_dynamic: bool,
|
force_dynamic: bool,
|
||||||
) -> (PatternType, Vec<PatternElement>) {
|
) -> (PatternType, Vec<PatternElement>) {
|
||||||
|
profile_method!(parse);
|
||||||
|
|
||||||
let mut unprocessed = pattern;
|
let mut unprocessed = pattern;
|
||||||
|
|
||||||
if !force_dynamic && unprocessed.find('{').is_none() && !unprocessed.ends_with('*') {
|
if !force_dynamic && unprocessed.find('{').is_none() && !unprocessed.ends_with('*') {
|
||||||
@ -637,6 +678,8 @@ impl From<String> for ResourceDef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn insert_slash(path: &str) -> Cow<'_, str> {
|
pub(crate) fn insert_slash(path: &str) -> Cow<'_, str> {
|
||||||
|
profile_fn!(insert_slash);
|
||||||
|
|
||||||
if !path.is_empty() && !path.starts_with('/') {
|
if !path.is_empty() && !path.starts_with('/') {
|
||||||
let mut new_path = String::with_capacity(path.len() + 1);
|
let mut new_path = String::with_capacity(path.len() + 1);
|
||||||
new_path.push('/');
|
new_path.push('/');
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use firestorm::profile_method;
|
||||||
|
|
||||||
use crate::{IntoPatterns, Resource, ResourceDef, ResourcePath};
|
use crate::{IntoPatterns, Resource, ResourceDef, ResourcePath};
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
@ -24,6 +26,8 @@ impl<T, U> Router<T, U> {
|
|||||||
R: Resource<P>,
|
R: Resource<P>,
|
||||||
P: ResourcePath,
|
P: ResourcePath,
|
||||||
{
|
{
|
||||||
|
profile_method!(recognize);
|
||||||
|
|
||||||
for item in self.0.iter() {
|
for item in self.0.iter() {
|
||||||
if item.0.match_path(resource.resource_path()) {
|
if item.0.match_path(resource.resource_path()) {
|
||||||
return Some((&item.1, ResourceId(item.0.id())));
|
return Some((&item.1, ResourceId(item.0.id())));
|
||||||
@ -37,6 +41,8 @@ impl<T, U> Router<T, U> {
|
|||||||
R: Resource<P>,
|
R: Resource<P>,
|
||||||
P: ResourcePath,
|
P: ResourcePath,
|
||||||
{
|
{
|
||||||
|
profile_method!(recognize_mut);
|
||||||
|
|
||||||
for item in self.0.iter_mut() {
|
for item in self.0.iter_mut() {
|
||||||
if item.0.match_path(resource.resource_path()) {
|
if item.0.match_path(resource.resource_path()) {
|
||||||
return Some((&mut item.1, ResourceId(item.0.id())));
|
return Some((&mut item.1, ResourceId(item.0.id())));
|
||||||
@ -55,6 +61,8 @@ impl<T, U> Router<T, U> {
|
|||||||
R: Resource<P>,
|
R: Resource<P>,
|
||||||
P: ResourcePath,
|
P: ResourcePath,
|
||||||
{
|
{
|
||||||
|
profile_method!(recognize_checked);
|
||||||
|
|
||||||
for item in self.0.iter() {
|
for item in self.0.iter() {
|
||||||
if item.0.match_path_checked(resource, &check, &item.2) {
|
if item.0.match_path_checked(resource, &check, &item.2) {
|
||||||
return Some((&item.1, ResourceId(item.0.id())));
|
return Some((&item.1, ResourceId(item.0.id())));
|
||||||
@ -73,6 +81,8 @@ impl<T, U> Router<T, U> {
|
|||||||
R: Resource<P>,
|
R: Resource<P>,
|
||||||
P: ResourcePath,
|
P: ResourcePath,
|
||||||
{
|
{
|
||||||
|
profile_method!(recognize_mut_checked);
|
||||||
|
|
||||||
for item in self.0.iter_mut() {
|
for item in self.0.iter_mut() {
|
||||||
if item.0.match_path_checked(resource, &check, &item.2) {
|
if item.0.match_path_checked(resource, &check, &item.2) {
|
||||||
return Some((&mut item.1, ResourceId(item.0.id())));
|
return Some((&mut item.1, ResourceId(item.0.id())));
|
||||||
@ -93,6 +103,8 @@ impl<T, U> RouterBuilder<T, U> {
|
|||||||
path: P,
|
path: P,
|
||||||
resource: T,
|
resource: T,
|
||||||
) -> &mut (ResourceDef, T, Option<U>) {
|
) -> &mut (ResourceDef, T, Option<U>) {
|
||||||
|
profile_method!(path);
|
||||||
|
|
||||||
self.resources
|
self.resources
|
||||||
.push((ResourceDef::new(path), resource, None));
|
.push((ResourceDef::new(path), resource, None));
|
||||||
self.resources.last_mut().unwrap()
|
self.resources.last_mut().unwrap()
|
||||||
@ -100,6 +112,8 @@ impl<T, U> RouterBuilder<T, U> {
|
|||||||
|
|
||||||
/// Register resource for specified path prefix.
|
/// Register resource for specified path prefix.
|
||||||
pub fn prefix(&mut self, prefix: &str, resource: T) -> &mut (ResourceDef, T, Option<U>) {
|
pub fn prefix(&mut self, prefix: &str, resource: T) -> &mut (ResourceDef, T, Option<U>) {
|
||||||
|
profile_method!(prefix);
|
||||||
|
|
||||||
self.resources
|
self.resources
|
||||||
.push((ResourceDef::prefix(prefix), resource, None));
|
.push((ResourceDef::prefix(prefix), resource, None));
|
||||||
self.resources.last_mut().unwrap()
|
self.resources.last_mut().unwrap()
|
||||||
@ -107,6 +121,8 @@ impl<T, U> RouterBuilder<T, U> {
|
|||||||
|
|
||||||
/// Register resource for ResourceDef
|
/// Register resource for ResourceDef
|
||||||
pub fn rdef(&mut self, rdef: ResourceDef, resource: T) -> &mut (ResourceDef, T, Option<U>) {
|
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.push((rdef, resource, None));
|
||||||
self.resources.last_mut().unwrap()
|
self.resources.last_mut().unwrap()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user