From fb27ffc525ec32af82cf71749a5486f643ac705f Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Thu, 1 Apr 2021 13:53:44 +0100 Subject: [PATCH] add future::Either type to utils (#305) --- actix-tracing/Cargo.toml | 2 +- actix-tracing/src/lib.rs | 6 +- actix-utils/CHANGES.md | 3 + actix-utils/Cargo.toml | 1 + actix-utils/src/future/either.rs | 91 +++++++++++++++++++++++++++++++ actix-utils/src/future/mod.rs | 2 + actix-utils/src/future/poll_fn.rs | 2 +- actix-utils/src/future/ready.rs | 4 +- 8 files changed, 104 insertions(+), 7 deletions(-) create mode 100644 actix-utils/src/future/either.rs diff --git a/actix-tracing/Cargo.toml b/actix-tracing/Cargo.toml index 992edbf4..4bbe7396 100644 --- a/actix-tracing/Cargo.toml +++ b/actix-tracing/Cargo.toml @@ -17,8 +17,8 @@ path = "src/lib.rs" [dependencies] actix-service = "2.0.0-beta.5" +actix-utils = "3.0.0-beta.3" -futures-util = { version = "0.3.7", default-features = false } tracing = "0.1" tracing-futures = "0.2" diff --git a/actix-tracing/src/lib.rs b/actix-tracing/src/lib.rs index 89e93be1..fcc1488d 100644 --- a/actix-tracing/src/lib.rs +++ b/actix-tracing/src/lib.rs @@ -9,7 +9,7 @@ use core::marker::PhantomData; use actix_service::{ apply, ApplyTransform, IntoServiceFactory, Service, ServiceFactory, Transform, }; -use futures_util::future::{ok, Either, Ready}; +use actix_utils::future::{ok, Either, Ready}; use tracing_futures::{Instrument, Instrumented}; /// A `Service` implementation that automatically enters/exits tracing spans @@ -48,9 +48,9 @@ where .clone() .map(|span| tracing::span!(parent: &span, tracing::Level::INFO, "future")) { - Either::Right(fut.instrument(span)) + Either::right(fut.instrument(span)) } else { - Either::Left(fut) + Either::left(fut) } } } diff --git a/actix-utils/CHANGES.md b/actix-utils/CHANGES.md index 57ab7add..5aa36128 100644 --- a/actix-utils/CHANGES.md +++ b/actix-utils/CHANGES.md @@ -1,6 +1,9 @@ # Changes ## Unreleased - 2021-xx-xx +* Add `future::Either` type. [#305] + +[#305]: https://github.com/actix/actix-net/pull/305 ## 3.0.0-beta.3 - 2021-04-01 diff --git a/actix-utils/Cargo.toml b/actix-utils/Cargo.toml index 019d6d98..c3961a6a 100644 --- a/actix-utils/Cargo.toml +++ b/actix-utils/Cargo.toml @@ -17,6 +17,7 @@ name = "actix_utils" path = "src/lib.rs" [dependencies] +pin-project-lite = "0.2" local-waker = "0.1" [dev-dependencies] diff --git a/actix-utils/src/future/either.rs b/actix-utils/src/future/either.rs new file mode 100644 index 00000000..77b2118d --- /dev/null +++ b/actix-utils/src/future/either.rs @@ -0,0 +1,91 @@ +//! A symmetric either future. + +use core::{ + future::Future, + pin::Pin, + task::{Context, Poll}, +}; + +use pin_project_lite::pin_project; + +pin_project! { + /// Combines two different futures that have the same output type. + /// + /// Construct variants with [`Either::left`] and [`Either::right`]. + /// + /// # Examples + /// ``` + /// use actix_utils::future::{ready, Ready, Either}; + /// + /// # async fn run() { + /// let res = Either::<_, Ready>::left(ready(42)); + /// assert_eq!(res.await, 42); + /// + /// let res = Either::, _>::right(ready(43)); + /// assert_eq!(res.await, 43); + /// # } + /// ``` + #[project = EitherProj] + #[derive(Debug, Clone)] + pub enum Either { + /// A value of type `L`. + #[allow(missing_docs)] + Left { #[pin] value: L }, + + /// A value of type `R`. + #[allow(missing_docs)] + Right { #[pin] value: R }, + } +} + +impl Either { + /// Creates new `Either` using left variant. + pub fn left(value: L) -> Either { + Either::Left { value } + } + + /// Creates new `Either` using right variant. + pub fn right(value: R) -> Either { + Either::Right { value } + } +} + +impl Either { + /// Unwraps into inner value when left and right have a common type. + pub fn into_inner(self) -> T { + match self { + Either::Left { value } => value, + Either::Right { value } => value, + } + } +} + +impl Future for Either +where + L: Future, + R: Future, +{ + type Output = L::Output; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + match self.project() { + EitherProj::Left { value } => value.poll(cx), + EitherProj::Right { value } => value.poll(cx), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::future::{ready, Ready}; + + #[actix_rt::test] + async fn test_either() { + let res = Either::<_, Ready>::left(ready(42)); + assert_eq!(res.await, 42); + + let res = Either::, _>::right(ready(43)); + assert_eq!(res.await, 43); + } +} diff --git a/actix-utils/src/future/mod.rs b/actix-utils/src/future/mod.rs index 0ad84ec7..be3807bf 100644 --- a/actix-utils/src/future/mod.rs +++ b/actix-utils/src/future/mod.rs @@ -1,7 +1,9 @@ //! Asynchronous values. +mod either; mod poll_fn; mod ready; +pub use self::either::Either; pub use self::poll_fn::{poll_fn, PollFn}; pub use self::ready::{err, ok, ready, Ready}; diff --git a/actix-utils/src/future/poll_fn.rs b/actix-utils/src/future/poll_fn.rs index 2e5285d8..5e911bf5 100644 --- a/actix-utils/src/future/poll_fn.rs +++ b/actix-utils/src/future/poll_fn.rs @@ -7,7 +7,7 @@ use core::{ task::{Context, Poll}, }; -/// Create a future driven by the provided function that receives a task context. +/// Creates a future driven by the provided function that receives a task context. pub fn poll_fn(f: F) -> PollFn where F: FnMut(&mut Context<'_>) -> Poll, diff --git a/actix-utils/src/future/ready.rs b/actix-utils/src/future/ready.rs index be2ee146..4a01ada3 100644 --- a/actix-utils/src/future/ready.rs +++ b/actix-utils/src/future/ready.rs @@ -69,7 +69,7 @@ pub fn ready(val: T) -> Ready { Ready { val: Some(val) } } -/// Create a future that is immediately ready with a success value. +/// Creates a future that is immediately ready with a success value. /// /// # Examples /// ```no_run @@ -84,7 +84,7 @@ pub fn ok(val: T) -> Ready> { Ready { val: Some(Ok(val)) } } -/// Create a future that is immediately ready with an error value. +/// Creates a future that is immediately ready with an error value. /// /// # Examples /// ```no_run