Skip to main content

quinn/
recv_stream.rs

1use std::{
2    future::{Future, poll_fn},
3    io,
4    pin::Pin,
5    task::{Context, Poll, ready},
6};
7
8use bytes::Bytes;
9use proto::{Chunk, Chunks, ClosedStream, ConnectionError, ReadableError, StreamId};
10use thiserror::Error;
11use tokio::io::ReadBuf;
12
13use crate::{VarInt, connection::ConnectionRef};
14
15/// A stream that can only be used to receive data
16///
17/// `stop(0)` is implicitly called on drop unless:
18/// - A variant of [`ReadError`] has been yielded by a read call
19/// - [`stop()`] was called explicitly
20///
21/// # Cancellation
22///
23/// A `read` method is said to be *cancel-safe* when dropping its future before the future becomes
24/// ready cannot lead to loss of stream data. This is true of methods which succeed immediately when
25/// any progress is made, and is not true of methods which might need to perform multiple reads
26/// internally before succeeding. Each `read` method documents whether it is cancel-safe.
27///
28/// # Common issues
29///
30/// ## Data never received on a locally-opened stream
31///
32/// Peers are not notified of streams until they or a later-numbered stream are used to send
33/// data. If a bidirectional stream is locally opened but never used to send, then the peer may
34/// never see it. Application protocols should always arrange for the endpoint which will first
35/// transmit on a stream to be the endpoint responsible for opening it.
36///
37/// ## Data never received on a remotely-opened stream
38///
39/// Verify that the stream you are receiving is the same one that the server is sending on, e.g. by
40/// logging the [`id`] of each. Streams are always accepted in the same order as they are created,
41/// i.e. ascending order by [`StreamId`]. For example, even if a sender first transmits on
42/// bidirectional stream 1, the first stream yielded by [`Connection::accept_bi`] on the receiver
43/// will be bidirectional stream 0.
44///
45/// [`ReadError`]: crate::ReadError
46/// [`stop()`]: RecvStream::stop
47/// [`SendStream::finish`]: crate::SendStream::finish
48/// [`WriteError::Stopped`]: crate::WriteError::Stopped
49/// [`id`]: RecvStream::id
50/// [`Connection::accept_bi`]: crate::Connection::accept_bi
51#[derive(Debug)]
52pub struct RecvStream {
53    conn: ConnectionRef,
54    stream: StreamId,
55    is_0rtt: bool,
56    all_data_read: bool,
57    reset: Option<VarInt>,
58}
59
60impl RecvStream {
61    pub(crate) fn new(conn: ConnectionRef, stream: StreamId, is_0rtt: bool) -> Self {
62        Self {
63            conn,
64            stream,
65            is_0rtt,
66            all_data_read: false,
67            reset: None,
68        }
69    }
70
71    /// Read data contiguously from the stream.
72    ///
73    /// Yields the number of bytes read into `buf` on success, or `None` if the stream was finished.
74    ///
75    /// This operation is cancel-safe.
76    pub async fn read(&mut self, buf: &mut [u8]) -> Result<Option<usize>, ReadError> {
77        Read {
78            stream: self,
79            buf: ReadBuf::new(buf),
80        }
81        .await
82    }
83
84    /// Read an exact number of bytes contiguously from the stream.
85    ///
86    /// See [`read()`] for details. This operation is *not* cancel-safe.
87    ///
88    /// [`read()`]: RecvStream::read
89    pub async fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), ReadExactError> {
90        ReadExact {
91            stream: self,
92            buf: ReadBuf::new(buf),
93        }
94        .await
95    }
96
97    /// Attempts to read from the stream into the provided buffer
98    ///
99    /// On success, returns `Poll::Ready(Ok(num_bytes_read))` and places data into `buf`. If this
100    /// returns zero bytes read (and `buf` has a non-zero length), that indicates that the remote
101    /// side has [`finish`]ed the stream and the local side has already read all bytes.
102    ///
103    /// If no data is available for reading, this returns `Poll::Pending` and arranges for the
104    /// current task (via `cx.waker()`) to be notified when the stream becomes readable or is
105    /// closed.
106    ///
107    /// [`finish`]: crate::SendStream::finish
108    pub fn poll_read(
109        &mut self,
110        cx: &mut Context,
111        buf: &mut [u8],
112    ) -> Poll<Result<usize, ReadError>> {
113        let mut buf = ReadBuf::new(buf);
114        ready!(self.poll_read_buf(cx, &mut buf))?;
115        Poll::Ready(Ok(buf.filled().len()))
116    }
117
118    /// Attempts to read from the stream into the provided buffer, which may be uninitialized
119    ///
120    /// On success, returns `Poll::Ready(Ok(()))` and places data into the unfilled portion of
121    /// `buf`. If this does not write any bytes to `buf` (and `buf.remaining()` is non-zero), that
122    /// indicates that the remote side has [`finish`]ed the stream and the local side has already
123    /// read all bytes.
124    ///
125    /// If no data is available for reading, this returns `Poll::Pending` and arranges for the
126    /// current task (via `cx.waker()`) to be notified when the stream becomes readable or is
127    /// closed.
128    ///
129    /// [`finish`]: crate::SendStream::finish
130    pub fn poll_read_buf(
131        &mut self,
132        cx: &mut Context,
133        buf: &mut ReadBuf<'_>,
134    ) -> Poll<Result<(), ReadError>> {
135        if buf.remaining() == 0 {
136            return Poll::Ready(Ok(()));
137        }
138
139        self.poll_read_generic(cx, true, |chunks| {
140            let mut read = false;
141            loop {
142                if buf.remaining() == 0 {
143                    // We know `read` is `true` because `buf.remaining()` was not 0 before
144                    return ReadStatus::Readable(());
145                }
146
147                match chunks.next(buf.remaining()) {
148                    Ok(Some(chunk)) => {
149                        buf.put_slice(&chunk.bytes);
150                        read = true;
151                    }
152                    res => return (if read { Some(()) } else { None }, res.err()).into(),
153                }
154            }
155        })
156        .map(|res| res.map(|_| ()))
157    }
158
159    /// Read the next segment of data
160    ///
161    /// Yields `None` if the stream was finished. Otherwise, yields a segment of data and its
162    /// offset in the stream. If `ordered` is `true`, the chunk's offset will be immediately after
163    /// the last data yielded by `read()` or `read_chunk()`. If `ordered` is `false`, segments may
164    /// be received in any order, and the `Chunk`'s `offset` field can be used to determine
165    /// ordering in the caller. Unordered reads are less prone to head-of-line blocking within a
166    /// stream, but require the application to manage reassembling the original data.
167    ///
168    /// Slightly more efficient than `read` due to not copying. Chunk boundaries do not correspond
169    /// to peer writes, and hence cannot be used as framing.
170    ///
171    /// This operation is cancel-safe.
172    pub async fn read_chunk(
173        &mut self,
174        max_length: usize,
175        ordered: bool,
176    ) -> Result<Option<Chunk>, ReadError> {
177        ReadChunk {
178            stream: self,
179            max_length,
180            ordered,
181        }
182        .await
183    }
184
185    /// Attempts to read a chunk from the stream.
186    ///
187    /// On success, returns `Poll::Ready(Ok(Some(chunk)))`. If `Poll::Ready(Ok(None))`
188    /// is returned, it implies that EOF has been reached.
189    ///
190    /// If no data is available for reading, the method returns `Poll::Pending`
191    /// and arranges for the current task (via cx.waker()) to receive a notification
192    /// when the stream becomes readable or is closed.
193    fn poll_read_chunk(
194        &mut self,
195        cx: &mut Context,
196        max_length: usize,
197        ordered: bool,
198    ) -> Poll<Result<Option<Chunk>, ReadError>> {
199        self.poll_read_generic(cx, ordered, |chunks| match chunks.next(max_length) {
200            Ok(Some(chunk)) => ReadStatus::Readable(chunk),
201            res => (None, res.err()).into(),
202        })
203    }
204
205    /// Read the next segments of data
206    ///
207    /// Fills `bufs` with the segments of data beginning immediately after the
208    /// last data yielded by `read` or `read_chunk`, or `None` if the stream was
209    /// finished.
210    ///
211    /// Slightly more efficient than `read` due to not copying. Chunk boundaries
212    /// do not correspond to peer writes, and hence cannot be used as framing.
213    ///
214    /// This operation is cancel-safe.
215    pub async fn read_chunks(&mut self, bufs: &mut [Bytes]) -> Result<Option<usize>, ReadError> {
216        ReadChunks { stream: self, bufs }.await
217    }
218
219    /// Foundation of [`Self::read_chunks`]
220    fn poll_read_chunks(
221        &mut self,
222        cx: &mut Context,
223        bufs: &mut [Bytes],
224    ) -> Poll<Result<Option<usize>, ReadError>> {
225        if bufs.is_empty() {
226            return Poll::Ready(Ok(Some(0)));
227        }
228
229        self.poll_read_generic(cx, true, |chunks| {
230            let mut read = 0;
231            loop {
232                if read >= bufs.len() {
233                    // We know `read > 0` because `bufs` cannot be empty here
234                    return ReadStatus::Readable(read);
235                }
236
237                match chunks.next(usize::MAX) {
238                    Ok(Some(chunk)) => {
239                        bufs[read] = chunk.bytes;
240                        read += 1;
241                    }
242                    res => return (if read == 0 { None } else { Some(read) }, res.err()).into(),
243                }
244            }
245        })
246    }
247
248    /// Convenience method to read all remaining data into a buffer
249    ///
250    /// Fails with [`ReadToEndError::TooLong`] on reading more than `size_limit` bytes, discarding
251    /// all data read. Uses unordered reads to be more efficient than using `AsyncRead` would
252    /// allow. `size_limit` should be set to limit worst-case memory use.
253    ///
254    /// If unordered reads have already been made, the resulting buffer may have gaps containing
255    /// arbitrary data.
256    ///
257    /// This operation is *not* cancel-safe.
258    ///
259    /// [`ReadToEndError::TooLong`]: crate::ReadToEndError::TooLong
260    pub async fn read_to_end(&mut self, size_limit: usize) -> Result<Vec<u8>, ReadToEndError> {
261        ReadToEnd {
262            stream: self,
263            size_limit,
264            read: Vec::new(),
265            start: u64::MAX,
266            end: 0,
267        }
268        .await
269    }
270
271    /// Stop accepting data
272    ///
273    /// Discards unread data and notifies the peer to stop transmitting. Once stopped, further
274    /// attempts to operate on a stream will yield `ClosedStream` errors.
275    pub fn stop(&mut self, error_code: VarInt) -> Result<(), ClosedStream> {
276        let mut conn = self.conn.state.lock("RecvStream::stop");
277        if self.is_0rtt && conn.check_0rtt().is_err() {
278            return Ok(());
279        }
280        conn.inner.recv_stream(self.stream).stop(error_code)?;
281        conn.wake();
282        self.all_data_read = true;
283        // Clean up shared state that might be left over from a cancalled read
284        // operation, so `drop` doesn't have to
285        conn.blocked_readers.remove(&self.stream);
286        Ok(())
287    }
288
289    /// Check if this stream has been opened during 0-RTT.
290    ///
291    /// In which case any non-idempotent request should be considered dangerous at the application
292    /// level. Because read data is subject to replay attacks.
293    pub fn is_0rtt(&self) -> bool {
294        self.is_0rtt
295    }
296
297    /// Get the identity of this stream
298    pub fn id(&self) -> StreamId {
299        self.stream
300    }
301
302    /// Completes when the stream has been reset by the peer or otherwise closed
303    ///
304    /// Yields `Some` with the reset error code when the stream is reset by the peer. Yields `None`
305    /// when the stream was previously [`stop()`](Self::stop)ed, or when the stream was
306    /// [`finish()`](crate::SendStream::finish)ed by the peer and all data has been received, after
307    /// which it is no longer meaningful for the stream to be reset.
308    ///
309    /// This operation is cancel-safe.
310    pub async fn received_reset(&mut self) -> Result<Option<VarInt>, ResetError> {
311        poll_fn(|cx| {
312            let mut conn = self.conn.state.lock("RecvStream::reset");
313            if self.is_0rtt && conn.check_0rtt().is_err() {
314                return Poll::Ready(Err(ResetError::ZeroRttRejected));
315            }
316
317            if let Some(code) = self.reset {
318                return Poll::Ready(Ok(Some(code)));
319            }
320
321            match conn.inner.recv_stream(self.stream).received_reset() {
322                Err(_) => Poll::Ready(Ok(None)),
323                Ok(Some(error_code)) => {
324                    // Stream state has just now been freed, so the connection may need to issue new
325                    // stream ID flow control credit
326                    conn.wake();
327                    Poll::Ready(Ok(Some(error_code)))
328                }
329                Ok(None) => {
330                    if let Some(e) = &conn.error {
331                        return Poll::Ready(Err(e.clone().into()));
332                    }
333                    // Resets always notify readers, since a reset is an immediate read error. We
334                    // could introduce a dedicated channel to reduce the risk of spurious wakeups,
335                    // but that increased complexity is probably not justified, as an application
336                    // that is expecting a reset is not likely to receive large amounts of data.
337                    conn.blocked_readers.insert(self.stream, cx.waker().clone());
338                    Poll::Pending
339                }
340            }
341        })
342        .await
343    }
344
345    /// Handle common logic related to reading out of a receive stream
346    ///
347    /// This takes an `FnMut` closure that takes care of the actual reading process, matching
348    /// the detailed read semantics for the calling function with a particular return type.
349    /// The closure can read from the passed `&mut Chunks` and has to return the status after
350    /// reading: the amount of data read, and the status after the final read call.
351    fn poll_read_generic<T, U>(
352        &mut self,
353        cx: &mut Context,
354        ordered: bool,
355        mut read_fn: T,
356    ) -> Poll<Result<Option<U>, ReadError>>
357    where
358        T: FnMut(&mut Chunks) -> ReadStatus<U>,
359    {
360        use proto::ReadError::*;
361        if self.all_data_read {
362            return Poll::Ready(Ok(None));
363        }
364
365        let mut conn = self.conn.state.lock("RecvStream::poll_read");
366        if self.is_0rtt {
367            conn.check_0rtt().map_err(|()| ReadError::ZeroRttRejected)?;
368        }
369
370        // If we stored an error during a previous call, return it now. This can happen if a
371        // `read_fn` both wants to return data and also returns an error in its final stream status.
372        let status = match self.reset {
373            Some(code) => ReadStatus::Failed(None, Reset(code)),
374            None => {
375                let mut recv = conn.inner.recv_stream(self.stream);
376                let mut chunks = recv.read(ordered)?;
377                let status = read_fn(&mut chunks);
378                if chunks.finalize().should_transmit() {
379                    conn.wake();
380                }
381                status
382            }
383        };
384
385        match status {
386            ReadStatus::Readable(read) => Poll::Ready(Ok(Some(read))),
387            ReadStatus::Finished(read) => {
388                self.all_data_read = true;
389                Poll::Ready(Ok(read))
390            }
391            ReadStatus::Failed(read, Blocked) => match read {
392                Some(val) => Poll::Ready(Ok(Some(val))),
393                None => {
394                    if let Some(ref x) = conn.error {
395                        return Poll::Ready(Err(ReadError::ConnectionLost(x.clone())));
396                    }
397                    conn.blocked_readers.insert(self.stream, cx.waker().clone());
398                    Poll::Pending
399                }
400            },
401            ReadStatus::Failed(read, Reset(error_code)) => match read {
402                None => {
403                    self.all_data_read = true;
404                    self.reset = Some(error_code);
405                    Poll::Ready(Err(ReadError::Reset(error_code)))
406                }
407                done => {
408                    self.reset = Some(error_code);
409                    Poll::Ready(Ok(done))
410                }
411            },
412        }
413    }
414}
415
416enum ReadStatus<T> {
417    Readable(T),
418    Finished(Option<T>),
419    Failed(Option<T>, proto::ReadError),
420}
421
422impl<T> From<(Option<T>, Option<proto::ReadError>)> for ReadStatus<T> {
423    fn from(status: (Option<T>, Option<proto::ReadError>)) -> Self {
424        match status {
425            (read, None) => Self::Finished(read),
426            (read, Some(e)) => Self::Failed(read, e),
427        }
428    }
429}
430
431/// Future produced by [`RecvStream::read_to_end()`].
432///
433/// [`RecvStream::read_to_end()`]: crate::RecvStream::read_to_end
434struct ReadToEnd<'a> {
435    stream: &'a mut RecvStream,
436    read: Vec<(Bytes, u64)>,
437    start: u64,
438    end: u64,
439    size_limit: usize,
440}
441
442impl Future for ReadToEnd<'_> {
443    type Output = Result<Vec<u8>, ReadToEndError>;
444    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
445        loop {
446            match ready!(self.stream.poll_read_chunk(cx, usize::MAX, false))? {
447                Some(chunk) => {
448                    self.start = self.start.min(chunk.offset);
449                    let end = chunk.bytes.len() as u64 + chunk.offset;
450                    if (end - self.start) > self.size_limit as u64 {
451                        return Poll::Ready(Err(ReadToEndError::TooLong));
452                    }
453                    self.end = self.end.max(end);
454                    self.read.push((chunk.bytes, chunk.offset));
455                }
456                None => {
457                    if self.end == 0 {
458                        // Never received anything
459                        return Poll::Ready(Ok(Vec::new()));
460                    }
461                    let start = self.start;
462                    let mut buffer = vec![0; (self.end - start) as usize];
463                    for (data, offset) in self.read.drain(..) {
464                        let offset = (offset - start) as usize;
465                        buffer[offset..offset + data.len()].copy_from_slice(&data);
466                    }
467                    return Poll::Ready(Ok(buffer));
468                }
469            }
470        }
471    }
472}
473
474/// Errors from [`RecvStream::read_to_end`]
475#[derive(Debug, Error, Clone, PartialEq, Eq)]
476pub enum ReadToEndError {
477    /// An error occurred during reading
478    #[error("read error: {0}")]
479    Read(#[from] ReadError),
480    /// The stream is larger than the user-supplied limit
481    #[error("stream too long")]
482    TooLong,
483}
484
485#[cfg(feature = "futures-io")]
486impl futures_io::AsyncRead for RecvStream {
487    fn poll_read(
488        self: Pin<&mut Self>,
489        cx: &mut Context,
490        buf: &mut [u8],
491    ) -> Poll<io::Result<usize>> {
492        let mut buf = ReadBuf::new(buf);
493        ready!(Self::poll_read_buf(self.get_mut(), cx, &mut buf))?;
494        Poll::Ready(Ok(buf.filled().len()))
495    }
496}
497
498impl tokio::io::AsyncRead for RecvStream {
499    fn poll_read(
500        self: Pin<&mut Self>,
501        cx: &mut Context<'_>,
502        buf: &mut ReadBuf<'_>,
503    ) -> Poll<io::Result<()>> {
504        ready!(Self::poll_read_buf(self.get_mut(), cx, buf))?;
505        Poll::Ready(Ok(()))
506    }
507}
508
509impl Drop for RecvStream {
510    fn drop(&mut self) {
511        if self.all_data_read {
512            debug_assert!(
513                !self
514                    .conn
515                    .state
516                    .lock("RecvStream:drop")
517                    .blocked_readers
518                    .contains_key(&self.stream),
519                "Stream {} should not have a blocked reader when all data read is true",
520                &self.stream
521            );
522            return;
523        }
524        let mut conn = self.conn.state.lock("RecvStream::drop");
525
526        // clean up any previously registered wakers
527        conn.blocked_readers.remove(&self.stream);
528
529        if conn.error.is_some() || (self.is_0rtt && conn.check_0rtt().is_err()) {
530            return;
531        }
532
533        // Ignore ClosedStream errors
534        let _ = conn.inner.recv_stream(self.stream).stop(0u32.into());
535        conn.wake();
536    }
537}
538
539/// Errors that arise from reading from a stream.
540#[derive(Debug, Error, Clone, PartialEq, Eq)]
541pub enum ReadError {
542    /// The peer abandoned transmitting data on this stream
543    ///
544    /// Carries an application-defined error code.
545    #[error("stream reset by peer: error {0}")]
546    Reset(VarInt),
547    /// The connection was lost
548    #[error("connection lost")]
549    ConnectionLost(#[from] ConnectionError),
550    /// The stream has already been stopped, finished, or reset
551    #[error("closed stream")]
552    ClosedStream,
553    /// Attempted an ordered read following an unordered read
554    ///
555    /// Performing an unordered read allows discontinuities to arise in the receive buffer of a
556    /// stream which cannot be recovered, making further ordered reads impossible.
557    #[error("ordered read after unordered read")]
558    IllegalOrderedRead,
559    /// This was a 0-RTT stream and the server rejected it
560    ///
561    /// Can only occur on clients for 0-RTT streams, which can be opened using
562    /// [`Connecting::into_0rtt()`].
563    ///
564    /// [`Connecting::into_0rtt()`]: crate::Connecting::into_0rtt()
565    #[error("0-RTT rejected")]
566    ZeroRttRejected,
567}
568
569impl From<ReadableError> for ReadError {
570    fn from(e: ReadableError) -> Self {
571        match e {
572            ReadableError::ClosedStream => Self::ClosedStream,
573            ReadableError::IllegalOrderedRead => Self::IllegalOrderedRead,
574        }
575    }
576}
577
578impl From<ResetError> for ReadError {
579    fn from(e: ResetError) -> Self {
580        match e {
581            ResetError::ConnectionLost(e) => Self::ConnectionLost(e),
582            ResetError::ZeroRttRejected => Self::ZeroRttRejected,
583        }
584    }
585}
586
587impl From<ReadError> for io::Error {
588    fn from(x: ReadError) -> Self {
589        use ReadError::*;
590        let kind = match x {
591            Reset { .. } | ZeroRttRejected => io::ErrorKind::ConnectionReset,
592            ConnectionLost(_) | ClosedStream => io::ErrorKind::NotConnected,
593            IllegalOrderedRead => io::ErrorKind::InvalidInput,
594        };
595        Self::new(kind, x)
596    }
597}
598
599/// Errors that arise while waiting for a stream to be reset
600#[derive(Debug, Error, Clone, PartialEq, Eq)]
601pub enum ResetError {
602    /// The connection was lost
603    #[error("connection lost")]
604    ConnectionLost(#[from] ConnectionError),
605    /// This was a 0-RTT stream and the server rejected it
606    ///
607    /// Can only occur on clients for 0-RTT streams, which can be opened using
608    /// [`Connecting::into_0rtt()`].
609    ///
610    /// [`Connecting::into_0rtt()`]: crate::Connecting::into_0rtt()
611    #[error("0-RTT rejected")]
612    ZeroRttRejected,
613}
614
615impl From<ResetError> for io::Error {
616    fn from(x: ResetError) -> Self {
617        use ResetError::*;
618        let kind = match x {
619            ZeroRttRejected => io::ErrorKind::ConnectionReset,
620            ConnectionLost(_) => io::ErrorKind::NotConnected,
621        };
622        Self::new(kind, x)
623    }
624}
625
626/// Future produced by [`RecvStream::read()`].
627///
628/// [`RecvStream::read()`]: crate::RecvStream::read
629struct Read<'a> {
630    stream: &'a mut RecvStream,
631    buf: ReadBuf<'a>,
632}
633
634impl Future for Read<'_> {
635    type Output = Result<Option<usize>, ReadError>;
636
637    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
638        let this = self.get_mut();
639        ready!(this.stream.poll_read_buf(cx, &mut this.buf))?;
640        match this.buf.filled().len() {
641            0 if this.buf.capacity() != 0 => Poll::Ready(Ok(None)),
642            n => Poll::Ready(Ok(Some(n))),
643        }
644    }
645}
646
647/// Future produced by [`RecvStream::read_exact()`].
648///
649/// [`RecvStream::read_exact()`]: crate::RecvStream::read_exact
650struct ReadExact<'a> {
651    stream: &'a mut RecvStream,
652    buf: ReadBuf<'a>,
653}
654
655impl Future for ReadExact<'_> {
656    type Output = Result<(), ReadExactError>;
657    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
658        let this = self.get_mut();
659        let mut remaining = this.buf.remaining();
660        while remaining > 0 {
661            ready!(this.stream.poll_read_buf(cx, &mut this.buf))?;
662            let new = this.buf.remaining();
663            if new == remaining {
664                return Poll::Ready(Err(ReadExactError::FinishedEarly(this.buf.filled().len())));
665            }
666            remaining = new;
667        }
668        Poll::Ready(Ok(()))
669    }
670}
671
672/// Errors that arise from reading from a stream.
673#[derive(Debug, Error, Clone, PartialEq, Eq)]
674pub enum ReadExactError {
675    /// The stream finished before all bytes were read
676    #[error("stream finished early ({0} bytes read)")]
677    FinishedEarly(usize),
678    /// A read error occurred
679    #[error(transparent)]
680    ReadError(#[from] ReadError),
681}
682
683/// Future produced by [`RecvStream::read_chunk()`].
684///
685/// [`RecvStream::read_chunk()`]: crate::RecvStream::read_chunk
686struct ReadChunk<'a> {
687    stream: &'a mut RecvStream,
688    max_length: usize,
689    ordered: bool,
690}
691
692impl Future for ReadChunk<'_> {
693    type Output = Result<Option<Chunk>, ReadError>;
694    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
695        let (max_length, ordered) = (self.max_length, self.ordered);
696        self.stream.poll_read_chunk(cx, max_length, ordered)
697    }
698}
699
700/// Future produced by [`RecvStream::read_chunks()`].
701///
702/// [`RecvStream::read_chunks()`]: crate::RecvStream::read_chunks
703struct ReadChunks<'a> {
704    stream: &'a mut RecvStream,
705    bufs: &'a mut [Bytes],
706}
707
708impl Future for ReadChunks<'_> {
709    type Output = Result<Option<usize>, ReadError>;
710    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
711        let this = self.get_mut();
712        this.stream.poll_read_chunks(cx, this.bufs)
713    }
714}