use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
use pin_project_lite::pin_project;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Either<A, B> {
Left(A),
Right(B),
}
impl<A, B> Either<A, B> {
pub fn is_left(&self) -> bool {
matches!(self, Self::Left(_))
}
pub fn is_right(&self) -> bool {
matches!(self, Self::Right(_))
}
pub fn is_first(&self) -> bool {
self.is_left()
}
pub fn is_second(&self) -> bool {
self.is_right()
}
pub fn left(self) -> Option<A> {
match self {
Self::Left(a) => Some(a),
Self::Right(_) => None,
}
}
pub fn right(self) -> Option<B> {
match self {
Self::Left(_) => None,
Self::Right(b) => Some(b),
}
}
pub fn first(self) -> Option<A> {
self.left()
}
pub fn second(self) -> Option<B> {
self.right()
}
}
pin_project! {
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Join2<F1, F2>
where
F1: Future,
F2: Future,
{
#[pin]
fut1: Option<F1>,
#[pin]
fut2: Option<F2>,
out1: Option<F1::Output>,
out2: Option<F2::Output>,
}
}
impl<F1, F2> Future for Join2<F1, F2>
where
F1: Future,
F2: Future,
{
type Output = (F1::Output, F2::Output);
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut this = self.project();
if this.out1.is_none() {
if let Some(fut) = this.fut1.as_mut().as_pin_mut() {
if let Poll::Ready(out) = fut.poll(cx) {
*this.out1 = Some(out);
this.fut1.set(None);
}
}
}
if this.out2.is_none() {
if let Some(fut) = this.fut2.as_mut().as_pin_mut() {
if let Poll::Ready(out) = fut.poll(cx) {
*this.out2 = Some(out);
this.fut2.set(None);
}
}
}
if this.out1.is_some() && this.out2.is_some() {
Poll::Ready((this.out1.take().unwrap(), this.out2.take().unwrap()))
} else {
Poll::Pending
}
}
}
pub fn join2<F1, F2>(fut1: F1, fut2: F2) -> Join2<F1, F2>
where
F1: Future,
F2: Future,
{
Join2 {
fut1: Some(fut1),
fut2: Some(fut2),
out1: None,
out2: None,
}
}
pin_project! {
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Select2<F1, F2> {
#[pin]
fut1: Option<F1>,
#[pin]
fut2: Option<F2>,
}
}
impl<F1, F2> Future for Select2<F1, F2>
where
F1: Future,
F2: Future,
{
type Output = Either<F1::Output, F2::Output>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut this = self.project();
if let Some(fut) = this.fut1.as_mut().as_pin_mut() {
if let Poll::Ready(out) = fut.poll(cx) {
this.fut1.set(None);
this.fut2.set(None);
return Poll::Ready(Either::Left(out));
}
}
if let Some(fut) = this.fut2.as_mut().as_pin_mut() {
if let Poll::Ready(out) = fut.poll(cx) {
this.fut1.set(None);
this.fut2.set(None);
return Poll::Ready(Either::Right(out));
}
}
Poll::Pending
}
}
pub fn select2<F1, F2>(fut1: F1, fut2: F2) -> Select2<F1, F2>
where
F1: Future,
F2: Future,
{
Select2 {
fut1: Some(fut1),
fut2: Some(fut2),
}
}