This commit is contained in:
Aode (lion) 2022-03-07 19:56:29 -06:00
commit 270099c58b
3 changed files with 99 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target
Cargo.lock

8
Cargo.toml Normal file
View file

@ -0,0 +1,8 @@
[package]
name = "select"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

89
src/lib.rs Normal file
View file

@ -0,0 +1,89 @@
use std::{
future::Future,
pin::Pin,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
task::{Context, Poll, Wake, Waker},
};
pub enum Either<L, R> {
Left(L),
Right(R),
}
pub fn join<L, R>(left: L, right: R) -> impl Future<Output = Either<L::Output, R::Output>> + Unpin
where
L: Future + Unpin,
R: Future + Unpin,
{
Select {
left: SelectState {
woken: Arc::new(AtomicBool::new(true)),
future: left,
},
right: SelectState {
woken: Arc::new(AtomicBool::new(true)),
future: right,
},
}
}
struct SelectWaker {
woken: Arc<AtomicBool>,
parent: Waker,
}
struct SelectState<T> {
woken: Arc<AtomicBool>,
future: T,
}
struct Select<L, R> {
left: SelectState<L>,
right: SelectState<R>,
}
impl<T: Future> SelectState<T> {
fn check_for_poll(&self) -> bool {
self.woken.swap(false, Ordering::AcqRel)
}
}
impl Wake for SelectWaker {
fn wake(self: Arc<Self>) {
self.wake_by_ref();
}
fn wake_by_ref(self: &Arc<Self>) {
self.woken.store(true, Ordering::Release);
self.parent.wake_by_ref();
}
}
impl<L, R> Future for Select<L, R>
where
L: Future + Unpin,
R: Future + Unpin,
{
type Output = Either<L::Output, R::Output>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
if this.left.check_for_poll() {
if let Poll::Ready(out) = Pin::new(&mut this.left.future).poll(cx) {
return Poll::Ready(Either::Left(out));
}
}
if this.right.check_for_poll() {
if let Poll::Ready(out) = Pin::new(&mut this.right.future).poll(cx) {
return Poll::Ready(Either::Right(out));
}
}
Poll::Pending
}
}