use std::pin::Pin;
use std::task::{Context, Poll};
pub use futures_core::Stream;
pub(crate) fn next<S>(stream: &mut S) -> impl Future<Output = Option<S::Item>> + '_
where
S: Stream + Unpin + ?Sized,
{
std::future::poll_fn(move |cx| Pin::new(&mut *stream).poll_next(cx))
}
pub(crate) fn filter_map<S, F, T>(stream: S, f: F) -> FilterMap<S, F>
where
S: Stream + Unpin,
F: FnMut(S::Item) -> Option<T>,
{
FilterMap { stream, f }
}
pub(crate) struct FilterMap<S, F> {
stream: S,
f: F,
}
impl<S, F, T> Stream for FilterMap<S, F>
where
S: Stream + Unpin,
F: FnMut(S::Item) -> Option<T> + Unpin,
{
type Item = T;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> {
let this = self.get_mut();
loop {
match Pin::new(&mut this.stream).poll_next(cx) {
Poll::Ready(Some(item)) => match (this.f)(item) {
Some(mapped) => return Poll::Ready(Some(mapped)),
None => continue,
},
Poll::Ready(None) => return Poll::Ready(None),
Poll::Pending => return Poll::Pending,
}
}
}
}
pub(crate) fn empty<T>() -> Empty<T> {
Empty(std::marker::PhantomData)
}
pub(crate) struct Empty<T>(std::marker::PhantomData<fn() -> T>);
impl<T> Stream for Empty<T> {
type Item = T;
fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<T>> {
Poll::Ready(None)
}
}
#[cfg(test)]
pub(crate) fn iter<I>(items: I) -> Iter<I::IntoIter>
where
I: IntoIterator,
{
Iter(items.into_iter())
}
#[cfg(test)]
pub(crate) struct Iter<I>(I);
#[cfg(test)]
impl<I: Iterator + Unpin> Stream for Iter<I> {
type Item = I::Item;
fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<I::Item>> {
Poll::Ready(self.get_mut().0.next())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn iter_yields_then_ends() {
let mut s = iter([1, 2, 3]);
assert_eq!(next(&mut s).await, Some(1));
assert_eq!(next(&mut s).await, Some(2));
assert_eq!(next(&mut s).await, Some(3));
assert_eq!(next(&mut s).await, None);
assert_eq!(next(&mut s).await, None);
}
#[tokio::test]
async fn empty_ends_immediately() {
let mut s = empty::<u8>();
assert_eq!(next(&mut s).await, None);
}
#[tokio::test]
async fn filter_map_drops_and_maps() {
let mut s = filter_map(iter([1, 2, 3, 4]), |n| (n % 2 == 0).then(|| n * 10));
assert_eq!(next(&mut s).await, Some(20));
assert_eq!(next(&mut s).await, Some(40));
assert_eq!(next(&mut s).await, None);
}
#[tokio::test]
async fn filter_map_skips_a_leading_run_without_stalling() {
let mut s = filter_map(iter([1, 1, 1, 2]), |n| (n % 2 == 0).then_some(n));
assert_eq!(next(&mut s).await, Some(2));
assert_eq!(next(&mut s).await, None);
}
}