rework IntoPatterns trait and codegen

This commit is contained in:
Rob Ede 2021-07-16 23:07:28 +01:00
parent a0fe2a9b2e
commit 5360b9eb58
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
4 changed files with 91 additions and 104 deletions

View File

@ -20,11 +20,12 @@ path = "src/lib.rs"
default = ["http"] default = ["http"]
[dependencies] [dependencies]
bytestring = ">=0.1.5, <2"
either = "1.6"
http = { version = "0.2.3", optional = true }
log = "0.4"
regex = "1.5" regex = "1.5"
serde = "1" serde = "1"
bytestring = ">=0.1.5, <2"
log = "0.4"
http = { version = "0.2.3", optional = true }
[dev-dependencies] [dev-dependencies]
http = "0.2.3" http = "0.2.3"

View File

@ -4,6 +4,8 @@
#![doc(html_logo_url = "https://actix.rs/img/logo.png")] #![doc(html_logo_url = "https://actix.rs/img/logo.png")]
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")] #![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
use either::Either;
mod de; mod de;
mod path; mod path;
mod resource; mod resource;
@ -40,98 +42,64 @@ impl ResourcePath for bytestring::ByteString {
} }
} }
/// Helper trait for type that could be converted to path pattern /// Helper trait for type that could be converted to one or more path pattern.
pub trait IntoPattern { pub trait IntoPatterns {
fn is_single(&self) -> bool; fn patterns(&self) -> Either<String, Vec<String>>;
fn patterns(&self) -> Vec<String>;
} }
impl IntoPattern for String { impl IntoPatterns for String {
fn is_single(&self) -> bool { fn patterns(&self) -> Either<String, Vec<String>> {
true Either::Left(self.clone())
}
fn patterns(&self) -> Vec<String> {
vec![self.clone()]
} }
} }
impl<'a> IntoPattern for &'a String { impl<'a> IntoPatterns for &'a String {
fn is_single(&self) -> bool { fn patterns(&self) -> Either<String, Vec<String>> {
true Either::Left((*self).clone())
}
fn patterns(&self) -> Vec<String> {
vec![self.as_str().to_string()]
} }
} }
impl<'a> IntoPattern for &'a str { impl<'a> IntoPatterns for &'a str {
fn is_single(&self) -> bool { fn patterns(&self) -> Either<String, Vec<String>> {
true Either::Left((*self).to_owned())
}
fn patterns(&self) -> Vec<String> {
vec![(*self).to_string()]
} }
} }
impl<T: AsRef<str>> IntoPattern for Vec<T> { impl<T: AsRef<str>> IntoPatterns for Vec<T> {
fn is_single(&self) -> bool { fn patterns(&self) -> Either<String, Vec<String>> {
self.len() == 1 let mut patterns = self.iter().map(|v| v.as_ref().to_owned());
}
fn patterns(&self) -> Vec<String> { match patterns.size_hint() {
self.iter().map(|v| v.as_ref().to_string()).collect() (1, _) => Either::Left(patterns.next().unwrap()),
} _ => Either::Right(patterns.collect()),
}
macro_rules! array_patterns (($tp:ty, $num:tt) => {
impl IntoPattern for [$tp; $num] {
fn is_single(&self) -> bool {
$num == 1
} }
}
}
fn patterns(&self) -> Vec<String> { macro_rules! array_patterns_single (($tp:ty) => {
self.iter().map(|v| v.to_string()).collect() impl IntoPatterns for [$tp; 1] {
fn patterns(&self) -> Either<String, Vec<String>> {
Either::Left(self[0].to_owned())
} }
} }
}); });
array_patterns!(&str, 1); macro_rules! array_patterns_multiple (($tp:ty, $str_fn:expr, $($num:tt) +) => {
array_patterns!(&str, 2); // for each array length specified in $num
array_patterns!(&str, 3); $(
array_patterns!(&str, 4); impl IntoPatterns for [$tp; $num] {
array_patterns!(&str, 5); fn patterns(&self) -> Either<String, Vec<String>> {
array_patterns!(&str, 6); Either::Right(self.iter().map($str_fn).collect())
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);
array_patterns!(String, 1); array_patterns_single!(&str);
array_patterns!(String, 2); 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!(String, 3);
array_patterns!(String, 4); array_patterns_single!(String);
array_patterns!(String, 5); array_patterns_multiple!(String, |v| v.clone(), 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16);
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);
#[cfg(feature = "http")] #[cfg(feature = "http")]
mod url; mod url;
@ -140,10 +108,11 @@ mod url;
pub use self::url::{Quoter, Url}; pub use self::url::{Quoter, Url};
#[cfg(feature = "http")] #[cfg(feature = "http")]
mod http_support { mod http_impls {
use super::ResourcePath;
use http::Uri; use http::Uri;
use super::ResourcePath;
impl ResourcePath for Uri { impl ResourcePath for Uri {
fn path(&self) -> &str { fn path(&self) -> &str {
self.path() self.path()

View File

@ -6,10 +6,11 @@ use std::{
mem, mem,
}; };
use either::Either;
use regex::{escape, Regex, RegexSet}; use regex::{escape, Regex, RegexSet};
use crate::path::{Path, PathItem}; use crate::path::{Path, PathItem};
use crate::{IntoPattern, Resource, ResourcePath}; use crate::{IntoPatterns, Resource, ResourcePath};
const MAX_DYNAMIC_SEGMENTS: usize = 16; const MAX_DYNAMIC_SEGMENTS: usize = 16;
@ -25,9 +26,6 @@ const REGEX_FLAGS: &str = "(?s-m)";
pub struct ResourceDef { pub struct ResourceDef {
id: u16, id: u16,
/// Pattern type.
pat_type: PatternType,
/// Optional name of resource definition. Defaults to "". /// Optional name of resource definition. Defaults to "".
name: String, name: String,
@ -35,6 +33,9 @@ pub struct ResourceDef {
// TODO: Sort of, in dynamic set pattern type it is blank, consider change to option. // TODO: Sort of, in dynamic set pattern type it is blank, consider change to option.
pattern: String, pattern: String,
/// Pattern type.
pat_type: PatternType,
/// List of elements that compose the pattern, in order. /// List of elements that compose the pattern, in order.
/// ///
/// `None` with pattern type is DynamicSet. /// `None` with pattern type is DynamicSet.
@ -75,29 +76,45 @@ impl ResourceDef {
/// Parse path pattern and create new `Pattern` instance. /// Parse path pattern and create new `Pattern` instance.
/// ///
/// Panics if path pattern is malformed. /// Panics if path pattern is malformed.
pub fn new<T: IntoPattern>(path: T) -> Self { pub fn new<T: IntoPatterns>(path: T) -> Self {
if path.is_single() { match path.patterns() {
ResourceDef::from_single_pattern(&path.patterns()[0], false) Either::Left(pattern) => ResourceDef::from_single_pattern(&pattern, false),
} else {
let mut data = Vec::new();
let mut re_set = Vec::new();
for pattern in path.patterns() { Either::Right(patterns) => {
match ResourceDef::parse(&pattern, false, true) { if patterns.is_empty() {
(PatternType::Dynamic(re, names), _) => { // since zero length pattern sets are possible, return a useless `ResourceDef`
re_set.push(re.as_str().to_owned());
data.push((re, names)); return ResourceDef {
} id: 0,
_ => unreachable!(), name: String::new(),
pattern: String::new(),
pat_type: PatternType::DynamicSet(RegexSet::empty(), Vec::new()),
elements: None,
};
} }
}
ResourceDef { let mut re_set = Vec::with_capacity(patterns.len());
id: 0, let mut pattern_data = Vec::new();
pat_type: PatternType::DynamicSet(RegexSet::new(re_set).unwrap(), data),
elements: None, for pattern in patterns {
name: String::new(), match ResourceDef::parse(&pattern, false, true) {
pattern: "".to_owned(), (PatternType::Dynamic(re, names), _) => {
re_set.push(re.as_str().to_owned());
pattern_data.push((re, names));
}
_ => unreachable!(),
}
}
let pattern_re_set = RegexSet::new(re_set).unwrap();
ResourceDef {
id: 0,
name: String::new(),
pattern: String::new(),
pat_type: PatternType::DynamicSet(pattern_re_set, pattern_data),
elements: None,
}
} }
} }
} }

View File

@ -1,4 +1,4 @@
use crate::{IntoPattern, Resource, ResourceDef, ResourcePath}; use crate::{IntoPatterns, Resource, ResourceDef, ResourcePath};
#[derive(Debug, Copy, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq)]
pub struct ResourceId(pub u16); pub struct ResourceId(pub u16);
@ -88,7 +88,7 @@ pub struct RouterBuilder<T, U = ()> {
impl<T, U> RouterBuilder<T, U> { impl<T, U> RouterBuilder<T, U> {
/// Register resource for specified path. /// Register resource for specified path.
pub fn path<P: IntoPattern>( pub fn path<P: IntoPatterns>(
&mut self, &mut self,
path: P, path: P,
resource: T, resource: T,