Skip to main content

musli_web/
buf.rs

1use core::cell::Cell;
2use core::fmt;
3use core::mem;
4use core::num::NonZeroUsize;
5use core::ops::Range;
6
7use alloc::vec::Vec;
8use musli::mode::Binary;
9use musli::{Encode, storage};
10
11#[derive(Debug)]
12enum InvalidFrameWhat {
13    ReadPosition(usize),
14    LengthPrefix,
15    LengthPrefixOverflow(u32),
16    InsufficientLength(usize),
17    InsufficientFrame(usize),
18}
19
20impl fmt::Display for InvalidFrameWhat {
21    #[inline]
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        match self {
24            Self::ReadPosition(pos) => write!(f, "read position ({pos}) out of bounds"),
25            Self::LengthPrefix => write!(f, "4 byte length prefix out of bounds"),
26            Self::LengthPrefixOverflow(len) => write!(f, "length prefix {len} overflowed usize"),
27            Self::InsufficientLength(len) => {
28                write!(f, "insufficient data for length (needed {len} bytes)")
29            }
30            Self::InsufficientFrame(len) => {
31                write!(f, "insufficient data for frame (needed {len} bytes)")
32            }
33        }
34    }
35}
36
37#[derive(Debug)]
38pub(crate) struct InvalidFrame {
39    what: InvalidFrameWhat,
40    range: Range<usize>,
41    size: usize,
42}
43
44impl fmt::Display for InvalidFrame {
45    #[inline]
46    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47        write!(
48            f,
49            "{} {}-{} (has {} bytes)",
50            self.what, self.range.start, self.range.end, self.size
51        )
52    }
53}
54
55/// A length-prefixed buffer which keeps track of the start of each frame and
56/// allows them to be iterated over.
57#[derive(Default)]
58pub(crate) struct Buf {
59    start: Option<NonZeroUsize>,
60    buffer: Vec<u8>,
61    read: Cell<usize>,
62}
63
64impl Buf {
65    /// Write data to the current frame, or start a new frame if no frame is
66    /// being written.
67    ///
68    /// This needs to be paired with a call to [`Buf::done`] to complete an
69    /// outgoing frame.
70    ///
71    /// If a new frame is started, a new start point is recorded.
72    #[inline]
73    pub(crate) fn write<T>(&mut self, value: T) -> Result<(), storage::Error>
74    where
75        T: Encode<Binary>,
76    {
77        if self.start.is_none() {
78            let bytes = 0u32.to_le_bytes();
79            self.buffer.extend_from_slice(&bytes);
80            self.start = NonZeroUsize::new(self.buffer.len());
81        }
82
83        storage::to_writer(&mut self.buffer, &value)?;
84        Ok(())
85    }
86
87    /// Check if the buffer is empty.
88    #[inline]
89    pub(crate) fn is_empty(&self) -> bool {
90        // NB: Read should never exceed the length of the buffer.
91        debug_assert!(self.read.get() <= self.buffer.len());
92        self.read.get() >= self.buffer.len()
93    }
94
95    fn len_at_mut(&mut self, at: usize) -> Option<&mut [u8; 4]> {
96        match self.buffer.get_mut(at..at + mem::size_of::<u32>())? {
97            bytes if bytes.len() == mem::size_of::<u32>() => {
98                Some(unsafe { &mut *bytes.as_mut_ptr().cast() })
99            }
100            _ => None,
101        }
102    }
103
104    /// Mark an outgoing frame as done from the previous start point.
105    ///
106    /// If no start point is recorded, calling this method does nothing.
107    #[inline]
108    pub(crate) fn done(&mut self) {
109        if let Some(start) = self.start.take() {
110            let l = u32::try_from(self.buffer.len().saturating_sub(start.get()))
111                .unwrap_or(u32::MAX)
112                .to_le_bytes();
113
114            let Some(len) = self.len_at_mut(start.get().saturating_sub(mem::size_of::<u32>()))
115            else {
116                return;
117            };
118
119            *len = l;
120        }
121    }
122
123    /// Reset the buffer to the previous start point.
124    ///
125    /// If no start point is set, this method does nothing.
126    #[inline]
127    pub(crate) fn reset(&mut self) {
128        if let Some(start) = self.start {
129            self.buffer.truncate(start.get());
130        }
131    }
132
133    #[inline]
134    pub(crate) fn clear(&mut self) {
135        self.start = None;
136        self.buffer.clear();
137        self.read.set(0);
138    }
139
140    /// Get the next frame starting at the given location.
141    #[inline]
142    pub(crate) fn read(&self) -> Result<Option<&[u8]>, InvalidFrame> {
143        let read = self.read.get();
144
145        if self.buffer.len() == read {
146            return Ok(None);
147        }
148
149        let Some(tail) = self.buffer.get(read..) else {
150            return Err(InvalidFrame {
151                what: InvalidFrameWhat::ReadPosition(read),
152                range: 0..read,
153                size: self.buffer.len(),
154            });
155        };
156
157        let Some((head, tail)) = tail.split_at_checked(mem::size_of::<u32>()) else {
158            return Err(InvalidFrame {
159                what: InvalidFrameWhat::InsufficientLength(mem::size_of::<u32>()),
160                range: 0..read,
161                size: self.buffer.len(),
162            });
163        };
164
165        let frame = read..read + mem::size_of::<u32>();
166
167        let &[a, b, c, d] = head else {
168            return Err(InvalidFrame {
169                what: InvalidFrameWhat::LengthPrefix,
170                range: frame.clone(),
171                size: self.buffer.len(),
172            });
173        };
174
175        let len = u32::from_le_bytes([a, b, c, d]);
176
177        let Ok(len) = usize::try_from(len) else {
178            return Err(InvalidFrame {
179                what: InvalidFrameWhat::LengthPrefixOverflow(len),
180                range: frame.clone(),
181                size: self.buffer.len(),
182            });
183        };
184
185        let Some(out) = tail.get(..len) else {
186            return Err(InvalidFrame {
187                what: InvalidFrameWhat::InsufficientFrame(len),
188                range: frame.start..frame.end + len,
189                size: self.buffer.len(),
190            });
191        };
192
193        let next = read
194            .saturating_add(mem::size_of::<u32>())
195            .saturating_add(len);
196
197        self.read.set(next);
198        Ok(Some(out))
199    }
200}