1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
|
use std::convert::identity;
use std::marker::Unpin;
use std::pin::Pin;
use std::task::{Context, Poll};
use pin_project_lite::pin_project;
use async_std::channel::bounded as channel;
use async_std::prelude::*;
use async_std::stream;
use async_std::task;
#[cfg(target_arch = "wasm32")]
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
#[cfg(not(target_os = "unknown"))]
use async_std::task::spawn;
#[cfg(target_os = "unknown")]
use async_std::task::spawn_local as spawn;
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
/// Checks that streams are merged fully even if one of the components
/// experiences delay.
fn merging_delayed_streams_work() {
let (sender, receiver) = channel::<i32>(10);
let mut s = receiver.merge(stream::empty());
let t = spawn(async move {
let mut xs = Vec::new();
while let Some(x) = s.next().await {
xs.push(x);
}
xs
});
task::block_on(async move {
task::sleep(std::time::Duration::from_millis(500)).await;
sender.send(92).await.unwrap();
drop(sender);
let xs = t.await;
assert_eq!(xs, vec![92])
});
let (sender, receiver) = channel::<i32>(10);
let mut s = stream::empty().merge(receiver);
let t = spawn(async move {
let mut xs = Vec::new();
while let Some(x) = s.next().await {
xs.push(x);
}
xs
});
task::block_on(async move {
task::sleep(std::time::Duration::from_millis(500)).await;
sender.send(92).await.unwrap();
drop(sender);
let xs = t.await;
assert_eq!(xs, vec![92])
});
}
pin_project! {
/// The opposite of `Fuse`: makes the stream panic if polled after termination.
struct Explode<S> {
#[pin]
done: bool,
#[pin]
inner: S,
}
}
impl<S: Stream> Stream for Explode<S> {
type Item = S::Item;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let mut this = self.project();
if *this.done {
panic!("KABOOM!")
}
let res = this.inner.poll_next(cx);
if let Poll::Ready(None) = &res {
*this.done = true;
}
res
}
}
fn explode<S: Stream>(s: S) -> Explode<S> {
Explode {
done: false,
inner: s,
}
}
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
fn merge_works_with_unfused_streams() {
let s1 = explode(stream::once(92));
let s2 = explode(stream::once(92));
let mut s = s1.merge(s2);
task::block_on(async move {
let mut xs = Vec::new();
while let Some(x) = s.next().await {
xs.push(x)
}
assert_eq!(xs, vec![92, 92]);
});
}
struct S<T>(T);
impl<T: Stream + Unpin> Stream for S<T> {
type Item = T::Item;
fn poll_next(mut self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Option<Self::Item>> {
unsafe { Pin::new_unchecked(&mut self.0) }.poll_next(ctx)
}
}
struct StrictOnce {
polled: bool,
}
impl Stream for StrictOnce {
type Item = ();
fn poll_next(mut self: Pin<&mut Self>, _: &mut Context) -> Poll<Option<Self::Item>> {
assert!(!self.polled, "Polled after completion!");
self.polled = true;
Poll::Ready(None)
}
}
struct Interchanger {
polled: bool,
}
impl Stream for Interchanger {
type Item = S<Box<dyn Stream<Item = ()> + Unpin>>;
fn poll_next(mut self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Option<Self::Item>> {
if self.polled {
self.polled = false;
ctx.waker().wake_by_ref();
Poll::Pending
} else {
self.polled = true;
Poll::Ready(Some(S(Box::new(StrictOnce { polled: false }))))
}
}
}
#[test]
fn flat_map_doesnt_poll_completed_inner_stream() {
task::block_on(async {
assert_eq!(
Interchanger { polled: false }
.take(2)
.flat_map(identity)
.count()
.await,
0
);
});
}
#[test]
fn flatten_doesnt_poll_completed_inner_stream() {
task::block_on(async {
assert_eq!(
Interchanger { polled: false }
.take(2)
.flatten()
.count()
.await,
0
);
});
}
|