1
0
mirror of https://github.com/fafhrd91/actix-net synced 2024-11-27 23:42:56 +01:00

rename Pattern to ResourceDef

This commit is contained in:
Nikolay Kim 2019-02-09 07:24:35 -08:00
parent 17d0f84f63
commit 9979bfb3ef
6 changed files with 102 additions and 64 deletions

View File

@ -2,7 +2,7 @@ use serde::de::{self, Deserializer, Error as DeError, Visitor};
use serde::forward_to_deserialize_any; use serde::forward_to_deserialize_any;
use crate::path::{Path, PathIter}; use crate::path::{Path, PathIter};
use crate::RequestPath; use crate::ResourcePath;
macro_rules! unsupported_type { macro_rules! unsupported_type {
($trait_fn:ident, $name:expr) => { ($trait_fn:ident, $name:expr) => {
@ -33,17 +33,17 @@ macro_rules! parse_single_value {
} }
} }
pub struct PathDeserializer<'de, T: RequestPath + 'de> { pub struct PathDeserializer<'de, T: ResourcePath + 'de> {
path: &'de Path<T>, path: &'de Path<T>,
} }
impl<'de, T: RequestPath + 'de> PathDeserializer<'de, T> { impl<'de, T: ResourcePath + 'de> PathDeserializer<'de, T> {
pub fn new(path: &'de Path<T>) -> Self { pub fn new(path: &'de Path<T>) -> Self {
PathDeserializer { path } PathDeserializer { path }
} }
} }
impl<'de, T: RequestPath + 'de> Deserializer<'de> for PathDeserializer<'de, T> { impl<'de, T: ResourcePath + 'de> Deserializer<'de> for PathDeserializer<'de, T> {
type Error = de::value::Error; type Error = de::value::Error;
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
@ -206,12 +206,12 @@ impl<'de, T: RequestPath + 'de> Deserializer<'de> for PathDeserializer<'de, T> {
parse_single_value!(deserialize_char, visit_char, "char"); parse_single_value!(deserialize_char, visit_char, "char");
} }
struct ParamsDeserializer<'de, T: RequestPath> { struct ParamsDeserializer<'de, T: ResourcePath> {
params: PathIter<'de, T>, params: PathIter<'de, T>,
current: Option<(&'de str, &'de str)>, current: Option<(&'de str, &'de str)>,
} }
impl<'de, T: RequestPath> de::MapAccess<'de> for ParamsDeserializer<'de, T> { impl<'de, T: ResourcePath> de::MapAccess<'de> for ParamsDeserializer<'de, T> {
type Error = de::value::Error; type Error = de::value::Error;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error> fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
@ -406,11 +406,11 @@ impl<'de> Deserializer<'de> for Value<'de> {
unsupported_type!(deserialize_identifier, "identifier"); unsupported_type!(deserialize_identifier, "identifier");
} }
struct ParamsSeq<'de, T: RequestPath> { struct ParamsSeq<'de, T: ResourcePath> {
params: PathIter<'de, T>, params: PathIter<'de, T>,
} }
impl<'de, T: RequestPath> de::SeqAccess<'de> for ParamsSeq<'de, T> { impl<'de, T: ResourcePath> de::SeqAccess<'de> for ParamsSeq<'de, T> {
type Error = de::value::Error; type Error = de::value::Error;
fn next_element_seed<U>(&mut self, seed: U) -> Result<Option<U::Value>, Self::Error> fn next_element_seed<U>(&mut self, seed: U) -> Result<Option<U::Value>, Self::Error>

View File

@ -1,31 +1,31 @@
//! Resource path matching library. //! Resource path matching library.
mod de; mod de;
mod path; mod path;
mod pattern; mod resource;
mod router; mod router;
pub use self::de::PathDeserializer; pub use self::de::PathDeserializer;
pub use self::path::Path; pub use self::path::Path;
pub use self::pattern::Pattern; pub use self::resource::ResourceDef;
pub use self::router::{ResourceInfo, Router, RouterBuilder}; pub use self::router::{ResourceInfo, Router, RouterBuilder};
pub trait RequestPath { pub trait ResourcePath {
fn path(&self) -> &str; fn path(&self) -> &str;
} }
impl RequestPath for String { impl ResourcePath for String {
fn path(&self) -> &str { fn path(&self) -> &str {
self.as_str() self.as_str()
} }
} }
impl<'a> RequestPath for &'a str { impl<'a> ResourcePath for &'a str {
fn path(&self) -> &str { fn path(&self) -> &str {
self self
} }
} }
impl<T: AsRef<[u8]>> RequestPath for string::String<T> { impl<T: AsRef<[u8]>> ResourcePath for string::String<T> {
fn path(&self) -> &str { fn path(&self) -> &str {
&*self &*self
} }
@ -39,10 +39,10 @@ pub use self::url::Url;
#[cfg(feature = "http")] #[cfg(feature = "http")]
mod http_support { mod http_support {
use super::RequestPath; use super::ResourcePath;
use http::Uri; use http::Uri;
impl RequestPath for Uri { impl ResourcePath for Uri {
fn path(&self) -> &str { fn path(&self) -> &str {
self.path() self.path()
} }

View File

@ -4,7 +4,7 @@ use std::rc::Rc;
use serde::de; use serde::de;
use crate::de::PathDeserializer; use crate::de::PathDeserializer;
use crate::RequestPath; use crate::ResourcePath;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) enum PathItem { pub(crate) enum PathItem {
@ -42,7 +42,7 @@ impl<T: Clone> Clone for Path<T> {
} }
} }
impl<T: RequestPath> Path<T> { impl<T: ResourcePath> Path<T> {
pub fn new(path: T) -> Path<T> { pub fn new(path: T) -> Path<T> {
Path { Path {
path, path,
@ -165,7 +165,7 @@ pub struct PathIter<'a, T> {
params: &'a Path<T>, params: &'a Path<T>,
} }
impl<'a, T: RequestPath> Iterator for PathIter<'a, T> { impl<'a, T: ResourcePath> Iterator for PathIter<'a, T> {
type Item = (&'a str, &'a str); type Item = (&'a str, &'a str);
#[inline] #[inline]
@ -183,7 +183,7 @@ impl<'a, T: RequestPath> Iterator for PathIter<'a, T> {
} }
} }
impl<'a, T: RequestPath> Index<&'a str> for Path<T> { impl<'a, T: ResourcePath> Index<&'a str> for Path<T> {
type Output = str; type Output = str;
fn index(&self, name: &'a str) -> &str { fn index(&self, name: &'a str) -> &str {
@ -192,7 +192,7 @@ impl<'a, T: RequestPath> Index<&'a str> for Path<T> {
} }
} }
impl<T: RequestPath> Index<usize> for Path<T> { impl<T: ResourcePath> Index<usize> for Path<T> {
type Output = str; type Output = str;
fn index(&self, idx: usize) -> &str { fn index(&self, idx: usize) -> &str {

View File

@ -5,20 +5,35 @@ use std::rc::Rc;
use regex::{escape, Regex}; use regex::{escape, Regex};
use crate::path::{Path, PathItem}; use crate::path::{Path, PathItem};
use crate::RequestPath; use crate::ResourcePath;
const MAX_DYNAMIC_SEGMENTS: usize = 16; const MAX_DYNAMIC_SEGMENTS: usize = 16;
/// Resource type describes an entry in resources table /// ResourceDef describes an entry in resources table
/// ///
/// Resource pattern can contain only 16 dynamic segments /// Resource definition can contain only 16 dynamic segments
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Pattern { pub struct ResourceDef {
tp: PatternType, tp: PatternType,
rtp: ResourceType,
name: String,
pattern: String, pattern: String,
elements: Vec<PatternElement>, elements: Vec<PatternElement>,
} }
#[derive(Debug, Copy, Clone, PartialEq)]
/// Resource type
pub enum ResourceType {
/// Normal resource
Normal,
/// Resource for application default handler
Default,
/// External resource
External,
/// Unknown resource type
Unset,
}
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
enum PatternElement { enum PatternElement {
Str(String), Str(String),
@ -32,12 +47,12 @@ enum PatternType {
Dynamic(Regex, Vec<Rc<String>>, usize), Dynamic(Regex, Vec<Rc<String>>, usize),
} }
impl Pattern { impl ResourceDef {
/// Parse path pattern and create new `Pattern` instance. /// Parse path pattern and create new `Pattern` instance.
/// ///
/// Panics if path pattern is wrong. /// Panics if path pattern is wrong.
pub fn new(path: &str) -> Self { pub fn new(path: &str) -> Self {
Pattern::with_prefix(path, false) ResourceDef::with_prefix(path, false)
} }
/// Parse path pattern and create new `Pattern` instance. /// Parse path pattern and create new `Pattern` instance.
@ -46,13 +61,22 @@ impl Pattern {
/// ///
/// Panics if path regex pattern is wrong. /// Panics if path regex pattern is wrong.
pub fn prefix(path: &str) -> Self { pub fn prefix(path: &str) -> Self {
Pattern::with_prefix(path, true) ResourceDef::with_prefix(path, true)
}
/// Construct external resource def
///
/// Panics if path pattern is malformed.
pub fn external(path: &str) -> Self {
let mut resource = ResourceDef::with_prefix(path, false);
resource.rtp = ResourceType::External;
resource
} }
/// Parse path pattern and create new `Pattern` instance with custom prefix /// Parse path pattern and create new `Pattern` instance with custom prefix
fn with_prefix(path: &str, for_prefix: bool) -> Self { fn with_prefix(path: &str, for_prefix: bool) -> Self {
let path = path.to_owned(); let path = path.to_owned();
let (pattern, elements, is_dynamic, len) = Pattern::parse(&path, for_prefix); let (pattern, elements, is_dynamic, len) = ResourceDef::parse(&path, for_prefix);
let tp = if is_dynamic { let tp = if is_dynamic {
let re = match Regex::new(&pattern) { let re = match Regex::new(&pattern) {
@ -71,9 +95,11 @@ impl Pattern {
PatternType::Static(pattern.clone()) PatternType::Static(pattern.clone())
}; };
Pattern { ResourceDef {
tp, tp,
elements, elements,
name: String::new(),
rtp: ResourceType::Normal,
pattern: path.to_owned(), pattern: path.to_owned(),
} }
} }
@ -93,7 +119,7 @@ impl Pattern {
} }
/// 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: RequestPath>(&self, path: &mut Path<T>) -> bool { pub fn match_path<T: ResourcePath>(&self, path: &mut Path<T>) -> bool {
match self.tp { match self.tp {
PatternType::Static(ref s) => { PatternType::Static(ref s) => {
if s == path.path() { if s == path.path() {
@ -261,20 +287,32 @@ impl Pattern {
} }
} }
impl PartialEq for Pattern { impl Eq for ResourceDef {}
fn eq(&self, other: &Pattern) -> bool {
impl PartialEq for ResourceDef {
fn eq(&self, other: &ResourceDef) -> bool {
self.pattern == other.pattern self.pattern == other.pattern
} }
} }
impl Eq for Pattern {} impl Hash for ResourceDef {
impl Hash for Pattern {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
self.pattern.hash(state); self.pattern.hash(state);
} }
} }
impl<'a> From<&'a str> for ResourceDef {
fn from(path: &'a str) -> ResourceDef {
ResourceDef::new(path)
}
}
impl From<String> for ResourceDef {
fn from(path: String) -> ResourceDef {
ResourceDef::new(&path)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -282,29 +320,29 @@ mod tests {
#[test] #[test]
fn test_parse_static() { fn test_parse_static() {
let re = Pattern::new("/"); let re = ResourceDef::new("/");
assert!(re.is_match("/")); assert!(re.is_match("/"));
assert!(!re.is_match("/a")); assert!(!re.is_match("/a"));
let re = Pattern::new("/name"); let re = ResourceDef::new("/name");
assert!(re.is_match("/name")); assert!(re.is_match("/name"));
assert!(!re.is_match("/name1")); assert!(!re.is_match("/name1"));
assert!(!re.is_match("/name/")); assert!(!re.is_match("/name/"));
assert!(!re.is_match("/name~")); assert!(!re.is_match("/name~"));
let re = Pattern::new("/name/"); let re = ResourceDef::new("/name/");
assert!(re.is_match("/name/")); assert!(re.is_match("/name/"));
assert!(!re.is_match("/name")); assert!(!re.is_match("/name"));
assert!(!re.is_match("/name/gs")); assert!(!re.is_match("/name/gs"));
let re = Pattern::new("/user/profile"); let re = ResourceDef::new("/user/profile");
assert!(re.is_match("/user/profile")); assert!(re.is_match("/user/profile"));
assert!(!re.is_match("/user/profile/profile")); assert!(!re.is_match("/user/profile/profile"));
} }
#[test] #[test]
fn test_parse_param() { fn test_parse_param() {
let re = Pattern::new("/user/{id}"); let re = ResourceDef::new("/user/{id}");
assert!(re.is_match("/user/profile")); assert!(re.is_match("/user/profile"));
assert!(re.is_match("/user/2345")); assert!(re.is_match("/user/2345"));
assert!(!re.is_match("/user/2345/")); assert!(!re.is_match("/user/2345/"));
@ -318,7 +356,7 @@ mod tests {
assert!(re.match_path(&mut path)); assert!(re.match_path(&mut path));
assert_eq!(path.get("id").unwrap(), "1245125"); assert_eq!(path.get("id").unwrap(), "1245125");
let re = Pattern::new("/v{version}/resource/{id}"); let re = ResourceDef::new("/v{version}/resource/{id}");
assert!(re.is_match("/v1/resource/320120")); assert!(re.is_match("/v1/resource/320120"));
assert!(!re.is_match("/v/resource/1")); assert!(!re.is_match("/v/resource/1"));
assert!(!re.is_match("/resource")); assert!(!re.is_match("/resource"));
@ -328,7 +366,7 @@ mod tests {
assert_eq!(path.get("version").unwrap(), "151"); assert_eq!(path.get("version").unwrap(), "151");
assert_eq!(path.get("id").unwrap(), "adahg32"); assert_eq!(path.get("id").unwrap(), "adahg32");
let re = Pattern::new("/{id:[[:digit:]]{6}}"); let re = ResourceDef::new("/{id:[[:digit:]]{6}}");
assert!(re.is_match("/012345")); assert!(re.is_match("/012345"));
assert!(!re.is_match("/012")); assert!(!re.is_match("/012"));
assert!(!re.is_match("/01234567")); assert!(!re.is_match("/01234567"));
@ -341,7 +379,7 @@ mod tests {
#[test] #[test]
fn test_parse_urlencoded_param() { fn test_parse_urlencoded_param() {
let re = Pattern::new("/user/{id}/test"); let re = ResourceDef::new("/user/{id}/test");
let mut path = Path::new("/user/2345/test"); let mut path = Path::new("/user/2345/test");
assert!(re.match_path(&mut path)); assert!(re.match_path(&mut path));
@ -359,14 +397,14 @@ mod tests {
#[test] #[test]
fn test_resource_prefix() { fn test_resource_prefix() {
let re = Pattern::prefix("/name"); let re = ResourceDef::prefix("/name");
assert!(re.is_match("/name")); assert!(re.is_match("/name"));
assert!(re.is_match("/name/")); assert!(re.is_match("/name/"));
assert!(re.is_match("/name/test/test")); assert!(re.is_match("/name/test/test"));
assert!(re.is_match("/name1")); assert!(re.is_match("/name1"));
assert!(re.is_match("/name~")); assert!(re.is_match("/name~"));
let re = Pattern::prefix("/name/"); let re = ResourceDef::prefix("/name/");
assert!(re.is_match("/name/")); assert!(re.is_match("/name/"));
assert!(re.is_match("/name/gs")); assert!(re.is_match("/name/gs"));
assert!(!re.is_match("/name")); assert!(!re.is_match("/name"));
@ -374,7 +412,7 @@ mod tests {
#[test] #[test]
fn test_reousrce_prefix_dynamic() { fn test_reousrce_prefix_dynamic() {
let re = Pattern::prefix("/{name}/"); let re = ResourceDef::prefix("/{name}/");
assert!(re.is_match("/name/")); assert!(re.is_match("/name/"));
assert!(re.is_match("/name/gs")); assert!(re.is_match("/name/gs"));
assert!(!re.is_match("/name")); assert!(!re.is_match("/name"));

View File

@ -2,8 +2,8 @@ use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use crate::path::Path; use crate::path::Path;
use crate::pattern::Pattern; use crate::resource::ResourceDef;
use crate::RequestPath; use crate::ResourcePath;
#[derive(Debug, Copy, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq)]
pub(crate) enum ResourceId { pub(crate) enum ResourceId {
@ -20,15 +20,15 @@ pub struct ResourceInfo {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub(crate) struct ResourceMap { pub(crate) struct ResourceMap {
root: Option<Pattern>, root: Option<ResourceDef>,
named: HashMap<String, Pattern>, named: HashMap<String, ResourceDef>,
patterns: Vec<Pattern>, patterns: Vec<ResourceDef>,
} }
/// Resource router. /// Resource router.
pub struct Router<T> { pub struct Router<T> {
rmap: Rc<ResourceMap>, rmap: Rc<ResourceMap>,
named: HashMap<String, Pattern>, named: HashMap<String, ResourceDef>,
resources: Vec<T>, resources: Vec<T>,
} }
@ -41,7 +41,7 @@ impl<T> Router<T> {
} }
} }
pub fn recognize<U: RequestPath>(&self, path: &mut Path<U>) -> Option<(&T, ResourceInfo)> { pub fn recognize<U: ResourcePath>(&self, path: &mut Path<U>) -> Option<(&T, ResourceInfo)> {
if !path.path().is_empty() { if !path.path().is_empty() {
for (idx, resource) in self.rmap.patterns.iter().enumerate() { for (idx, resource) in self.rmap.patterns.iter().enumerate() {
if resource.match_path(path) { if resource.match_path(path) {
@ -56,7 +56,7 @@ impl<T> Router<T> {
None None
} }
pub fn recognize_mut<U: RequestPath>( pub fn recognize_mut<U: ResourcePath>(
&mut self, &mut self,
path: &mut Path<U>, path: &mut Path<U>,
) -> Option<(&mut T, ResourceInfo)> { ) -> Option<(&mut T, ResourceInfo)> {
@ -94,11 +94,11 @@ impl<'a, T> IntoIterator for &'a mut Router<T> {
} }
impl ResourceMap { impl ResourceMap {
fn register(&mut self, pattern: Pattern) { fn register(&mut self, pattern: ResourceDef) {
self.patterns.push(pattern); self.patterns.push(pattern);
} }
fn register_named(&mut self, name: String, pattern: Pattern) { fn register_named(&mut self, name: String, pattern: ResourceDef) {
self.patterns.push(pattern.clone()); self.patterns.push(pattern.clone());
self.named.insert(name, pattern); self.named.insert(name, pattern);
} }
@ -110,18 +110,18 @@ impl ResourceMap {
pub struct RouterBuilder<T> { pub struct RouterBuilder<T> {
rmap: ResourceMap, rmap: ResourceMap,
named: HashMap<String, Pattern>, named: HashMap<String, ResourceDef>,
resources: Vec<T>, resources: Vec<T>,
} }
impl<T> RouterBuilder<T> { impl<T> RouterBuilder<T> {
pub fn path(&mut self, path: &str, resource: T) { pub fn path(&mut self, path: &str, resource: T) {
self.rmap.register(Pattern::new(path)); self.rmap.register(ResourceDef::new(path));
self.resources.push(resource); self.resources.push(resource);
} }
pub fn prefix(&mut self, prefix: &str, resource: T) { pub fn prefix(&mut self, prefix: &str, resource: T) {
self.rmap.register(Pattern::prefix(prefix)); self.rmap.register(ResourceDef::prefix(prefix));
self.resources.push(resource); self.resources.push(resource);
} }

View File

@ -1,6 +1,6 @@
use std::rc::Rc; use std::rc::Rc;
use crate::RequestPath; use crate::ResourcePath;
#[allow(dead_code)] #[allow(dead_code)]
const GEN_DELIMS: &[u8] = b":/?#[]@"; const GEN_DELIMS: &[u8] = b":/?#[]@";
@ -67,7 +67,7 @@ impl Url {
} }
} }
impl RequestPath for Url { impl ResourcePath for Url {
fn path(&self) -> &str { fn path(&self) -> &str {
self.path() self.path()
} }
@ -190,11 +190,11 @@ mod tests {
use http::{HttpTryFrom, Uri}; use http::{HttpTryFrom, Uri};
use super::*; use super::*;
use crate::{Path, Pattern}; use crate::{Path, ResourceDef};
#[test] #[test]
fn test_parse_url() { fn test_parse_url() {
let re = Pattern::new("/user/{id}/test"); let re = ResourceDef::new("/user/{id}/test");
let url = Uri::try_from("/user/2345/test").unwrap(); let url = Uri::try_from("/user/2345/test").unwrap();
let mut path = Path::new(Url::new(url)); let mut path = Path::new(Url::new(url));