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