Skip to main content

substrate_data/wire/io/
frame_reader.rs

1//! [`FrameReader`]: reads frames into one buffer it keeps.
2
3use std::io::{self, Read};
4
5use super::MAX_FRAME;
6use super::framing::{decode_frame, read_len};
7use crate::Schema;
8
9/// Reads frames into a buffer it keeps, so a stream of messages costs no
10/// allocation per frame once the buffer has grown to the biggest. The end
11/// rules are those of [`super::read_frame_bytes`]: a clean end only between
12/// frames; a stream cut inside a length or a frame is an error.
13///
14/// ```
15/// use substrate_data::io::{FrameReader, write_frame};
16///
17/// let mut pipe = Vec::new();
18/// write_frame(&mut pipe, &7_u32)?;
19/// write_frame(&mut pipe, &8_u32)?;
20/// let (mut r, mut frames) = (pipe.as_slice(), FrameReader::new());
21/// assert_eq!(frames.read::<u32>(&mut r)?, Some(7));
22/// assert_eq!(frames.read::<u32>(&mut r)?, Some(8));
23/// assert_eq!(frames.read::<u32>(&mut r)?, None);
24/// # Ok::<(), std::io::Error>(())
25/// ```
26#[derive(Debug, Default)]
27pub struct FrameReader {
28    buf: Vec<u8>,
29}
30
31impl FrameReader {
32    /// A reader with an empty buffer.
33    #[must_use]
34    pub fn new() -> Self {
35        Self::default()
36    }
37
38    /// The next frame's bytes, valid until the next read; `None` where the
39    /// stream ends between frames. The buffer grows as bytes arrive, never
40    /// by a length the peer merely claims.
41    ///
42    /// # Errors
43    ///
44    /// The reader's I/O error; [`io::ErrorKind::UnexpectedEof`] when the
45    /// stream ends inside a length or a frame; [`io::ErrorKind::InvalidData`]
46    /// for a length over [`MAX_FRAME`].
47    pub fn read_bytes(&mut self, r: &mut impl Read) -> io::Result<Option<&[u8]>> {
48        let Some(len) = read_len(r)? else {
49            return Ok(None);
50        };
51        let len = len as usize;
52        if len > MAX_FRAME {
53            return Err(io::Error::new(io::ErrorKind::InvalidData, "frame too long"));
54        }
55        self.buf.clear();
56        r.take(len as u64).read_to_end(&mut self.buf)?;
57        if self.buf.len() < len {
58            return Err(io::ErrorKind::UnexpectedEof.into());
59        }
60        Ok(Some(&self.buf))
61    }
62
63    /// The next message; `None` where the stream ends between frames.
64    ///
65    /// # Errors
66    ///
67    /// The reader's I/O error, or [`io::ErrorKind::InvalidData`] for a frame
68    /// that isn't a `T`.
69    pub fn read<T: Schema>(&mut self, r: &mut impl Read) -> io::Result<Option<T>> {
70        self.read_bytes(r)?.map(decode_frame).transpose()
71    }
72}