mirror of
https://github.com/fafhrd91/actix-net
synced 2024-11-30 21:04:35 +01:00
allow custom checks for resource selection
This commit is contained in:
parent
fb43940824
commit
0ff0daa795
@ -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::Resource;
|
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: Resource + 'de> {
|
pub struct PathDeserializer<'de, T: ResourcePath + 'de> {
|
||||||
path: &'de Path<T>,
|
path: &'de Path<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de, T: Resource + '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: Resource + '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: Resource + '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: Resource> {
|
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: Resource> 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: Resource> {
|
struct ParamsSeq<'de, T: ResourcePath> {
|
||||||
params: PathIter<'de, T>,
|
params: PathIter<'de, T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de, T: Resource> 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>
|
||||||
|
@ -9,23 +9,27 @@ pub use self::path::Path;
|
|||||||
pub use self::resource::ResourceDef;
|
pub use self::resource::ResourceDef;
|
||||||
pub use self::router::{ResourceInfo, Router, RouterBuilder};
|
pub use self::router::{ResourceInfo, Router, RouterBuilder};
|
||||||
|
|
||||||
pub trait Resource {
|
pub trait Resource<T: ResourcePath> {
|
||||||
|
fn resource_path(&mut self) -> &mut Path<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ResourcePath {
|
||||||
fn path(&self) -> &str;
|
fn path(&self) -> &str;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Resource for String {
|
impl ResourcePath for String {
|
||||||
fn path(&self) -> &str {
|
fn path(&self) -> &str {
|
||||||
self.as_str()
|
self.as_str()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Resource for &'a str {
|
impl<'a> ResourcePath for &'a str {
|
||||||
fn path(&self) -> &str {
|
fn path(&self) -> &str {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: AsRef<[u8]>> Resource 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 +43,10 @@ pub use self::url::Url;
|
|||||||
|
|
||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
mod http_support {
|
mod http_support {
|
||||||
use super::Resource;
|
use super::ResourcePath;
|
||||||
use http::Uri;
|
use http::Uri;
|
||||||
|
|
||||||
impl Resource for Uri {
|
impl ResourcePath for Uri {
|
||||||
fn path(&self) -> &str {
|
fn path(&self) -> &str {
|
||||||
self.path()
|
self.path()
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use std::rc::Rc;
|
|||||||
use serde::de;
|
use serde::de;
|
||||||
|
|
||||||
use crate::de::PathDeserializer;
|
use crate::de::PathDeserializer;
|
||||||
use crate::Resource;
|
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: Resource> 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: Resource> 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: Resource> Iterator for PathIter<'a, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: Resource> 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: Resource> Index<&'a str> for Path<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Resource> 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 {
|
||||||
|
@ -5,7 +5,7 @@ use std::rc::Rc;
|
|||||||
use regex::{escape, Regex};
|
use regex::{escape, Regex};
|
||||||
|
|
||||||
use crate::path::{Path, PathItem};
|
use crate::path::{Path, PathItem};
|
||||||
use crate::Resource;
|
use crate::ResourcePath;
|
||||||
|
|
||||||
const MAX_DYNAMIC_SEGMENTS: usize = 16;
|
const MAX_DYNAMIC_SEGMENTS: usize = 16;
|
||||||
|
|
||||||
@ -119,7 +119,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: Resource>(&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() {
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::path::Path;
|
|
||||||
use crate::resource::ResourceDef;
|
use crate::resource::ResourceDef;
|
||||||
use crate::Resource;
|
use crate::{Resource, ResourcePath};
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub(crate) enum ResourceId {
|
pub(crate) enum ResourceId {
|
||||||
@ -26,14 +25,14 @@ pub(crate) struct ResourceMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Resource router.
|
/// Resource router.
|
||||||
pub struct Router<T> {
|
pub struct Router<T, U = ()> {
|
||||||
rmap: Rc<ResourceMap>,
|
rmap: Rc<ResourceMap>,
|
||||||
named: HashMap<String, ResourceDef>,
|
named: HashMap<String, ResourceDef>,
|
||||||
resources: Vec<T>,
|
resources: Vec<(T, Option<U>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Router<T> {
|
impl<T, U> Router<T, U> {
|
||||||
pub fn build() -> RouterBuilder<T> {
|
pub fn build() -> RouterBuilder<T, U> {
|
||||||
RouterBuilder {
|
RouterBuilder {
|
||||||
rmap: ResourceMap::default(),
|
rmap: ResourceMap::default(),
|
||||||
named: HashMap::new(),
|
named: HashMap::new(),
|
||||||
@ -41,48 +40,71 @@ impl<T> Router<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recognize<U: Resource>(&self, path: &mut Path<U>) -> Option<(&T, ResourceInfo)> {
|
pub fn recognize<R: Resource<P>, P: ResourcePath>(
|
||||||
|
&self,
|
||||||
|
res: &mut R,
|
||||||
|
) -> Option<(&T, ResourceInfo)> {
|
||||||
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(res.resource_path()) {
|
||||||
let info = ResourceInfo {
|
let info = ResourceInfo {
|
||||||
rmap: self.rmap.clone(),
|
rmap: self.rmap.clone(),
|
||||||
resource: ResourceId::Normal(idx as u16),
|
resource: ResourceId::Normal(idx as u16),
|
||||||
};
|
};
|
||||||
return Some((&self.resources[idx], info));
|
return Some((&self.resources[idx].0, info));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recognize_mut<U: Resource>(
|
pub fn recognize_mut<R: Resource<P>, P: ResourcePath>(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: &mut Path<U>,
|
res: &mut R,
|
||||||
) -> Option<(&mut T, ResourceInfo)> {
|
) -> Option<(&mut T, ResourceInfo)> {
|
||||||
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(res.resource_path()) {
|
||||||
let info = ResourceInfo {
|
let info = ResourceInfo {
|
||||||
rmap: self.rmap.clone(),
|
rmap: self.rmap.clone(),
|
||||||
resource: ResourceId::Normal(idx as u16),
|
resource: ResourceId::Normal(idx as u16),
|
||||||
};
|
};
|
||||||
return Some((&mut self.resources[idx], info));
|
return Some((&mut self.resources[idx].0, info));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn recognize_mut_checked<R: Resource<P>, P: ResourcePath, F>(
|
||||||
|
&mut self,
|
||||||
|
res: &mut R,
|
||||||
|
check: F,
|
||||||
|
) -> Option<(&mut T, ResourceInfo)>
|
||||||
|
where
|
||||||
|
F: Fn(&R, &Option<U>) -> bool,
|
||||||
|
{
|
||||||
|
for (idx, resource) in self.rmap.patterns.iter().enumerate() {
|
||||||
|
if resource.match_path(res.resource_path()) && check(res, &self.resources[idx].1) {
|
||||||
|
let info = ResourceInfo {
|
||||||
|
rmap: self.rmap.clone(),
|
||||||
|
resource: ResourceId::Normal(idx as u16),
|
||||||
|
};
|
||||||
|
return Some((&mut self.resources[idx].0, info));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> IntoIterator for &'a Router<T> {
|
impl<'a, T, U> IntoIterator for &'a Router<T, U> {
|
||||||
type Item = &'a T;
|
type Item = &'a (T, Option<U>);
|
||||||
type IntoIter = std::slice::Iter<'a, T>;
|
type IntoIter = std::slice::Iter<'a, (T, Option<U>)>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
self.resources.iter()
|
self.resources.iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> IntoIterator for &'a mut Router<T> {
|
impl<'a, T, U> IntoIterator for &'a mut Router<T, U> {
|
||||||
type Item = &'a mut T;
|
type Item = &'a mut (T, Option<U>);
|
||||||
type IntoIter = std::slice::IterMut<'a, T>;
|
type IntoIter = std::slice::IterMut<'a, (T, Option<U>)>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
self.resources.iter_mut()
|
self.resources.iter_mut()
|
||||||
@ -104,33 +126,40 @@ impl ResourceMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RouterBuilder<T> {
|
pub struct RouterBuilder<T, U> {
|
||||||
rmap: ResourceMap,
|
rmap: ResourceMap,
|
||||||
named: HashMap<String, ResourceDef>,
|
named: HashMap<String, ResourceDef>,
|
||||||
resources: Vec<T>,
|
resources: Vec<(T, Option<U>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> RouterBuilder<T> {
|
impl<T, U> RouterBuilder<T, U> {
|
||||||
/// Register resource for specified path.
|
/// Register resource for specified path.
|
||||||
pub fn path(&mut self, path: &str, resource: T) {
|
pub fn path(&mut self, path: &str, resource: T) {
|
||||||
self.rmap.register(ResourceDef::new(path));
|
self.rmap.register(ResourceDef::new(path));
|
||||||
self.resources.push(resource);
|
self.resources.push((resource, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register resource for specified path prefix.
|
/// Register resource for specified path prefix.
|
||||||
pub fn prefix(&mut self, prefix: &str, resource: T) {
|
pub fn prefix(&mut self, prefix: &str, resource: T) {
|
||||||
self.rmap.register(ResourceDef::prefix(prefix));
|
self.rmap.register(ResourceDef::prefix(prefix));
|
||||||
self.resources.push(resource);
|
self.resources.push((resource, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register resource for ResourceDef
|
/// Register resource for ResourceDef
|
||||||
pub fn rdef(&mut self, rdef: ResourceDef, resource: T) {
|
pub fn rdef(&mut self, rdef: ResourceDef, resource: T) {
|
||||||
self.rmap.register(rdef);
|
self.rmap.register(rdef);
|
||||||
self.resources.push(resource);
|
self.resources.push((resource, None));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Method attachs user data to lastly added resource.
|
||||||
|
///
|
||||||
|
/// This panics if no resources were added.
|
||||||
|
pub fn set_user_data(&mut self, userdata: Option<U>) {
|
||||||
|
self.resources.last_mut().unwrap().1 = userdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finish configuration and create router instance.
|
/// Finish configuration and create router instance.
|
||||||
pub fn finish(self) -> Router<T> {
|
pub fn finish(self) -> Router<T, U> {
|
||||||
Router {
|
Router {
|
||||||
rmap: Rc::new(self.rmap),
|
rmap: Rc::new(self.rmap),
|
||||||
named: self.named,
|
named: self.named,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::Resource;
|
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 Resource for Url {
|
impl ResourcePath for Url {
|
||||||
fn path(&self) -> &str {
|
fn path(&self) -> &str {
|
||||||
self.path()
|
self.path()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user