1
0
mirror of https://github.com/fafhrd91/actix-net synced 2024-11-23 20:51:06 +01:00

Check code style with rustfmt on CI (#164)

This commit is contained in:
Yuki Okushi 2020-07-22 12:32:13 +09:00 committed by GitHub
parent 0dca1a705a
commit 8ace9264b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 333 additions and 283 deletions

View File

@ -12,6 +12,7 @@ Check your PR fulfills the following:
- [ ] Tests for the changes have been added / updated. - [ ] Tests for the changes have been added / updated.
- [ ] Documentation comments have been added / updated. - [ ] Documentation comments have been added / updated.
- [ ] A changelog entry has been made for the appropriate packages. - [ ] A changelog entry has been made for the appropriate packages.
- [ ] Format code with the latest stable rustfmt
## Overview ## Overview

34
.github/workflows/clippy-fmt.yml vendored Normal file
View File

@ -0,0 +1,34 @@
on:
pull_request:
types: [opened, synchronize, reopened]
name: Clippy and rustfmt Check
jobs:
clippy_check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
components: rustfmt
profile: minimal
override: true
- name: Check with rustfmt
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- uses: actions-rs/toolchain@v1
with:
toolchain: nightly
components: clippy
profile: minimal
override: true
- name: Check with Clippy
uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --all-features --all --tests

View File

@ -1,20 +0,0 @@
on:
pull_request:
types: [opened, synchronize, reopened]
name: Clippy Check
jobs:
clippy_check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: nightly
components: clippy
profile: minimal
override: true
- uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --all-features --all --tests

View File

@ -1,4 +1,4 @@
use bytes::{Bytes, BytesMut, Buf}; use bytes::{Buf, Bytes, BytesMut};
use std::io; use std::io;
use super::{Decoder, Encoder}; use super::{Decoder, Encoder};

View File

@ -271,7 +271,10 @@ impl<T, U> Framed<T, U> {
} }
/// Flush write buffer to underlying I/O stream. /// Flush write buffer to underlying I/O stream.
pub fn flush<I>(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), U::Error>> pub fn flush<I>(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(), U::Error>>
where where
T: AsyncWrite, T: AsyncWrite,
U: Encoder<I>, U: Encoder<I>,
@ -304,7 +307,10 @@ impl<T, U> Framed<T, U> {
} }
/// Flush write buffer and shutdown underlying I/O stream. /// Flush write buffer and shutdown underlying I/O stream.
pub fn close<I>(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), U::Error>> pub fn close<I>(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(), U::Error>>
where where
T: AsyncWrite, T: AsyncWrite,
U: Encoder<I>, U: Encoder<I>,

View File

@ -1,28 +1,26 @@
use actix_service::boxed::BoxFuture;
use actix_service::IntoService;
use actix_service::Service;
/// Benchmark various implementations of and_then /// Benchmark various implementations of and_then
use criterion::{criterion_main, Criterion}; use criterion::{criterion_main, Criterion};
use futures_util::future::join_all; use futures_util::future::join_all;
use futures_util::future::TryFutureExt;
use std::cell::{RefCell, UnsafeCell}; use std::cell::{RefCell, UnsafeCell};
use std::task::{Context, Poll};
use std::rc::Rc;
use actix_service::{Service};
use actix_service::IntoService;
use std::future::Future; use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use futures_util::future::TryFutureExt; use std::rc::Rc;
use actix_service::boxed::BoxFuture; use std::task::{Context, Poll};
/* /*
* Test services A,B for AndThen service implementations * Test services A,B for AndThen service implementations
*/ */
async fn svc1(_: ()) -> Result<usize, ()> { async fn svc1(_: ()) -> Result<usize, ()> {
Ok(1) Ok(1)
} }
async fn svc2(req: usize) -> Result<usize, ()> { async fn svc2(req: usize) -> Result<usize, ()> {
Ok(req + 1) Ok(req + 1)
} }
/* /*
@ -30,45 +28,44 @@ async fn svc2(req: usize) -> Result<usize, ()> {
* Cut down version of actix_service::AndThenService based on actix-service::Cell * Cut down version of actix_service::AndThenService based on actix-service::Cell
*/ */
struct AndThenUC<A, B>(Rc<UnsafeCell<(A, B)>>);
struct AndThenUC<A,B>(Rc<UnsafeCell<(A, B)>>); impl<A, B> AndThenUC<A, B> {
fn new(a: A, b: B) -> Self
impl<A,B> AndThenUC<A,B> { where
fn new(a: A, b: B) -> Self A: Service,
where B: Service<Request = A::Response, Error = A::Error>,
A: Service, {
B: Service<Request = A::Response, Error = A::Error>, Self(Rc::new(UnsafeCell::new((a, b))))
{ }
Self(Rc::new(UnsafeCell::new((a,b))))
}
} }
impl<A,B> Clone for AndThenUC<A,B> { impl<A, B> Clone for AndThenUC<A, B> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self(self.0.clone()) Self(self.0.clone())
} }
} }
impl<A,B> Service for AndThenUC<A,B> impl<A, B> Service for AndThenUC<A, B>
where where
A: Service, A: Service,
B: Service<Request = A::Response, Error = A::Error> B: Service<Request = A::Response, Error = A::Error>,
{ {
type Request = A::Request; type Request = A::Request;
type Response = B::Response; type Response = B::Response;
type Error = A::Error; type Error = A::Error;
type Future = AndThenServiceResponse<A,B>; type Future = AndThenServiceResponse<A, B>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(())) Poll::Ready(Ok(()))
} }
fn call(&mut self, req: A::Request) -> Self::Future { fn call(&mut self, req: A::Request) -> Self::Future {
let fut = unsafe { &mut *(*self.0).get() }.0.call(req); let fut = unsafe { &mut *(*self.0).get() }.0.call(req);
AndThenServiceResponse { AndThenServiceResponse {
state: State::A(fut, Some(self.0.clone())) state: State::A(fut, Some(self.0.clone())),
} }
} }
} }
#[pin_project::pin_project] #[pin_project::pin_project]
@ -117,157 +114,156 @@ where
this.state.set(State::Empty); this.state.set(State::Empty);
r r
}), }),
StateProj::Empty => panic!("future must not be polled after it returned `Poll::Ready`"), StateProj::Empty => {
panic!("future must not be polled after it returned `Poll::Ready`")
}
} }
} }
} }
/* /*
* AndThenRC - AndThen service based on RefCell * AndThenRC - AndThen service based on RefCell
*/ */
struct AndThenRC<A,B>(Rc<RefCell<(A, B)>>); struct AndThenRC<A, B>(Rc<RefCell<(A, B)>>);
impl<A,B> AndThenRC<A,B> { impl<A, B> AndThenRC<A, B> {
fn new(a: A, b: B) -> Self fn new(a: A, b: B) -> Self
where where
A: Service, A: Service,
B: Service<Request = A::Response, Error = A::Error>, B: Service<Request = A::Response, Error = A::Error>,
{ {
Self(Rc::new(RefCell::new((a,b)))) Self(Rc::new(RefCell::new((a, b))))
} }
} }
impl<A,B> Clone for AndThenRC<A,B> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<A,B> Service for AndThenRC<A,B>
where
A: Service,
B: Service<Request = A::Response, Error = A::Error>
{
type Request = A::Request;
type Response = B::Response;
type Error = A::Error;
type Future = AndThenServiceResponseRC<A,B>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: A::Request) -> Self::Future {
let fut = self.0.borrow_mut().0.call(req);
AndThenServiceResponseRC {
state: StateRC::A(fut, Some(self.0.clone()))
}
}
}
#[pin_project::pin_project]
pub(crate) struct AndThenServiceResponseRC<A, B>
where
A: Service,
B: Service<Request = A::Response, Error = A::Error>,
{
#[pin]
state: StateRC<A, B>,
}
#[pin_project::pin_project(project = StateRCProj)]
enum StateRC<A, B>
where
A: Service,
B: Service<Request = A::Response, Error = A::Error>,
{
A(#[pin] A::Future, Option<Rc<RefCell<(A, B)>>>),
B(#[pin] B::Future),
Empty,
}
impl<A, B> Future for AndThenServiceResponseRC<A, B>
where
A: Service,
B: Service<Request = A::Response, Error = A::Error>,
{
type Output = Result<B::Response, A::Error>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { impl<A, B> Clone for AndThenRC<A, B> {
let mut this = self.as_mut().project(); fn clone(&self) -> Self {
Self(self.0.clone())
}
}
match this.state.as_mut().project() { impl<A, B> Service for AndThenRC<A, B>
StateRCProj::A(fut, b) => match fut.poll(cx)? { where
Poll::Ready(res) => { A: Service,
let b = b.take().unwrap(); B: Service<Request = A::Response, Error = A::Error>,
this.state.set(StateRC::Empty); // drop fut A {
let fut = b.borrow_mut().1.call(res); type Request = A::Request;
this.state.set(StateRC::B(fut)); type Response = B::Response;
self.poll(cx) type Error = A::Error;
} type Future = AndThenServiceResponseRC<A, B>;
Poll::Pending => Poll::Pending,
},
StateRCProj::B(fut) => fut.poll(cx).map(|r| {
this.state.set(StateRC::Empty);
r
}),
StateRCProj::Empty => panic!("future must not be polled after it returned `Poll::Ready`"),
}
}
}
/* fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
* AndThenRCFuture - AndThen service based on RefCell Poll::Ready(Ok(()))
}
fn call(&mut self, req: A::Request) -> Self::Future {
let fut = self.0.borrow_mut().0.call(req);
AndThenServiceResponseRC {
state: StateRC::A(fut, Some(self.0.clone())),
}
}
}
#[pin_project::pin_project]
pub(crate) struct AndThenServiceResponseRC<A, B>
where
A: Service,
B: Service<Request = A::Response, Error = A::Error>,
{
#[pin]
state: StateRC<A, B>,
}
#[pin_project::pin_project(project = StateRCProj)]
enum StateRC<A, B>
where
A: Service,
B: Service<Request = A::Response, Error = A::Error>,
{
A(#[pin] A::Future, Option<Rc<RefCell<(A, B)>>>),
B(#[pin] B::Future),
Empty,
}
impl<A, B> Future for AndThenServiceResponseRC<A, B>
where
A: Service,
B: Service<Request = A::Response, Error = A::Error>,
{
type Output = Result<B::Response, A::Error>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut this = self.as_mut().project();
match this.state.as_mut().project() {
StateRCProj::A(fut, b) => match fut.poll(cx)? {
Poll::Ready(res) => {
let b = b.take().unwrap();
this.state.set(StateRC::Empty); // drop fut A
let fut = b.borrow_mut().1.call(res);
this.state.set(StateRC::B(fut));
self.poll(cx)
}
Poll::Pending => Poll::Pending,
},
StateRCProj::B(fut) => fut.poll(cx).map(|r| {
this.state.set(StateRC::Empty);
r
}),
StateRCProj::Empty => {
panic!("future must not be polled after it returned `Poll::Ready`")
}
}
}
}
/*
* AndThenRCFuture - AndThen service based on RefCell
* and standard futures::future::and_then combinator in a Box * and standard futures::future::and_then combinator in a Box
*/ */
struct AndThenRCFuture<A,B>(Rc<RefCell<(A, B)>>); struct AndThenRCFuture<A, B>(Rc<RefCell<(A, B)>>);
impl<A,B> AndThenRCFuture<A,B> { impl<A, B> AndThenRCFuture<A, B> {
fn new(a: A, b: B) -> Self fn new(a: A, b: B) -> Self
where where
A: Service, A: Service,
B: Service<Request = A::Response, Error = A::Error>, B: Service<Request = A::Response, Error = A::Error>,
{ {
Self(Rc::new(RefCell::new((a,b)))) Self(Rc::new(RefCell::new((a, b))))
} }
} }
impl<A,B> Clone for AndThenRCFuture<A,B> { impl<A, B> Clone for AndThenRCFuture<A, B> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self(self.0.clone()) Self(self.0.clone())
} }
} }
impl<A,B> Service for AndThenRCFuture<A,B> impl<A, B> Service for AndThenRCFuture<A, B>
where where
A: Service + 'static, A: Service + 'static,
A::Future: 'static, A::Future: 'static,
B: Service<Request = A::Response, Error = A::Error> + 'static, B: Service<Request = A::Response, Error = A::Error> + 'static,
B::Future: 'static B::Future: 'static,
{ {
type Request = A::Request; type Request = A::Request;
type Response = B::Response; type Response = B::Response;
type Error = A::Error; type Error = A::Error;
type Future = BoxFuture<Self::Response, Self::Error>; type Future = BoxFuture<Self::Response, Self::Error>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(())) Poll::Ready(Ok(()))
} }
fn call(&mut self, req: A::Request) -> Self::Future { fn call(&mut self, req: A::Request) -> Self::Future {
let fut = self.0.borrow_mut().0.call(req); let fut = self.0.borrow_mut().0.call(req);
let core = self.0.clone(); let core = self.0.clone();
let fut2 = move |res| (*core).borrow_mut().1.call(res); let fut2 = move |res| (*core).borrow_mut().1.call(res);
Box::pin( Box::pin(fut.and_then(fut2))
fut.and_then(fut2) }
) }
}
}
/// Criterion Benchmark for async Service /// Criterion Benchmark for async Service
/// Should be used from within criterion group: /// Should be used from within criterion group:
@ -296,9 +292,7 @@ where
// exclude request generation, it appears it takes significant time vs call (3us vs 1us) // exclude request generation, it appears it takes significant time vs call (3us vs 1us)
let start = std::time::Instant::now(); let start = std::time::Instant::now();
// benchmark body // benchmark body
rt.block_on(async move { rt.block_on(async move { join_all(srvs.iter_mut().map(|srv| srv.call(()))).await });
join_all(srvs.iter_mut().map(|srv| srv.call(()))).await
});
let elapsed = start.elapsed(); let elapsed = start.elapsed();
// check that at least first request succeeded // check that at least first request succeeded
elapsed elapsed
@ -306,15 +300,34 @@ where
}); });
} }
pub fn service_benches() { pub fn service_benches() {
let mut criterion: ::criterion::Criterion<_> = let mut criterion: ::criterion::Criterion<_> =
::criterion::Criterion::default().configure_from_args(); ::criterion::Criterion::default().configure_from_args();
bench_async_service(&mut criterion, AndThenUC::new(svc1.into_service(), svc2.into_service()), "AndThen with UnsafeCell"); bench_async_service(
bench_async_service(&mut criterion, AndThenRC::new(svc1.into_service(), svc2.into_service()), "AndThen with RefCell"); &mut criterion,
bench_async_service(&mut criterion, AndThenUC::new(svc1.into_service(), svc2.into_service()), "AndThen with UnsafeCell"); AndThenUC::new(svc1.into_service(), svc2.into_service()),
bench_async_service(&mut criterion, AndThenRC::new(svc1.into_service(), svc2.into_service()), "AndThen with RefCell"); "AndThen with UnsafeCell",
bench_async_service(&mut criterion, AndThenRCFuture::new(svc1.into_service(), svc2.into_service()), "AndThen with RefCell via future::and_then"); );
bench_async_service(
&mut criterion,
AndThenRC::new(svc1.into_service(), svc2.into_service()),
"AndThen with RefCell",
);
bench_async_service(
&mut criterion,
AndThenUC::new(svc1.into_service(), svc2.into_service()),
"AndThen with UnsafeCell",
);
bench_async_service(
&mut criterion,
AndThenRC::new(svc1.into_service(), svc2.into_service()),
"AndThen with RefCell",
);
bench_async_service(
&mut criterion,
AndThenRCFuture::new(svc1.into_service(), svc2.into_service()),
"AndThen with RefCell via future::and_then",
);
} }
criterion_main!(service_benches); criterion_main!(service_benches);

View File

@ -1,73 +1,72 @@
use actix_service::Service;
use criterion::{criterion_main, Criterion}; use criterion::{criterion_main, Criterion};
use futures_util::future::join_all; use futures_util::future::join_all;
use std::cell::{RefCell, UnsafeCell};
use std::task::{Context, Poll};
use std::rc::Rc;
use actix_service::{Service};
use futures_util::future::{ok, Ready}; use futures_util::future::{ok, Ready};
use std::cell::{RefCell, UnsafeCell};
use std::rc::Rc;
use std::task::{Context, Poll};
struct SrvUC(Rc<UnsafeCell<usize>>); struct SrvUC(Rc<UnsafeCell<usize>>);
impl Default for SrvUC { impl Default for SrvUC {
fn default() -> Self { fn default() -> Self {
Self(Rc::new(UnsafeCell::new(0))) Self(Rc::new(UnsafeCell::new(0)))
} }
} }
impl Clone for SrvUC { impl Clone for SrvUC {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self(self.0.clone()) Self(self.0.clone())
} }
} }
impl Service for SrvUC { impl Service for SrvUC {
type Request = (); type Request = ();
type Response = usize; type Response = usize;
type Error = (); type Error = ();
type Future = Ready<Result<Self::Response, ()>>; type Future = Ready<Result<Self::Response, ()>>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(())) Poll::Ready(Ok(()))
} }
fn call(&mut self, _: ()) -> Self::Future { fn call(&mut self, _: ()) -> Self::Future {
unsafe { *(*self.0).get() = *(*self.0).get() + 1 }; unsafe { *(*self.0).get() = *(*self.0).get() + 1 };
ok(unsafe { *self.0.get() }) ok(unsafe { *self.0.get() })
} }
} }
struct SrvRC(Rc<RefCell<usize>>); struct SrvRC(Rc<RefCell<usize>>);
impl Default for SrvRC { impl Default for SrvRC {
fn default() -> Self { fn default() -> Self {
Self(Rc::new(RefCell::new(0))) Self(Rc::new(RefCell::new(0)))
} }
} }
impl Clone for SrvRC { impl Clone for SrvRC {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self(self.0.clone()) Self(self.0.clone())
} }
} }
impl Service for SrvRC { impl Service for SrvRC {
type Request = (); type Request = ();
type Response = usize; type Response = usize;
type Error = (); type Error = ();
type Future = Ready<Result<Self::Response, ()>>; type Future = Ready<Result<Self::Response, ()>>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(())) Poll::Ready(Ok(()))
} }
fn call(&mut self, _: ()) -> Self::Future { fn call(&mut self, _: ()) -> Self::Future {
let prev = *self.0.borrow(); let prev = *self.0.borrow();
*(*self.0).borrow_mut() = prev + 1; *(*self.0).borrow_mut() = prev + 1;
ok(*self.0.borrow()) ok(*self.0.borrow())
} }
} }
/// Criterion Benchmark for async Service /// Criterion Benchmark for async Service
/// Should be used from within criterion group: /// Should be used from within criterion group:
/// ```rust,ignore /// ```rust,ignore
@ -95,9 +94,7 @@ where
// exclude request generation, it appears it takes significant time vs call (3us vs 1us) // exclude request generation, it appears it takes significant time vs call (3us vs 1us)
let start = std::time::Instant::now(); let start = std::time::Instant::now();
// benchmark body // benchmark body
rt.block_on(async move { rt.block_on(async move { join_all(srvs.iter_mut().map(|srv| srv.call(()))).await });
join_all(srvs.iter_mut().map(|srv| srv.call(()))).await
});
let elapsed = start.elapsed(); let elapsed = start.elapsed();
// check that at least first request succeeded // check that at least first request succeeded
elapsed elapsed
@ -105,7 +102,6 @@ where
}); });
} }
pub fn service_benches() { pub fn service_benches() {
let mut criterion: ::criterion::Criterion<_> = let mut criterion: ::criterion::Criterion<_> =
::criterion::Criterion::default().configure_from_args(); ::criterion::Criterion::default().configure_from_args();

View File

@ -1,12 +1,11 @@
use std::cell::RefCell;
use std::future::Future; use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use std::rc::Rc; use std::rc::Rc;
use std::cell::RefCell;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use super::{Service, ServiceFactory}; use super::{Service, ServiceFactory};
/// Service for the `and_then` combinator, chaining a computation onto the end /// Service for the `and_then` combinator, chaining a computation onto the end
/// of another service which completes successfully. /// of another service which completes successfully.
/// ///
@ -103,7 +102,9 @@ where
this.state.set(State::Empty); this.state.set(State::Empty);
r r
}), }),
StateProj::Empty => panic!("future must not be polled after it returned `Poll::Ready`"), StateProj::Empty => {
panic!("future must not be polled after it returned `Poll::Ready`")
}
} }
} }
} }

View File

@ -1,8 +1,8 @@
use std::cell::RefCell;
use std::future::Future; use std::future::Future;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::pin::Pin; use std::pin::Pin;
use std::rc::Rc; use std::rc::Rc;
use std::cell::RefCell;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use crate::{Service, ServiceFactory}; use crate::{Service, ServiceFactory};
@ -31,7 +31,7 @@ where
/// Create new `Apply` combinator /// Create new `Apply` combinator
pub(crate) fn new(a: A, b: B, f: F) -> Self { pub(crate) fn new(a: A, b: B, f: F) -> Self {
Self { Self {
srv: Rc::new(RefCell::new((a, b, f))), srv: Rc::new(RefCell::new((a, b, f))),
r: PhantomData, r: PhantomData,
} }
} }
@ -142,7 +142,9 @@ where
this.state.set(State::Empty); this.state.set(State::Empty);
r r
}), }),
StateProj::Empty => panic!("future must not be polled after it returned `Poll::Ready`"), StateProj::Empty => {
panic!("future must not be polled after it returned `Poll::Ready`")
}
} }
} }
} }
@ -296,10 +298,9 @@ mod tests {
#[actix_rt::test] #[actix_rt::test]
async fn test_service() { async fn test_service() {
let mut srv = pipeline(ok) let mut srv = pipeline(ok).and_then_apply_fn(Srv, |req: &'static str, s| {
.and_then_apply_fn(Srv, |req: &'static str, s| { s.call(()).map_ok(move |res| (req, res))
s.call(()).map_ok(move |res| (req, res)) });
});
let res = lazy(|cx| srv.poll_ready(cx)).await; let res = lazy(|cx| srv.poll_ready(cx)).await;
assert_eq!(res, Poll::Ready(Ok(()))); assert_eq!(res, Poll::Ready(Ok(())));
@ -310,11 +311,10 @@ mod tests {
#[actix_rt::test] #[actix_rt::test]
async fn test_service_factory() { async fn test_service_factory() {
let new_srv = pipeline_factory(|| ok::<_, ()>(fn_service(ok))) let new_srv = pipeline_factory(|| ok::<_, ()>(fn_service(ok))).and_then_apply_fn(
.and_then_apply_fn( || ok(Srv),
|| ok(Srv), |req: &'static str, s| s.call(()).map_ok(move |res| (req, res)),
|req: &'static str, s| s.call(()).map_ok(move |res| (req, res)), );
);
let mut srv = new_srv.new_service(()).await.unwrap(); let mut srv = new_srv.new_service(()).await.unwrap();
let res = lazy(|cx| srv.poll_ready(cx)).await; let res = lazy(|cx| srv.poll_ready(cx)).await;
assert_eq!(res, Poll::Ready(Ok(()))); assert_eq!(res, Poll::Ready(Ok(())));

View File

@ -1,9 +1,9 @@
use std::cell::RefCell;
use std::future::Future; use std::future::Future;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::pin::Pin; use std::pin::Pin;
use std::task::{Context, Poll};
use std::rc::Rc; use std::rc::Rc;
use std::cell::RefCell; use std::task::{Context, Poll};
use crate::{Service, ServiceFactory}; use crate::{Service, ServiceFactory};

View File

@ -1,7 +1,7 @@
use std::cell::RefCell;
use std::future::Future; use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use std::rc::Rc; use std::rc::Rc;
use std::cell::RefCell;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use super::{Service, ServiceFactory}; use super::{Service, ServiceFactory};
@ -102,7 +102,9 @@ where
this.state.set(State::Empty); this.state.set(State::Empty);
r r
}), }),
StateProj::Empty => panic!("future must not be polled after it returned `Poll::Ready`"), StateProj::Empty => {
panic!("future must not be polled after it returned `Poll::Ready`")
}
} }
} }
} }

View File

@ -7,9 +7,13 @@ use crate::ResourcePath;
macro_rules! unsupported_type { macro_rules! unsupported_type {
($trait_fn:ident, $name:expr) => { ($trait_fn:ident, $name:expr) => {
fn $trait_fn<V>(self, _: V) -> Result<V::Value, Self::Error> fn $trait_fn<V>(self, _: V) -> Result<V::Value, Self::Error>
where V: Visitor<'de> where
V: Visitor<'de>,
{ {
Err(de::value::Error::custom(concat!("unsupported type: ", $name))) Err(de::value::Error::custom(concat!(
"unsupported type: ",
$name
)))
} }
}; };
} }
@ -17,20 +21,25 @@ macro_rules! unsupported_type {
macro_rules! parse_single_value { macro_rules! parse_single_value {
($trait_fn:ident, $visit_fn:ident, $tp:tt) => { ($trait_fn:ident, $visit_fn:ident, $tp:tt) => {
fn $trait_fn<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn $trait_fn<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where V: Visitor<'de> where
V: Visitor<'de>,
{ {
if self.path.len() != 1 { if self.path.len() != 1 {
Err(de::value::Error::custom( Err(de::value::Error::custom(
format!("wrong number of parameters: {} expected 1", format!("wrong number of parameters: {} expected 1", self.path.len())
self.path.len()).as_str())) .as_str(),
))
} else { } else {
let v = self.path[0].parse().map_err( let v = self.path[0].parse().map_err(|_| {
|_| de::value::Error::custom( de::value::Error::custom(format!(
format!("can not parse {:?} to a {}", &self.path[0], $tp)))?; "can not parse {:?} to a {}",
&self.path[0], $tp
))
})?;
visitor.$visit_fn(v) visitor.$visit_fn(v)
} }
} }
} };
} }
pub struct PathDeserializer<'de, T: ResourcePath + 'de> { pub struct PathDeserializer<'de, T: ResourcePath + 'de> {
@ -268,14 +277,15 @@ impl<'de> Deserializer<'de> for Key<'de> {
macro_rules! parse_value { macro_rules! parse_value {
($trait_fn:ident, $visit_fn:ident, $tp:tt) => { ($trait_fn:ident, $visit_fn:ident, $tp:tt) => {
fn $trait_fn<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn $trait_fn<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where V: Visitor<'de> where
V: Visitor<'de>,
{ {
let v = self.value.parse().map_err( let v = self.value.parse().map_err(|_| {
|_| de::value::Error::custom( de::value::Error::custom(format!("can not parse {:?} to a {}", self.value, $tp))
format!("can not parse {:?} to a {}", self.value, $tp)))?; })?;
visitor.$visit_fn(v) visitor.$visit_fn(v)
} }
} };
} }
struct Value<'de> { struct Value<'de> {

View File

@ -33,6 +33,13 @@ impl ByteString {
} }
/// Creates a new `ByteString` from a Bytes. /// Creates a new `ByteString` from a Bytes.
///
/// # Safety
/// This function is unsafe because it does not check the bytes passed to it
/// are valid UTF-8. If this constraint is violated,
/// it may cause memory unsafety issues with future users of the `ByteString`,
/// as we assume that `ByteString`s are valid UTF-8.
/// However, the most likely issue is that the data gets corrupted.
pub const unsafe fn from_bytes_unchecked(src: Bytes) -> ByteString { pub const unsafe fn from_bytes_unchecked(src: Bytes) -> ByteString {
Self(src) Self(src)
} }