forked from private-attribution/ipa
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
dcb6a39
commit 5abc016
Showing
4 changed files
with
147 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
use std::{task::{Context, Poll}, pin::Pin, iter::{repeat_with, repeat}}; | ||
|
||
use futures::{Future, FutureExt, future::Shared, ready}; | ||
use tokio::sync::oneshot::{Sender, self, Receiver}; | ||
use pin_project::pin_project; | ||
|
||
pub fn vec_item_futures<Fut: Future<Output = Vec<T>>, T>(fut: Fut, len: usize) -> impl Iterator<Item = VecItemFuture<Fut, T>> { | ||
let (tx, rx): (Vec<Sender<T>>, Vec<Receiver<T>>) = repeat_with(|| oneshot::channel()).take(len).unzip(); | ||
repeat(VecDistributionFuture { fut, len, tx }.shared()).zip(rx).map(|(fut, rx)| VecItemFuture { src: Some(fut), rx }) | ||
} | ||
|
||
#[pin_project] | ||
pub struct VecDistributionFuture<Fut: Future<Output = Vec<T>>, T> { | ||
#[pin] | ||
fut: Fut, | ||
len: usize, | ||
tx: Vec<Sender<T>>, | ||
} | ||
|
||
impl<Fut: Future<Output = Vec<T>>, T> Future for VecDistributionFuture<Fut, T> { | ||
type Output = (); | ||
|
||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
let proj = self.project(); | ||
let vec = ready!(proj.fut.poll(cx)); | ||
|
||
assert_eq!(vec.len(), *proj.len, "future used with vec_item_futures did not resolve with the correct length"); | ||
for (item, tx) in vec.into_iter().zip(proj.tx.drain(..)) { | ||
assert!(tx.send(item).is_ok()); | ||
} | ||
|
||
Poll::Ready(()) | ||
} | ||
} | ||
|
||
#[pin_project] | ||
pub struct VecItemFuture<Fut: Future<Output = Vec<T>>, T> { | ||
#[pin] | ||
src: Option<Shared<VecDistributionFuture<Fut, T>>>, | ||
#[pin] | ||
rx: Receiver<T>, | ||
} | ||
|
||
impl<Fut: Future<Output = Vec<T>>, T> Future for VecItemFuture<Fut, T> { | ||
type Output = T; | ||
|
||
fn poll(self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
let mut proj = self.project(); | ||
if let Some(src) = proj.src.as_mut().as_pin_mut() { | ||
match src.poll(cx) { | ||
Poll::Ready(()) => *proj.src = None, | ||
Poll::Pending => return Poll::Pending, | ||
} | ||
} | ||
<Receiver<T> as Future>::poll(proj.rx, cx).map(|recv_res| recv_res.unwrap()) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use std::{ptr::null, task::Waker, future}; | ||
|
||
use super::*; | ||
|
||
fn fake_waker() -> Waker { | ||
use std::task::{RawWaker, RawWakerVTable}; | ||
const fn fake_raw_waker() -> RawWaker { | ||
const TABLE: RawWakerVTable = | ||
RawWakerVTable::new(|_| fake_raw_waker(), |_| {}, |_| {}, |_| {}); | ||
RawWaker::new(null(), &TABLE) | ||
} | ||
unsafe { Waker::from_raw(fake_raw_waker()) } | ||
} | ||
|
||
#[tokio::test] | ||
async fn test_vec_item_futures() { | ||
let mut futs = vec_item_futures(future::ready(vec![1, 2]), 2); | ||
let fut1 = futs.next().unwrap(); | ||
let fut2 = futs.next().unwrap(); | ||
assert!(futs.next().is_none()); | ||
|
||
assert_eq!(fut1.await, 1); | ||
assert_eq!(fut2.await, 2); | ||
} | ||
|
||
#[tokio::test] | ||
async fn test_vec_item_futures_reverse_order() { | ||
let mut futs = vec_item_futures(future::ready(vec![1, 2]), 2); | ||
let fut1 = futs.next().unwrap(); | ||
let fut2 = futs.next().unwrap(); | ||
assert!(futs.next().is_none()); | ||
|
||
assert_eq!(fut2.await, 2); | ||
assert_eq!(fut1.await, 1); | ||
} | ||
|
||
#[tokio::test] | ||
#[should_panic(expected = "future used with vec_item_futures did not resolve with the correct length")] | ||
async fn test_vec_item_futures_incorrect_length() { | ||
let mut futs = vec_item_futures(future::ready(vec![1, 2]), 3); | ||
futs.next().unwrap().await; | ||
} | ||
|
||
#[tokio::test] | ||
async fn test_vec_item_futures_pending() { | ||
let (_tx, rx) = oneshot::channel::<Vec<i32>>(); | ||
let mut futs = vec_item_futures(rx.map(Result::unwrap), 3); | ||
let mut fut = futs.next().unwrap(); | ||
let waker = fake_waker(); | ||
let mut cx = Context::from_waker(&waker); | ||
assert_eq!(fut.poll_unpin(&mut cx), Poll::Pending); | ||
} | ||
|
||
#[tokio::test] | ||
async fn test_vec_item_futures_broadcast() { | ||
// We should be able to poll the second future, even if nobody looks at the first. | ||
let (tx, rx) = oneshot::channel::<Vec<i32>>(); | ||
let mut futs = vec_item_futures(rx.map(Result::unwrap), 2); | ||
let _fut1 = futs.next().unwrap(); | ||
let fut2 = futs.next().unwrap(); | ||
assert!(futs.next().is_none()); | ||
tx.send(vec![1, 2]).unwrap(); | ||
assert_eq!(fut2.await, 2); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
mod buffered_stream; | ||
mod ordering_mpsc; | ||
mod ordering_sender; | ||
mod unordered_receiver; | ||
|
||
pub use buffered_stream::vec_item_futures; | ||
pub use ordering_mpsc::{ordering_mpsc, OrderingMpscReceiver, OrderingMpscSender}; | ||
pub use ordering_sender::{OrderedStream, OrderingSender}; | ||
pub use unordered_receiver::UnorderedReceiver; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters