use crate::runtime::{CancellationToken, FutureExt, WithCancellation};
#[allow(async_fn_in_trait)]
pub trait Stream {
type Item;
async fn next(&mut self) -> Option<Self::Item>;
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, None)
}
}
impl<S: ?Sized + Stream> Stream for &mut S {
type Item = S::Item;
#[inline]
async fn next(&mut self) -> Option<Self::Item> {
(**self).next().await
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(**self).size_hint()
}
}
#[allow(async_fn_in_trait)]
pub trait StreamExt: Stream {
fn with_cancellation(self, token: CancellationToken) -> WithCancellation<Self>
where
Self: Sized,
{
WithCancellation::new(self, token)
}
async fn count(mut self) -> usize
where
Self: Sized,
{
let mut n = 0usize;
while self.next().await.is_some() {
n += 1;
}
n
}
async fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
while n > 0 {
self.next().await?;
n -= 1;
}
self.next().await
}
async fn collect<C>(mut self) -> C
where
Self: Sized,
C: Default + Extend<Self::Item>,
{
let mut c = C::default();
while let Some(item) = self.next().await {
c.extend(core::iter::once(item));
}
c
}
async fn for_each<F>(mut self, mut f: F)
where
Self: Sized,
F: FnMut(Self::Item),
{
while let Some(item) = self.next().await {
f(item);
}
}
}
impl<S: Stream + ?Sized> StreamExt for S {}
impl<S: Stream> Stream for WithCancellation<S> {
type Item = S::Item;
async fn next(&mut self) -> Option<Self::Item> {
self.future.next().with_cancellation(self.token).await
}
}
#[cfg(test)]
mod tests {
use std::task::Poll;
use super::*;
use crate::runtime::CancellationSource;
struct ScopeCheckingStream;
impl Stream for ScopeCheckingStream {
type Item = ();
async fn next(&mut self) -> Option<Self::Item> {
std::future::poll_fn(|_cx| {
assert_eq!(crate::driver::helpers::scopes::current_scope_ids().len(), 1);
Poll::Ready(Some(()))
})
.await
}
}
#[test]
fn with_cancellation_installs_scope_while_polling_next() {
crate::Runtime::new().unwrap().block_on(async {
let source = CancellationSource::new();
let mut stream = ScopeCheckingStream.with_cancellation(source.token());
assert_eq!(stream.next().await, Some(()));
});
}
}