Skip to main content

rama_core/io/
read.rs

1use pin_project_lite::pin_project;
2use std::{
3    io::{Cursor, Read},
4    pin::Pin,
5    task::{Context, Poll, ready},
6};
7use tokio::io::{self, AsyncBufRead, AsyncRead, ReadBuf};
8
9use crate::bytes::{Buf, Bytes};
10
11/// Read and discard exactly `n` bytes from `reader`.
12///
13/// Equivalent to `reader.read_exact(&mut vec![0u8; n])` but does not allocate
14/// a buffer sized to `n`; it pipes the bytes through [`tokio::io::sink`] via
15/// a `take` adaptor, reusing a small internal scratch buffer instead.
16///
17/// Returns an `UnexpectedEof` error if the reader yields fewer than `n` bytes
18/// before EOF.
19pub async fn discard<R>(reader: &mut R, n: u64) -> io::Result<()>
20where
21    R: AsyncRead + Unpin,
22{
23    if n == 0 {
24        return Ok(());
25    }
26    let mut limited = tokio::io::AsyncReadExt::take(reader, n);
27    let copied = tokio::io::copy(&mut limited, &mut tokio::io::sink()).await?;
28    if copied < n {
29        return Err(io::Error::new(
30            io::ErrorKind::UnexpectedEof,
31            "io::discard: reader EOF before requested byte count was consumed",
32        ));
33    }
34    Ok(())
35}
36
37pin_project! {
38    /// Reader for reading from a heap-allocated bytes buffer.
39    #[derive(Debug, Clone)]
40    pub struct HeapReader {
41        #[pin]
42        inner: Cursor<Vec<u8>>,
43    }
44}
45
46impl HeapReader {
47    /// Creates a new `HeapReader` with the specified bytes data.
48    #[must_use]
49    pub const fn new(data: Vec<u8>) -> Self {
50        Self {
51            inner: Cursor::new(data),
52        }
53    }
54
55    /// How many bytes are there remaining
56    #[must_use]
57    pub fn remaining(&self) -> usize {
58        self.inner.remaining()
59    }
60
61    /// Returns true if there are any more bytes to consume
62    #[must_use]
63    pub fn has_remaining(&self) -> bool {
64        self.inner.has_remaining()
65    }
66}
67
68impl From<Vec<u8>> for HeapReader {
69    fn from(data: Vec<u8>) -> Self {
70        Self::new(data)
71    }
72}
73
74impl From<&[u8]> for HeapReader {
75    fn from(data: &[u8]) -> Self {
76        Self::new(data.to_vec())
77    }
78}
79
80impl From<&str> for HeapReader {
81    fn from(data: &str) -> Self {
82        Self::new(data.as_bytes().to_vec())
83    }
84}
85
86impl Default for HeapReader {
87    fn default() -> Self {
88        Self::new(Vec::new())
89    }
90}
91
92impl From<Bytes> for HeapReader {
93    fn from(data: Bytes) -> Self {
94        Self::new(data.to_vec())
95    }
96}
97
98#[warn(clippy::missing_trait_methods)]
99impl AsyncRead for HeapReader {
100    fn poll_read(
101        self: Pin<&mut Self>,
102        cx: &mut Context<'_>,
103        buf: &mut ReadBuf<'_>,
104    ) -> Poll<io::Result<()>> {
105        self.project().inner.poll_read(cx, buf)
106    }
107}
108
109#[warn(clippy::missing_trait_methods)]
110impl AsyncBufRead for HeapReader {
111    fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
112        self.project().inner.poll_fill_buf(cx)
113    }
114
115    fn consume(self: Pin<&mut Self>, amt: usize) {
116        self.project().inner.consume(amt);
117    }
118}
119
120impl Read for HeapReader {
121    #[inline]
122    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
123        self.inner.read(buf)
124    }
125
126    #[inline]
127    fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
128        self.inner.read_exact(buf)
129    }
130
131    #[inline]
132    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> std::io::Result<usize> {
133        self.inner.read_to_end(buf)
134    }
135
136    #[inline]
137    fn read_to_string(&mut self, buf: &mut String) -> std::io::Result<usize> {
138        self.inner.read_to_string(buf)
139    }
140
141    #[inline]
142    fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result<usize> {
143        self.inner.read_vectored(bufs)
144    }
145}
146
147/// Reader for reading from a stack buffer
148#[derive(Debug, Clone)]
149pub struct StackReader<const N: usize> {
150    data: [u8; N],
151    offset: usize,
152}
153
154impl<const N: usize> StackReader<N> {
155    /// Creates a new `StackReader` with the specified bytes data.
156    #[must_use]
157    pub const fn new(data: [u8; N]) -> Self {
158        Self { data, offset: 0 }
159    }
160
161    /// Skip up to n bytes, less if n < m
162    pub fn skip(&mut self, n: usize) {
163        self.offset = (self.offset + n).min(N);
164    }
165
166    /// How many bytes are there remaining
167    #[must_use]
168    pub fn remaining(&self) -> usize {
169        N - self.offset
170    }
171
172    /// Returns true if there are any more bytes to consume
173    #[must_use]
174    pub fn has_remaining(&self) -> bool {
175        self.remaining() > 0
176    }
177}
178
179impl<const N: usize> From<[u8; N]> for StackReader<N> {
180    #[inline]
181    fn from(data: [u8; N]) -> Self {
182        Self::new(data)
183    }
184}
185
186impl<const N: usize> AsyncRead for StackReader<N> {
187    fn poll_read(
188        mut self: Pin<&mut Self>,
189        _cx: &mut Context<'_>,
190        buf: &mut ReadBuf<'_>,
191    ) -> Poll<io::Result<()>> {
192        if self.offset < N {
193            let remaining = &self.data[self.offset..];
194            let to_copy = remaining.len().min(buf.remaining());
195
196            if to_copy > 0 {
197                buf.put_slice(&remaining[..to_copy]);
198                self.offset += to_copy;
199            }
200        }
201
202        // done
203        Poll::Ready(Ok(()))
204    }
205}
206
207impl<const N: usize> AsyncBufRead for StackReader<N> {
208    fn poll_fill_buf(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
209        let me = self.get_mut();
210        Poll::Ready(Ok(if me.offset < N {
211            &me.data[me.offset..]
212        } else {
213            &[]
214        }))
215    }
216
217    fn consume(self: Pin<&mut Self>, amt: usize) {
218        self.get_mut().skip(amt)
219    }
220}
221
222impl<const N: usize> Read for StackReader<N> {
223    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
224        if self.offset < N {
225            let remaining = &self.data[self.offset..];
226            let to_copy = remaining.len().min(buf.len());
227
228            if to_copy > 0 {
229                buf[..to_copy].copy_from_slice(&remaining[..to_copy]);
230                self.offset += to_copy;
231                return Ok(to_copy);
232            }
233        }
234
235        // done
236        Ok(0)
237    }
238}
239
240/// Reader replaying a [`Bytes`] buffer, releasing it once fully consumed.
241///
242/// Unlike [`HeapReader`] the backing allocation is dropped at EOF, so the
243/// reader can be held for a connection's lifetime (e.g. as the prefix of a
244/// [`PrefixedIo`]) without retaining the replayed bytes.
245///
246/// [`PrefixedIo`]: super::PrefixedIo
247#[derive(Debug, Clone, Default)]
248pub struct ReplayReader {
249    data: Bytes,
250}
251
252impl ReplayReader {
253    /// Creates a new `ReplayReader` with the specified bytes data.
254    #[must_use]
255    pub const fn new(data: Bytes) -> Self {
256        Self { data }
257    }
258
259    /// How many bytes are there remaining
260    #[must_use]
261    pub fn remaining(&self) -> usize {
262        self.data.len()
263    }
264
265    /// Returns true if there are any more bytes to consume
266    #[must_use]
267    pub fn has_remaining(&self) -> bool {
268        !self.data.is_empty()
269    }
270
271    fn advance(&mut self, n: usize) {
272        if n >= self.data.len() {
273            // EOF: release the backing allocation
274            self.data = Bytes::new();
275        } else {
276            self.data.advance(n);
277        }
278    }
279}
280
281impl From<Bytes> for ReplayReader {
282    #[inline]
283    fn from(data: Bytes) -> Self {
284        Self::new(data)
285    }
286}
287
288impl AsyncRead for ReplayReader {
289    fn poll_read(
290        mut self: Pin<&mut Self>,
291        _cx: &mut Context<'_>,
292        buf: &mut ReadBuf<'_>,
293    ) -> Poll<io::Result<()>> {
294        let to_copy = self.data.len().min(buf.remaining());
295        if to_copy > 0 {
296            buf.put_slice(&self.data[..to_copy]);
297            self.advance(to_copy);
298        }
299
300        // done
301        Poll::Ready(Ok(()))
302    }
303}
304
305impl AsyncBufRead for ReplayReader {
306    fn poll_fill_buf(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
307        Poll::Ready(Ok(&self.get_mut().data))
308    }
309
310    fn consume(self: Pin<&mut Self>, amt: usize) {
311        self.get_mut().advance(amt);
312    }
313}
314
315impl Read for ReplayReader {
316    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
317        let to_copy = self.data.len().min(buf.len());
318        if to_copy > 0 {
319            buf[..to_copy].copy_from_slice(&self.data[..to_copy]);
320            self.advance(to_copy);
321        }
322
323        // done
324        Ok(to_copy)
325    }
326}
327
328pin_project! {
329    /// Reader that can be used to chain two readers together.
330    #[must_use = "streams do nothing unless polled"]
331    #[derive(Debug, Clone)]
332    pub struct ChainReader<T, U> {
333        #[pin]
334        first: T,
335        #[pin]
336        second: U,
337        done_first: bool,
338    }
339}
340
341impl<T, U> ChainReader<T, U>
342where
343    T: AsyncRead,
344    U: AsyncRead,
345{
346    /// Creates a new `ChainReader` with the specified readers.
347    pub const fn new(first: T, second: U) -> Self {
348        Self {
349            first,
350            second,
351            done_first: false,
352        }
353    }
354
355    /// Gets references to the underlying readers in this `ChainReader`.
356    pub fn get_ref(&self) -> (&T, &U) {
357        (&self.first, &self.second)
358    }
359
360    /// Gets mutable references to the underlying readers in this `ChainReader`.
361    ///
362    /// Care should be taken to avoid modifying the internal I/O state of the
363    /// underlying readers as doing so may corrupt the internal state of this
364    /// `ChainReader`.
365    pub fn get_mut(&mut self) -> (&mut T, &mut U) {
366        (&mut self.first, &mut self.second)
367    }
368
369    /// Gets pinned mutable references to the underlying readers in this `ChainReader`.
370    ///
371    /// Care should be taken to avoid modifying the internal I/O state of the
372    /// underlying readers as doing so may corrupt the internal state of this
373    /// `ChainReader`.
374    #[must_use]
375    pub fn get_pin_mut(self: Pin<&mut Self>) -> (Pin<&mut T>, Pin<&mut U>) {
376        let me = self.project();
377        (me.first, me.second)
378    }
379
380    /// Consumes the `ChainReader`, returning the wrapped readers.
381    pub fn into_inner(self) -> (T, U) {
382        (self.first, self.second)
383    }
384}
385
386impl<T, U> AsyncRead for ChainReader<T, U>
387where
388    T: AsyncRead,
389    U: AsyncRead,
390{
391    fn poll_read(
392        self: Pin<&mut Self>,
393        cx: &mut Context<'_>,
394        buf: &mut ReadBuf<'_>,
395    ) -> Poll<io::Result<()>> {
396        let me = self.project();
397
398        if !*me.done_first {
399            let rem = buf.remaining();
400            ready!(me.first.poll_read(cx, buf))?;
401            if buf.remaining() == rem {
402                *me.done_first = true;
403            } else {
404                return Poll::Ready(Ok(()));
405            }
406        }
407        me.second.poll_read(cx, buf)
408    }
409}
410
411impl<T, U> Read for ChainReader<T, U>
412where
413    T: Read,
414    U: Read,
415{
416    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
417        if !self.done_first {
418            let n = self.first.read(buf)?;
419            if n == 0 {
420                self.done_first = true;
421            } else {
422                return Ok(n);
423            }
424        }
425        self.second.read(buf)
426    }
427}
428
429impl<T, U> AsyncBufRead for ChainReader<T, U>
430where
431    T: AsyncBufRead,
432    U: AsyncBufRead,
433{
434    fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
435        let me = self.project();
436
437        if !*me.done_first {
438            match ready!(me.first.poll_fill_buf(cx)?) {
439                [] => {
440                    *me.done_first = true;
441                }
442                buf => return Poll::Ready(Ok(buf)),
443            }
444        }
445        me.second.poll_fill_buf(cx)
446    }
447
448    fn consume(self: Pin<&mut Self>, amt: usize) {
449        let me = self.project();
450        if !*me.done_first {
451            me.first.consume(amt)
452        } else {
453            me.second.consume(amt)
454        }
455    }
456}
457
458#[cfg(test)]
459mod test {
460    use super::*;
461
462    use tokio::io::AsyncReadExt;
463
464    #[tokio::test]
465    async fn test_replay_reader_releases_buffer_at_eof() {
466        let data = Bytes::from(vec![7u8; 64]);
467        let mut reader = ReplayReader::new(data.clone());
468        let mut out = Vec::new();
469        tokio::io::AsyncReadExt::read_to_end(&mut reader, &mut out)
470            .await
471            .unwrap();
472        assert_eq!(vec![7u8; 64], out);
473        // the reader dropped its handle at EOF: ours is unique again
474        data.try_into_mut().expect("replay buffer was released");
475    }
476
477    #[tokio::test]
478    async fn test_discard_consumes_exact_bytes() {
479        let mut reader = Cursor::new(b"abcdefghij".to_vec());
480        discard(&mut reader, 4).await.unwrap();
481        let mut rest = Vec::new();
482        tokio::io::AsyncReadExt::read_to_end(&mut reader, &mut rest)
483            .await
484            .unwrap();
485        assert_eq!(rest, b"efghij");
486    }
487
488    #[tokio::test]
489    async fn test_discard_zero_is_noop() {
490        let mut reader = Cursor::new(b"abc".to_vec());
491        discard(&mut reader, 0).await.unwrap();
492        let mut rest = Vec::new();
493        tokio::io::AsyncReadExt::read_to_end(&mut reader, &mut rest)
494            .await
495            .unwrap();
496        assert_eq!(rest, b"abc");
497    }
498
499    #[tokio::test]
500    async fn test_discard_eof_before_n_errors() {
501        let mut reader = Cursor::new(b"abc".to_vec());
502        let err = discard(&mut reader, 10).await.unwrap_err();
503        assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof);
504    }
505
506    async fn test_multi_read_async<const N: usize>(
507        mut stream: impl AsyncRead + Unpin,
508        cases: &[&str],
509    ) {
510        let mut buf = [0u8; N];
511
512        for (i, case) in cases.iter().enumerate() {
513            let n = stream.read(&mut buf).await.unwrap();
514            assert_eq!(
515                n,
516                case.len(),
517                "[{N}][async] step #{} for cases: {:?}",
518                i + 1,
519                cases
520            );
521            assert_eq!(
522                &buf[..n],
523                case.as_bytes(),
524                "[{N}][async] step #{} for cases: {:?}",
525                i + 1,
526                cases
527            );
528        }
529    }
530
531    fn test_multi_read_sync<const N: usize>(mut stream: impl Read, cases: &[&str]) {
532        let mut buf = [0u8; N];
533
534        for (i, case) in cases.iter().enumerate() {
535            let n = stream.read(&mut buf).unwrap();
536            assert_eq!(
537                n,
538                case.len(),
539                "[{N}][sync] step #{} for cases: {:?}",
540                i + 1,
541                cases
542            );
543            assert_eq!(
544                &buf[..n],
545                case.as_bytes(),
546                "[{N}][sync] step #{} for cases: {:?}",
547                i + 1,
548                cases
549            );
550        }
551    }
552
553    #[derive(Debug)]
554    struct TestCase<const N: usize, R> {
555        reader: R,
556        expected_reads: &'static [&'static str],
557    }
558
559    impl<const N: usize, R: AsyncRead + Clone + Unpin + Read> TestCase<N, R> {
560        async fn test_sync_and_async(&self) {
561            let new_stream = || self.reader.clone();
562
563            test_multi_read_async::<N>(&mut new_stream(), self.expected_reads).await;
564            test_multi_read_sync::<N>(&mut new_stream(), self.expected_reads);
565        }
566    }
567
568    #[tokio::test]
569    async fn test_heap_reader() {
570        TestCase::<5, _> {
571            reader: HeapReader::from(""),
572            expected_reads: &[""],
573        }
574        .test_sync_and_async()
575        .await;
576
577        TestCase::<5, _> {
578            reader: HeapReader::from("hello world"),
579            expected_reads: &["hello", " worl", "d", ""],
580        }
581        .test_sync_and_async()
582        .await;
583
584        TestCase::<10, _> {
585            reader: HeapReader::from("hello world"),
586            expected_reads: &["hello worl", "d", ""],
587        }
588        .test_sync_and_async()
589        .await;
590    }
591
592    #[tokio::test]
593    async fn test_stack_reader() {
594        TestCase::<5, _> {
595            reader: StackReader::new(*b""),
596            expected_reads: &[""],
597        }
598        .test_sync_and_async()
599        .await;
600
601        TestCase::<5, _> {
602            reader: StackReader::new(*b"hello world"),
603            expected_reads: &["hello", " worl", "d", ""],
604        }
605        .test_sync_and_async()
606        .await;
607
608        TestCase::<10, _> {
609            reader: StackReader::from(*b"hello world"),
610            expected_reads: &["hello worl", "d", ""],
611        }
612        .test_sync_and_async()
613        .await;
614    }
615
616    #[tokio::test]
617    async fn test_chain_reader() {
618        TestCase::<5, _> {
619            reader: ChainReader::new(Cursor::new(""), Cursor::new("")),
620            expected_reads: &[""],
621        }
622        .test_sync_and_async()
623        .await;
624
625        TestCase::<5, _> {
626            reader: ChainReader::new(Cursor::new("hello world"), Cursor::new("")),
627            expected_reads: &["hello", " worl", "d", ""],
628        }
629        .test_sync_and_async()
630        .await;
631
632        TestCase::<5, _> {
633            reader: ChainReader::new(Cursor::new("hello "), Cursor::new("world")),
634            expected_reads: &["hello", " ", "world", ""],
635        }
636        .test_sync_and_async()
637        .await;
638
639        TestCase::<5, _> {
640            reader: ChainReader::new(Cursor::new(""), Cursor::new("hello world")),
641            expected_reads: &["hello", " worl", "d", ""],
642        }
643        .test_sync_and_async()
644        .await;
645    }
646}