mirror of
https://github.com/fafhrd91/actix-net
synced 2025-08-13 11:58:23 +02:00
Compare commits
3 Commits
router-v0.
...
utils-v1.0
Author | SHA1 | Date | |
---|---|---|---|
|
9f00daea80 | ||
|
7dddeab2a8 | ||
|
dcbcc40da2 |
@@ -1,5 +1,11 @@
|
||||
# Changes
|
||||
|
||||
## [1.0.5] - 2020-01-08
|
||||
|
||||
* Add `Condition` type.
|
||||
|
||||
* Add `Pool` of one-shot's.
|
||||
|
||||
## [1.0.4] - 2019-12-20
|
||||
|
||||
* Add methods to check `LocalWaker` registration state.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "actix-utils"
|
||||
version = "1.0.4"
|
||||
version = "1.0.5"
|
||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||
description = "Actix utils - various actix net related services"
|
||||
keywords = ["network", "framework", "async", "futures"]
|
||||
@@ -16,11 +16,13 @@ name = "actix_utils"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
actix-service = "1.0.0"
|
||||
actix-service = "1.0.1"
|
||||
actix-rt = "1.0.0"
|
||||
actix-codec = "0.2.0"
|
||||
bitflags = "1.2"
|
||||
bytes = "0.5.3"
|
||||
either = "1.5.3"
|
||||
futures = "0.3.1"
|
||||
pin-project = "0.4.6"
|
||||
log = "0.4"
|
||||
slab = "0.4"
|
||||
|
104
actix-utils/src/condition.rs
Normal file
104
actix-utils/src/condition.rs
Normal file
@@ -0,0 +1,104 @@
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use slab::Slab;
|
||||
|
||||
use crate::cell::Cell;
|
||||
use crate::task::LocalWaker;
|
||||
|
||||
/// Condition allows to notify multiple receivers at the same time
|
||||
pub struct Condition(Cell<Inner>);
|
||||
|
||||
struct Inner {
|
||||
data: Slab<Option<LocalWaker>>,
|
||||
}
|
||||
|
||||
impl Condition {
|
||||
pub fn new() -> Condition {
|
||||
Condition(Cell::new(Inner { data: Slab::new() }))
|
||||
}
|
||||
|
||||
/// Get condition waiter
|
||||
pub fn wait(&mut self) -> Waiter {
|
||||
let token = self.0.get_mut().data.insert(None);
|
||||
Waiter {
|
||||
token,
|
||||
inner: self.0.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Notify all waiters
|
||||
pub fn notify(&self) {
|
||||
let inner = self.0.get_ref();
|
||||
for item in inner.data.iter() {
|
||||
if let Some(waker) = item.1 {
|
||||
waker.wake();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Condition {
|
||||
fn drop(&mut self) {
|
||||
self.notify()
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use = "Waiter do nothing unless polled"]
|
||||
pub struct Waiter {
|
||||
token: usize,
|
||||
inner: Cell<Inner>,
|
||||
}
|
||||
|
||||
impl Future for Waiter {
|
||||
type Output = ();
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.get_mut();
|
||||
|
||||
let inner = unsafe { this.inner.get_mut().data.get_unchecked_mut(this.token) };
|
||||
if inner.is_none() {
|
||||
let waker = LocalWaker::default();
|
||||
waker.register(cx.waker());
|
||||
*inner = Some(waker);
|
||||
Poll::Pending
|
||||
} else if inner.as_mut().unwrap().register(cx.waker()) {
|
||||
Poll::Pending
|
||||
} else {
|
||||
Poll::Ready(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Waiter {
|
||||
fn drop(&mut self) {
|
||||
self.inner.get_mut().data.remove(self.token);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use futures::future::lazy;
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_condition() {
|
||||
let mut cond = Condition::new();
|
||||
let mut waiter = cond.wait();
|
||||
assert_eq!(
|
||||
lazy(|cx| Pin::new(&mut waiter).poll(cx)).await,
|
||||
Poll::Pending
|
||||
);
|
||||
cond.notify();
|
||||
assert_eq!(waiter.await, ());
|
||||
|
||||
let mut waiter = cond.wait();
|
||||
assert_eq!(
|
||||
lazy(|cx| Pin::new(&mut waiter).poll(cx)).await,
|
||||
Poll::Pending
|
||||
);
|
||||
drop(cond);
|
||||
assert_eq!(waiter.await, ());
|
||||
}
|
||||
}
|
@@ -3,6 +3,7 @@
|
||||
#![allow(clippy::type_complexity)]
|
||||
|
||||
mod cell;
|
||||
pub mod condition;
|
||||
pub mod counter;
|
||||
pub mod either;
|
||||
pub mod framed;
|
||||
|
@@ -4,6 +4,7 @@ use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
pub use futures::channel::oneshot::Canceled;
|
||||
use slab::Slab;
|
||||
|
||||
use crate::cell::Cell;
|
||||
use crate::task::LocalWaker;
|
||||
@@ -21,6 +22,11 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
|
||||
(tx, rx)
|
||||
}
|
||||
|
||||
/// Creates a new futures-aware, pool of one-shot's.
|
||||
pub fn pool<T>() -> Pool<T> {
|
||||
Pool(Cell::new(Slab::new()))
|
||||
}
|
||||
|
||||
/// Represents the completion half of a oneshot through which the result of a
|
||||
/// computation is signaled.
|
||||
#[derive(Debug)]
|
||||
@@ -77,9 +83,7 @@ impl<T> Sender<T> {
|
||||
|
||||
impl<T> Drop for Sender<T> {
|
||||
fn drop(&mut self) {
|
||||
if self.inner.strong_count() == 2 {
|
||||
self.inner.get_ref().rx_task.wake();
|
||||
};
|
||||
self.inner.get_ref().rx_task.wake();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +108,148 @@ impl<T> Future for Receiver<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Futures-aware, pool of one-shot's.
|
||||
pub struct Pool<T>(Cell<Slab<PoolInner<T>>>);
|
||||
|
||||
bitflags::bitflags! {
|
||||
pub struct Flags: u8 {
|
||||
const SENDER = 0b0000_0001;
|
||||
const RECEIVER = 0b0000_0010;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PoolInner<T> {
|
||||
flags: Flags,
|
||||
value: Option<T>,
|
||||
waker: LocalWaker,
|
||||
}
|
||||
|
||||
impl<T> Pool<T> {
|
||||
pub fn channel(&mut self) -> (PSender<T>, PReceiver<T>) {
|
||||
let token = self.0.get_mut().insert(PoolInner {
|
||||
flags: Flags::all(),
|
||||
value: None,
|
||||
waker: LocalWaker::default(),
|
||||
});
|
||||
|
||||
(
|
||||
PSender {
|
||||
token,
|
||||
inner: self.0.clone(),
|
||||
},
|
||||
PReceiver {
|
||||
token,
|
||||
inner: self.0.clone(),
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for Pool<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Pool(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the completion half of a oneshot through which the result of a
|
||||
/// computation is signaled.
|
||||
#[derive(Debug)]
|
||||
pub struct PSender<T> {
|
||||
token: usize,
|
||||
inner: Cell<Slab<PoolInner<T>>>,
|
||||
}
|
||||
|
||||
/// A future representing the completion of a computation happening elsewhere in
|
||||
/// memory.
|
||||
#[derive(Debug)]
|
||||
#[must_use = "futures do nothing unless polled"]
|
||||
pub struct PReceiver<T> {
|
||||
token: usize,
|
||||
inner: Cell<Slab<PoolInner<T>>>,
|
||||
}
|
||||
|
||||
// The oneshots do not ever project Pin to the inner T
|
||||
impl<T> Unpin for PReceiver<T> {}
|
||||
impl<T> Unpin for PSender<T> {}
|
||||
|
||||
impl<T> PSender<T> {
|
||||
/// Completes this oneshot with a successful result.
|
||||
///
|
||||
/// This function will consume `self` and indicate to the other end, the
|
||||
/// `Receiver`, that the error provided is the result of the computation this
|
||||
/// represents.
|
||||
///
|
||||
/// If the value is successfully enqueued for the remote end to receive,
|
||||
/// then `Ok(())` is returned. If the receiving end was dropped before
|
||||
/// this function was called, however, then `Err` is returned with the value
|
||||
/// provided.
|
||||
pub fn send(mut self, val: T) -> Result<(), T> {
|
||||
let inner = unsafe { self.inner.get_mut().get_unchecked_mut(self.token) };
|
||||
|
||||
if inner.flags.contains(Flags::RECEIVER) {
|
||||
inner.value = Some(val);
|
||||
inner.waker.wake();
|
||||
Ok(())
|
||||
} else {
|
||||
Err(val)
|
||||
}
|
||||
}
|
||||
|
||||
/// Tests to see whether this `Sender`'s corresponding `Receiver`
|
||||
/// has gone away.
|
||||
pub fn is_canceled(&self) -> bool {
|
||||
!unsafe { self.inner.get_ref().get_unchecked(self.token) }
|
||||
.flags
|
||||
.contains(Flags::RECEIVER)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for PSender<T> {
|
||||
fn drop(&mut self) {
|
||||
let inner = unsafe { self.inner.get_mut().get_unchecked_mut(self.token) };
|
||||
if inner.flags.contains(Flags::RECEIVER) {
|
||||
inner.waker.wake();
|
||||
inner.flags.remove(Flags::SENDER);
|
||||
} else {
|
||||
self.inner.get_mut().remove(self.token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for PReceiver<T> {
|
||||
fn drop(&mut self) {
|
||||
let inner = unsafe { self.inner.get_mut().get_unchecked_mut(self.token) };
|
||||
if inner.flags.contains(Flags::SENDER) {
|
||||
inner.flags.remove(Flags::RECEIVER);
|
||||
} else {
|
||||
self.inner.get_mut().remove(self.token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Future for PReceiver<T> {
|
||||
type Output = Result<T, Canceled>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.get_mut();
|
||||
let inner = unsafe { this.inner.get_mut().get_unchecked_mut(this.token) };
|
||||
|
||||
// If we've got a value, then skip the logic below as we're done.
|
||||
if let Some(val) = inner.value.take() {
|
||||
return Poll::Ready(Ok(val));
|
||||
}
|
||||
|
||||
// Check if sender is dropped and return error if it is.
|
||||
if !inner.flags.contains(Flags::SENDER) {
|
||||
Poll::Ready(Err(Canceled))
|
||||
} else {
|
||||
inner.waker.register(cx.waker());
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -135,4 +281,31 @@ mod tests {
|
||||
drop(tx);
|
||||
assert!(rx.await.is_err());
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_pool() {
|
||||
let (tx, rx) = pool().channel();
|
||||
tx.send("test").unwrap();
|
||||
assert_eq!(rx.await.unwrap(), "test");
|
||||
|
||||
let (tx, rx) = pool().channel();
|
||||
assert!(!tx.is_canceled());
|
||||
drop(rx);
|
||||
assert!(tx.is_canceled());
|
||||
assert!(tx.send("test").is_err());
|
||||
|
||||
let (tx, rx) = pool::<&'static str>().channel();
|
||||
drop(tx);
|
||||
assert!(rx.await.is_err());
|
||||
|
||||
let (tx, mut rx) = pool::<&'static str>().channel();
|
||||
assert_eq!(lazy(|cx| Pin::new(&mut rx).poll(cx)).await, Poll::Pending);
|
||||
tx.send("test").unwrap();
|
||||
assert_eq!(rx.await.unwrap(), "test");
|
||||
|
||||
let (tx, mut rx) = pool::<&'static str>().channel();
|
||||
assert_eq!(lazy(|cx| Pin::new(&mut rx).poll(cx)).await, Poll::Pending);
|
||||
drop(tx);
|
||||
assert!(rx.await.is_err());
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
# Changes
|
||||
|
||||
## [0.3.0] - 2019-12-31
|
||||
## [0.2.4] - 2019-12-31
|
||||
|
||||
* Support named parameters for `ResourceDef::resource_path()` in form of `((&k, &v), ...)`
|
||||
* Add `ResourceDef::resource_path_named()` path generation method
|
||||
|
||||
## [0.2.3] - 2019-12-25
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "actix-router"
|
||||
version = "0.3.0"
|
||||
version = "0.2.4"
|
||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||
description = "Path router"
|
||||
keywords = ["actix"]
|
||||
@@ -18,11 +18,10 @@ path = "src/lib.rs"
|
||||
default = ["http"]
|
||||
|
||||
[dependencies]
|
||||
bytestring = "0.1.2"
|
||||
either = "1.5.3"
|
||||
regex = "1.3.1"
|
||||
log = "0.4.8"
|
||||
serde = "1.0.104"
|
||||
bytestring = "0.1.2"
|
||||
log = "0.4.8"
|
||||
http = { version="0.2.0", optional=true }
|
||||
|
||||
[dev-dependencies]
|
||||
|
@@ -4,8 +4,6 @@ mod path;
|
||||
mod resource;
|
||||
mod router;
|
||||
|
||||
use either::Either;
|
||||
|
||||
pub use self::de::PathDeserializer;
|
||||
pub use self::path::Path;
|
||||
pub use self::resource::ResourceDef;
|
||||
@@ -37,127 +35,6 @@ impl ResourcePath for bytestring::ByteString {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ResourceElements {
|
||||
fn elements<F, R>(self, for_each: F) -> Option<R>
|
||||
where
|
||||
F: FnMut(Either<&str, (&str, &str)>) -> Option<R>;
|
||||
}
|
||||
|
||||
impl<'a, T: AsRef<str>> ResourceElements for &'a [T] {
|
||||
fn elements<F, R>(self, mut for_each: F) -> Option<R>
|
||||
where
|
||||
F: FnMut(Either<&str, (&str, &str)>) -> Option<R>,
|
||||
{
|
||||
for t in self {
|
||||
if let Some(res) = for_each(Either::Left(t.as_ref())) {
|
||||
return Some(res);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, U, I> ResourceElements for &'a U
|
||||
where
|
||||
&'a U: IntoIterator<Item = I>,
|
||||
I: AsRef<str>,
|
||||
{
|
||||
fn elements<F, R>(self, mut for_each: F) -> Option<R>
|
||||
where
|
||||
F: FnMut(Either<&str, (&str, &str)>) -> Option<R>,
|
||||
{
|
||||
for t in self.into_iter() {
|
||||
if let Some(res) = for_each(Either::Left(t.as_ref())) {
|
||||
return Some(res);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> ResourceElements for Vec<I>
|
||||
where
|
||||
I: AsRef<str>,
|
||||
{
|
||||
fn elements<F, R>(self, mut for_each: F) -> Option<R>
|
||||
where
|
||||
F: FnMut(Either<&str, (&str, &str)>) -> Option<R>,
|
||||
{
|
||||
for t in self.iter() {
|
||||
if let Some(res) = for_each(Either::Left(t.as_ref())) {
|
||||
return Some(res);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V, S> ResourceElements for std::collections::HashMap<K, V, S>
|
||||
where
|
||||
K: AsRef<str>,
|
||||
V: AsRef<str>,
|
||||
S: std::hash::BuildHasher,
|
||||
{
|
||||
fn elements<F, R>(self, mut for_each: F) -> Option<R>
|
||||
where
|
||||
F: FnMut(Either<&str, (&str, &str)>) -> Option<R>,
|
||||
{
|
||||
for t in self.iter() {
|
||||
if let Some(res) = for_each(Either::Right((t.0.as_ref(), t.1.as_ref()))) {
|
||||
return Some(res);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
mod _m {
|
||||
use super::*;
|
||||
// macro_rules! elements_tuple ({ $(($n:tt, $T:ident)),+} => {
|
||||
// impl<$($T: AsRef<str>,)+> ResourceElements for ($($T,)+) {
|
||||
// fn elements<F_, R_>(self, mut for_each: F_) -> Option<R_>
|
||||
// where
|
||||
// F_: FnMut(Either<&str, (&str, &str)>) -> Option<R_>,
|
||||
// {
|
||||
// $(
|
||||
// if let Some(res) = for_each(Either::Left(self.$n.as_ref())) {
|
||||
// return Some(res)
|
||||
// }
|
||||
// )+
|
||||
// None
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
macro_rules! elements_2tuple ({ $(($n:tt, $V:ident)),+} => {
|
||||
impl<'a, $($V: AsRef<str>,)+> ResourceElements for ($((&'a str, $V),)+) {
|
||||
fn elements<F_, R_>(self, mut for_each: F_) -> Option<R_>
|
||||
where
|
||||
F_: FnMut(Either<&str, (&str, &str)>) -> Option<R_>,
|
||||
{
|
||||
$(
|
||||
if let Some(res) = for_each(Either::Right((self.$n.0, self.$n.1.as_ref()))) {
|
||||
return Some(res)
|
||||
}
|
||||
)+
|
||||
None
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
elements_2tuple!((0, A));
|
||||
elements_2tuple!((0, A), (1, B));
|
||||
elements_2tuple!((0, A), (1, B), (2, C));
|
||||
elements_2tuple!((0, A), (1, B), (2, C), (3, D));
|
||||
elements_2tuple!((0, A), (1, B), (2, C), (3, D), (4, E));
|
||||
elements_2tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F));
|
||||
elements_2tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G));
|
||||
elements_2tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H));
|
||||
elements_2tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I));
|
||||
elements_2tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I), (9, J));
|
||||
}
|
||||
|
||||
/// Helper trait for type that could be converted to path pattern
|
||||
pub trait IntoPattern {
|
||||
/// Signle patter
|
||||
|
@@ -5,7 +5,7 @@ use std::hash::{Hash, Hasher};
|
||||
use regex::{escape, Regex, RegexSet};
|
||||
|
||||
use crate::path::{Path, PathItem};
|
||||
use crate::{IntoPattern, Resource, ResourceElements, ResourcePath};
|
||||
use crate::{IntoPattern, Resource, ResourcePath};
|
||||
|
||||
const MAX_DYNAMIC_SEGMENTS: usize = 16;
|
||||
|
||||
@@ -464,66 +464,61 @@ impl ResourceDef {
|
||||
}
|
||||
|
||||
/// Build resource path from elements. Returns `true` on success.
|
||||
pub fn resource_path<U: ResourceElements>(&self, path: &mut String, data: U) -> bool {
|
||||
pub fn resource_path<U, I>(&self, path: &mut String, elements: &mut U) -> bool
|
||||
where
|
||||
U: Iterator<Item = I>,
|
||||
I: AsRef<str>,
|
||||
{
|
||||
match self.tp {
|
||||
PatternType::Prefix(ref p) => path.push_str(p),
|
||||
PatternType::Static(ref p) => path.push_str(p),
|
||||
PatternType::Dynamic(..) => {
|
||||
let mut iter = self.elements.iter();
|
||||
let mut map = HashMap::new();
|
||||
|
||||
let result = data.elements(|item| match item {
|
||||
either::Either::Left(val) => loop {
|
||||
if let Some(el) = iter.next() {
|
||||
match *el {
|
||||
PatternElement::Str(ref s) => path.push_str(s),
|
||||
PatternElement::Var(_) => {
|
||||
path.push_str(val.as_ref());
|
||||
return None;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Some(false);
|
||||
}
|
||||
},
|
||||
either::Either::Right((name, val)) => {
|
||||
map.insert(name.to_string(), val.to_string());
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
if result.is_some() {
|
||||
return true;
|
||||
} else {
|
||||
if map.is_empty() {
|
||||
// push static sections
|
||||
loop {
|
||||
if let Some(el) = iter.next() {
|
||||
match *el {
|
||||
PatternElement::Str(ref s) => path.push_str(s),
|
||||
PatternElement::Var(_) => {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for el in &self.elements {
|
||||
match *el {
|
||||
PatternElement::Str(ref s) => path.push_str(s),
|
||||
PatternElement::Var(_) => {
|
||||
if let Some(val) = elements.next() {
|
||||
path.push_str(val.as_ref())
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for el in iter {
|
||||
match *el {
|
||||
PatternElement::Str(ref s) => path.push_str(s),
|
||||
PatternElement::Var(ref name) => {
|
||||
if let Some(val) = map.get(name) {
|
||||
path.push_str(val);
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PatternType::DynamicSet(..) => {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Build resource path from elements. Returns `true` on success.
|
||||
pub fn resource_path_named<K, V, S>(
|
||||
&self,
|
||||
path: &mut String,
|
||||
elements: &HashMap<K, V, S>,
|
||||
) -> bool
|
||||
where
|
||||
K: std::borrow::Borrow<str> + Eq + Hash,
|
||||
V: AsRef<str>,
|
||||
S: std::hash::BuildHasher,
|
||||
{
|
||||
match self.tp {
|
||||
PatternType::Prefix(ref p) => path.push_str(p),
|
||||
PatternType::Static(ref p) => path.push_str(p),
|
||||
PatternType::Dynamic(..) => {
|
||||
for el in &self.elements {
|
||||
match *el {
|
||||
PatternElement::Str(ref s) => path.push_str(s),
|
||||
PatternElement::Var(ref name) => {
|
||||
if let Some(val) = elements.get(name) {
|
||||
path.push_str(val.as_ref())
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
PatternType::DynamicSet(..) => {
|
||||
@@ -673,7 +668,6 @@ pub(crate) fn insert_slash(path: &str) -> String {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use http::Uri;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
#[test]
|
||||
@@ -905,66 +899,45 @@ mod tests {
|
||||
fn test_resource_path() {
|
||||
let mut s = String::new();
|
||||
let resource = ResourceDef::new("/user/{item1}/test");
|
||||
assert!(resource.resource_path(&mut s, &["user1"]));
|
||||
assert_eq!(s, "/user/user1/test");
|
||||
|
||||
let mut s = String::new();
|
||||
assert!(resource.resource_path(&mut s, (("item1", "user1"),)));
|
||||
assert!(resource.resource_path(&mut s, &mut (&["user1"]).into_iter()));
|
||||
assert_eq!(s, "/user/user1/test");
|
||||
|
||||
let mut s = String::new();
|
||||
let resource = ResourceDef::new("/user/{item1}/{item2}/test");
|
||||
assert!(resource.resource_path(&mut s, &["item", "item2"]));
|
||||
assert_eq!(s, "/user/item/item2/test");
|
||||
|
||||
let mut s = String::new();
|
||||
assert!(resource.resource_path(&mut s, (("item1", "item"), ("item2", "item2"))));
|
||||
assert!(resource.resource_path(&mut s, &mut (&["item", "item2"]).into_iter()));
|
||||
assert_eq!(s, "/user/item/item2/test");
|
||||
|
||||
let mut s = String::new();
|
||||
let resource = ResourceDef::new("/user/{item1}/{item2}");
|
||||
assert!(resource.resource_path(&mut s, &["item", "item2"]));
|
||||
assert_eq!(s, "/user/item/item2");
|
||||
|
||||
let mut s = String::new();
|
||||
assert!(resource.resource_path(&mut s, (("item1", "item"), ("item2", "item2"))));
|
||||
assert!(resource.resource_path(&mut s, &mut (&["item", "item2"]).into_iter()));
|
||||
assert_eq!(s, "/user/item/item2");
|
||||
|
||||
let mut s = String::new();
|
||||
let resource = ResourceDef::new("/user/{item1}/{item2}/");
|
||||
assert!(resource.resource_path(&mut s, &["item", "item2"]));
|
||||
assert!(resource.resource_path(&mut s, &mut (&["item", "item2"]).into_iter()));
|
||||
assert_eq!(s, "/user/item/item2/");
|
||||
|
||||
let mut s = String::new();
|
||||
assert!(!resource.resource_path(&mut s, &["item"]));
|
||||
assert!(!resource.resource_path(&mut s, &mut (&["item"]).into_iter()));
|
||||
|
||||
let mut s = String::new();
|
||||
assert!(resource.resource_path(&mut s, &["item", "item2"]));
|
||||
assert!(resource.resource_path(&mut s, &mut (&["item", "item2"]).into_iter()));
|
||||
assert_eq!(s, "/user/item/item2/");
|
||||
assert!(!resource.resource_path(&mut s, &["item"]));
|
||||
assert!(!resource.resource_path(&mut s, &mut (&["item"]).into_iter()));
|
||||
|
||||
let mut s = String::new();
|
||||
assert!(resource.resource_path(&mut s, vec!["item", "item2"]));
|
||||
assert_eq!(s, "/user/item/item2/");
|
||||
|
||||
let mut s = String::new();
|
||||
assert!(resource.resource_path(&mut s, &vec!["item", "item2"]));
|
||||
assert_eq!(s, "/user/item/item2/");
|
||||
|
||||
let mut s = String::new();
|
||||
assert!(resource.resource_path(&mut s, &vec!["item", "item2"][..]));
|
||||
assert!(resource.resource_path(&mut s, &mut vec!["item", "item2"].into_iter()));
|
||||
assert_eq!(s, "/user/item/item2/");
|
||||
|
||||
let mut map = HashMap::new();
|
||||
map.insert("item1", "item");
|
||||
|
||||
let mut s = String::new();
|
||||
assert!(!resource.resource_path_named(&mut s, &map));
|
||||
|
||||
let mut s = String::new();
|
||||
map.insert("item2", "item2");
|
||||
|
||||
let mut s = String::new();
|
||||
assert!(resource.resource_path(&mut s, map));
|
||||
assert_eq!(s, "/user/item/item2/");
|
||||
|
||||
let mut s = String::new();
|
||||
assert!(resource.resource_path(&mut s, (("item1", "item"), ("item2", "item2"))));
|
||||
assert!(resource.resource_path_named(&mut s, &map));
|
||||
assert_eq!(s, "/user/item/item2/");
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user