mirror of https://github.com/fafhrd91/actix-web
refactor: move regexset code selection to own module
This commit is contained in:
parent
6ccc853e19
commit
1a709596dc
|
@ -22,6 +22,7 @@ unicode = ["dep:regex"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bytestring = ">=0.1.5, <2"
|
bytestring = ">=0.1.5, <2"
|
||||||
|
cfg-if = "1"
|
||||||
http = { version = "0.2.7", optional = true }
|
http = { version = "0.2.7", optional = true }
|
||||||
regex = { version = "1.5", optional = true }
|
regex = { version = "1.5", optional = true }
|
||||||
regex-lite = "0.1"
|
regex-lite = "0.1"
|
||||||
|
@ -37,6 +38,7 @@ percent-encoding = "2.1"
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "router"
|
name = "router"
|
||||||
harness = false
|
harness = false
|
||||||
|
required-features = ["unicode"]
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "quoter"
|
name = "quoter"
|
||||||
|
|
|
@ -10,6 +10,7 @@ mod de;
|
||||||
mod path;
|
mod path;
|
||||||
mod pattern;
|
mod pattern;
|
||||||
mod quoter;
|
mod quoter;
|
||||||
|
mod regex_set;
|
||||||
mod resource;
|
mod resource;
|
||||||
mod resource_path;
|
mod resource_path;
|
||||||
mod router;
|
mod router;
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
//! Abstraction over `regex` and `regex-lite` depending on whether we have `unicode` crate feature
|
||||||
|
//! enabled.
|
||||||
|
|
||||||
|
use cfg_if::cfg_if;
|
||||||
|
#[cfg(feature = "unicode")]
|
||||||
|
pub(crate) use regex::{escape, Regex};
|
||||||
|
#[cfg(not(feature = "unicode"))]
|
||||||
|
pub(crate) use regex_lite::{escape, Regex};
|
||||||
|
|
||||||
|
#[cfg(feature = "unicode")]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct RegexSet(regex::RegexSet);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unicode"))]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct RegexSet(Vec<regex_lite::Regex>);
|
||||||
|
|
||||||
|
impl RegexSet {
|
||||||
|
/// Create a new regex set.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if any path patterns are malformed.
|
||||||
|
pub(crate) fn new(re_set: Vec<String>) -> Self {
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(feature = "unicode")] {
|
||||||
|
Self(regex::RegexSet::new(re_set).unwrap())
|
||||||
|
} else {
|
||||||
|
Self(re_set.iter().map(|re| Regex::new(re).unwrap()).collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new empty regex set.
|
||||||
|
pub(crate) fn empty() -> Self {
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(feature = "unicode")] {
|
||||||
|
Self(regex::RegexSet::empty())
|
||||||
|
} else {
|
||||||
|
Self(Vec::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_match(&self, path: &str) -> bool {
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(feature = "unicode")] {
|
||||||
|
self.0.is_match(path)
|
||||||
|
} else {
|
||||||
|
self.0.iter().any(|re| re.is_match(path))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn first_match_idx(&self, path: &str) -> Option<usize> {
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(feature = "unicode")] {
|
||||||
|
self.0.matches(path).into_iter().next()
|
||||||
|
} else {
|
||||||
|
Some(self.0.iter().enumerate().find(|(_, re)| re.is_match(path))?.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,13 +5,13 @@ use std::{
|
||||||
mem,
|
mem,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "unicode")]
|
|
||||||
use regex::{escape, Regex};
|
|
||||||
#[cfg(not(feature = "unicode"))]
|
|
||||||
use regex_lite::{escape, Regex};
|
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
use crate::{path::PathItem, IntoPatterns, Patterns, Resource, ResourcePath};
|
use crate::{
|
||||||
|
path::PathItem,
|
||||||
|
regex_set::{escape, Regex, RegexSet},
|
||||||
|
IntoPatterns, Patterns, Resource, ResourcePath,
|
||||||
|
};
|
||||||
|
|
||||||
const MAX_DYNAMIC_SEGMENTS: usize = 16;
|
const MAX_DYNAMIC_SEGMENTS: usize = 16;
|
||||||
|
|
||||||
|
@ -236,7 +236,7 @@ enum PatternSegment {
|
||||||
Var(String),
|
Var(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug, Clone)]
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
enum PatternType {
|
enum PatternType {
|
||||||
/// Single constant/literal segment.
|
/// Single constant/literal segment.
|
||||||
|
@ -246,7 +246,7 @@ enum PatternType {
|
||||||
Dynamic(Regex, Vec<&'static str>),
|
Dynamic(Regex, Vec<&'static str>),
|
||||||
|
|
||||||
/// Regular expression set and list of component expressions plus dynamic segment names.
|
/// Regular expression set and list of component expressions plus dynamic segment names.
|
||||||
DynamicSet(Vec<Regex>, Vec<(Regex, Vec<&'static str>)>),
|
DynamicSet(RegexSet, Vec<(Regex, Vec<&'static str>)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResourceDef {
|
impl ResourceDef {
|
||||||
|
@ -560,7 +560,7 @@ impl ResourceDef {
|
||||||
match &self.pat_type {
|
match &self.pat_type {
|
||||||
PatternType::Static(pattern) => self.static_match(pattern, path).is_some(),
|
PatternType::Static(pattern) => self.static_match(pattern, path).is_some(),
|
||||||
PatternType::Dynamic(re, _) => re.is_match(path),
|
PatternType::Dynamic(re, _) => re.is_match(path),
|
||||||
PatternType::DynamicSet(re, _) => re.iter().any(|re| re.is_match(path)),
|
PatternType::DynamicSet(re, _) => re.is_match(path),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -606,7 +606,7 @@ impl ResourceDef {
|
||||||
PatternType::Dynamic(re, _) => Some(re.captures(path)?[1].len()),
|
PatternType::Dynamic(re, _) => Some(re.captures(path)?[1].len()),
|
||||||
|
|
||||||
PatternType::DynamicSet(re, params) => {
|
PatternType::DynamicSet(re, params) => {
|
||||||
let idx = re.iter().enumerate().find(|(_, re)| re.is_match(path))?.0;
|
let idx = re.first_match_idx(path)?;
|
||||||
let (ref pattern, _) = params[idx];
|
let (ref pattern, _) = params[idx];
|
||||||
Some(pattern.captures(path)?[1].len())
|
Some(pattern.captures(path)?[1].len())
|
||||||
}
|
}
|
||||||
|
@ -709,9 +709,8 @@ impl ResourceDef {
|
||||||
|
|
||||||
PatternType::DynamicSet(re, params) => {
|
PatternType::DynamicSet(re, params) => {
|
||||||
let path = path.unprocessed();
|
let path = path.unprocessed();
|
||||||
let (pattern, names) = match re.iter().enumerate().find(|(_, re)| re.is_match(path))
|
let (pattern, names) = match re.first_match_idx(path) {
|
||||||
{
|
Some(idx) => ¶ms[idx],
|
||||||
Some((idx, _)) => ¶ms[idx],
|
|
||||||
_ => return false,
|
_ => return false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -853,9 +852,10 @@ impl ResourceDef {
|
||||||
|
|
||||||
// since zero length pattern sets are possible
|
// since zero length pattern sets are possible
|
||||||
// just return a useless `ResourceDef`
|
// just return a useless `ResourceDef`
|
||||||
Patterns::List(patterns) if patterns.is_empty() => {
|
Patterns::List(patterns) if patterns.is_empty() => (
|
||||||
(PatternType::DynamicSet(Vec::new(), Vec::new()), Vec::new())
|
PatternType::DynamicSet(RegexSet::empty(), Vec::new()),
|
||||||
}
|
Vec::new(),
|
||||||
|
),
|
||||||
|
|
||||||
Patterns::List(patterns) => {
|
Patterns::List(patterns) => {
|
||||||
let mut re_set = Vec::with_capacity(patterns.len());
|
let mut re_set = Vec::with_capacity(patterns.len());
|
||||||
|
@ -873,7 +873,7 @@ impl ResourceDef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let pattern_re_set = re_set.iter().map(|re| Regex::new(re).unwrap()).collect();
|
let pattern_re_set = RegexSet::new(re_set);
|
||||||
let segments = segments.unwrap_or_default();
|
let segments = segments.unwrap_or_default();
|
||||||
|
|
||||||
(
|
(
|
||||||
|
|
Loading…
Reference in New Issue