use std::any::type_name;
use std::fmt::{self, Debug};
use std::marker::PhantomPinned;
use std::pin::Pin;
use std::task::Poll::{Pending, Ready};
use std::{mem, task};
use bytesbuf::{BytesBuf, BytesView};
use crate::Read;
pub struct ReadAsFuturesStream<S>
where
S: Read + Debug,
{
#[expect(clippy::type_complexity, reason = "never needs to be named, good enough")]
active_read: Option<Pin<Box<dyn Future<Output = Result<BytesBuf, S::Error>>>>>,
inner: S,
_require_pin: PhantomPinned,
}
impl<S> ReadAsFuturesStream<S>
where
S: Read + Debug,
{
pub(crate) fn new(inner: S) -> Pin<Box<Self>> {
Box::pin(Self {
active_read: None,
inner,
_require_pin: PhantomPinned,
})
}
#[must_use]
pub fn into_inner(self: Pin<Box<Self>>) -> S {
let mut unpinned = unsafe { Pin::into_inner_unchecked(self) };
unpinned.active_read = None;
unpinned.inner
}
}
impl<S> futures_core::Stream for ReadAsFuturesStream<S>
where
S: Read + Debug,
{
type Item = Result<BytesView, S::Error>;
fn poll_next<'a>(self: Pin<&'a mut Self>, cx: &'a mut task::Context) -> task::Poll<Option<Self::Item>> {
let this = unsafe { self.get_unchecked_mut() };
let mut active_read = if let Some(active_read) = this.active_read.take() {
active_read
} else {
let inner = &mut this.inner;
let future = async move { inner.read_any().await };
let boxed_future = Box::pin(future);
unsafe {
mem::transmute::<
Pin<Box<dyn Future<Output = Result<BytesBuf, S::Error>> + 'a>>,
Pin<Box<dyn Future<Output = Result<BytesBuf, S::Error>>>>,
>(boxed_future)
}
};
let result = active_read.as_mut().poll(cx);
match result {
Ready(Ok(mut buf)) => {
let data = buf.consume_all();
if data.is_empty() {
return Ready(None);
}
Ready(Some(Ok(data)))
}
Ready(Err(e)) => Ready(Some(Err(e))),
Pending => {
this.active_read = Some(active_read);
Pending
}
}
}
}
impl<S> Debug for ReadAsFuturesStream<S>
where
S: Read + Debug,
{
#[cfg_attr(coverage_nightly, coverage(off))] #[cfg_attr(test, mutants::skip)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct(type_name::<Self>())
.field("inner", &self.inner)
.field("active_read.is_some()", &self.active_read.is_some())
.finish_non_exhaustive()
}
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use std::convert::Infallible;
use std::pin::pin;
use std::task::Waker;
use bytesbuf::mem::testing::TransparentMemory;
use bytesbuf::mem::{GlobalPool, HasMemory, Memory, MemoryShared};
use futures::{Stream, StreamExt};
use new_zealand::nz;
use testing_aids::{YieldFuture, async_test};
use super::*;
use crate::ReadExt;
use crate::testing::{FakeRead, Pending};
#[test]
fn smoke_test() {
async_test(async || {
let memory = GlobalPool::new();
let contents = BytesView::copied_from_slice(b"Hello, w", &memory);
let inner = FakeRead::builder().contents(contents).max_read_size(nz!(2)).build();
let mut futures_stream = inner.into_futures_stream();
let mut payload1 = futures_stream.next().await.unwrap().unwrap();
assert_eq!(payload1.len(), 2);
assert_eq!(payload1.get_byte(), b'H');
assert_eq!(payload1.get_byte(), b'e');
let mut payload2 = futures_stream.next().await.unwrap().unwrap();
assert_eq!(payload2.len(), 2);
assert_eq!(payload2.get_byte(), b'l');
assert_eq!(payload2.get_byte(), b'l');
let mut original = futures_stream.into_inner();
let mut payload3 = original.read_exactly(2).await.unwrap();
assert_eq!(payload3.len(), 2);
assert_eq!(payload3.get_byte(), b'o');
assert_eq!(payload3.get_byte(), b',');
let mut futures_stream = original.into_futures_stream();
let mut payload4 = futures_stream.next().await.unwrap().unwrap();
assert_eq!(payload4.len(), 2);
assert_eq!(payload4.get_byte(), b' ');
assert_eq!(payload4.get_byte(), b'w');
assert!(futures_stream.next().await.is_none());
});
}
#[test]
fn pending_read_cancelled_on_into_inner() {
let inner = Pending::new();
let mut futures_stream = inner.into_futures_stream();
let mut cx = task::Context::from_waker(Waker::noop());
assert!(matches!(futures_stream.as_mut().poll_next(&mut cx), task::Poll::Pending));
let mut inner = futures_stream.into_inner();
let read_future = pin!(inner.read_any());
assert!(read_future.poll(&mut cx).is_pending());
}
#[derive(Debug)]
struct YieldThenRead {
inner: FakeRead,
}
impl Memory for YieldThenRead {
fn reserve(&self, min_bytes: usize) -> BytesBuf {
self.inner.reserve(min_bytes)
}
}
impl HasMemory for YieldThenRead {
fn memory(&self) -> impl MemoryShared {
self.inner.memory()
}
}
impl crate::Read for YieldThenRead {
type Error = Infallible;
async fn read_at_most_into(&mut self, len: usize, into: BytesBuf) -> Result<(usize, BytesBuf), Self::Error> {
YieldFuture::default().await;
self.inner.read_at_most_into(len, into).await
}
async fn read_more_into(&mut self, into: BytesBuf) -> Result<(usize, BytesBuf), Self::Error> {
YieldFuture::default().await;
self.inner.read_more_into(into).await
}
async fn read_any(&mut self) -> Result<BytesBuf, Self::Error> {
YieldFuture::default().await;
self.inner.read_any().await
}
}
#[test]
fn pending_on_first_poll_then_returns_result() {
async_test(async || {
let memory = GlobalPool::new();
let contents = BytesView::copied_from_slice(b"Hello", &memory);
let inner = YieldThenRead {
inner: FakeRead::builder().contents(contents).build(),
};
let mut futures_stream = ReadAsFuturesStream::new(inner);
let waker = Waker::noop();
let mut cx = task::Context::from_waker(waker);
let poll_result = futures_stream.as_mut().poll_next(&mut cx);
assert!(matches!(poll_result, task::Poll::Pending));
let poll_result = futures_stream.as_mut().poll_next(&mut cx);
if let task::Poll::Ready(Some(Ok(mut data))) = poll_result {
assert_eq!(data.len(), 5);
assert_eq!(data.get_byte(), b'H');
assert_eq!(data.get_byte(), b'e');
assert_eq!(data.get_byte(), b'l');
assert_eq!(data.get_byte(), b'l');
assert_eq!(data.get_byte(), b'o');
} else {
panic!("Expected Ready(Some(Ok(_)))");
}
});
}
#[derive(Debug)]
struct ErroringRead {
memory: TransparentMemory,
}
impl Default for ErroringRead {
fn default() -> Self {
Self {
memory: TransparentMemory::new(),
}
}
}
#[derive(Debug)]
struct TestError(String);
impl fmt::Display for TestError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl std::error::Error for TestError {}
impl Memory for ErroringRead {
fn reserve(&self, min_bytes: usize) -> BytesBuf {
self.memory.reserve(min_bytes)
}
}
impl HasMemory for ErroringRead {
fn memory(&self) -> impl MemoryShared {
self.memory.clone()
}
}
impl crate::Read for ErroringRead {
type Error = TestError;
async fn read_at_most_into(&mut self, _len: usize, _into: BytesBuf) -> Result<(usize, BytesBuf), Self::Error> {
Err(TestError("read_at_most_into error".to_string()))
}
async fn read_more_into(&mut self, _into: BytesBuf) -> Result<(usize, BytesBuf), Self::Error> {
Err(TestError("read_more_into error".to_string()))
}
async fn read_any(&mut self) -> Result<BytesBuf, Self::Error> {
Err(TestError("read_any error".to_string()))
}
}
#[test]
fn passes_through_error_from_inner() {
async_test(async || {
let inner = ErroringRead::default();
let mut futures_stream = ReadAsFuturesStream::new(inner);
let result = futures_stream.next().await;
match result {
Some(Err(TestError(msg))) => {
assert_eq!(msg, "read_any error");
}
_ => panic!("Expected Some(Err(TestError(_)))"),
}
});
}
}