Skip to main content

musli_web/
buf.rs

1use core::cell::Cell;
2use core::cell::RefCell;
3use core::fmt;
4use core::mem;
5use core::mem::ManuallyDrop;
6use core::ops::Range;
7
8use alloc::vec::Vec;
9
10use crate::api::{EncodeBody, Format, Mode};
11use crate::format::{self, Envelope};
12
13#[derive(Debug)]
14#[cfg_attr(test, derive(PartialEq))]
15enum InvalidFrameWhat {
16    ReadPosition(usize),
17    LengthPrefix,
18    LengthPrefixOverflow(u32),
19    InsufficientLength(usize),
20    InsufficientFrame(usize),
21}
22
23impl fmt::Display for InvalidFrameWhat {
24    #[inline]
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        match self {
27            Self::ReadPosition(pos) => write!(f, "read position ({pos}) out of bounds"),
28            Self::LengthPrefix => write!(f, "4 byte length prefix out of bounds"),
29            Self::LengthPrefixOverflow(len) => write!(f, "length prefix {len} overflowed usize"),
30            Self::InsufficientLength(len) => {
31                write!(f, "insufficient data for length (needed {len} bytes)")
32            }
33            Self::InsufficientFrame(len) => {
34                write!(f, "insufficient data for frame (needed {len} bytes)")
35            }
36        }
37    }
38}
39
40#[derive(Debug)]
41#[cfg_attr(test, derive(PartialEq))]
42pub(crate) struct InvalidFrame {
43    what: InvalidFrameWhat,
44    range: Range<usize>,
45    size: usize,
46}
47
48impl fmt::Display for InvalidFrame {
49    #[inline]
50    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51        write!(
52            f,
53            "{} {}-{} (has {} bytes)",
54            self.what, self.range.start, self.range.end, self.size
55        )
56    }
57}
58
59#[must_use = "Writer must be consumed with Writer::flush to have an effect on the underlying buffer"]
60pub(crate) struct Writer<'a> {
61    start: usize,
62    buf: &'a mut Buf,
63}
64
65impl Writer<'_> {
66    /// Write the fixed envelope of a message to the current frame.
67    ///
68    /// The envelope never depends on the negotiated format, only on the [`Mode`]
69    /// the socket runs in, see the [wire format].
70    ///
71    /// [wire format]: crate::api#wire-format
72    #[inline]
73    pub(crate) fn envelope<T>(&mut self, mode: Mode, value: &T) -> Result<(), format::Error>
74    where
75        T: Envelope,
76    {
77        format::encode_envelope(mode, &mut self.buf.buffer, value)
78    }
79
80    /// Write the body of a message to the current frame using `format`.
81    #[inline]
82    pub(crate) fn body<T>(&mut self, format: Format, value: &T) -> Result<(), format::Error>
83    where
84        T: ?Sized + EncodeBody,
85    {
86        format.encode(&mut self.buf.buffer, value)
87    }
88
89    /// Write bytes which have already been encoded to the current frame.
90    #[inline]
91    #[cfg(feature = "ws")]
92    pub(crate) fn raw(&mut self, bytes: &[u8]) {
93        self.buf.buffer.extend_from_slice(bytes);
94    }
95
96    /// Finalize the current frame.
97    #[inline]
98    pub(crate) fn flush(self) {
99        let mut this = ManuallyDrop::new(self);
100        let start = this.start;
101        this.buf.done(start);
102    }
103}
104
105impl Drop for Writer<'_> {
106    #[inline]
107    fn drop(&mut self) {
108        self.buf.reset(self.start);
109    }
110}
111
112/// A length-prefixed buffer which keeps track of the start of each frame and
113/// allows them to be iterated over.
114#[derive(Default)]
115pub(crate) struct Buf {
116    buffer: Vec<u8>,
117    read: Cell<usize>,
118}
119
120impl Buf {
121    /// Start a write.
122    pub(crate) fn writer(&mut self) -> Writer<'_> {
123        if self.read.get() == self.buffer.len() {
124            self.buffer.clear();
125            self.read.set(0);
126        }
127
128        let start = self.buffer.len();
129        self.buffer.extend_from_slice(&[0; mem::size_of::<u32>()]);
130        Writer { start, buf: self }
131    }
132
133    #[inline]
134    #[cfg(test)]
135    pub(crate) fn is_empty(&self) -> bool {
136        // NB: Read should never exceed the length of the buffer.
137        debug_assert!(self.read.get() <= self.buffer.len());
138        self.read.get() >= self.buffer.len()
139    }
140
141    /// The number of bytes which are yet to be read, including the length
142    /// prefix of every frame.
143    #[inline]
144    pub(crate) fn remaining(&self) -> usize {
145        self.buffer.len().saturating_sub(self.read.get())
146    }
147
148    fn len_at_mut(&mut self, at: usize) -> Option<&mut [u8; 4]> {
149        let bytes = self.buffer.get_mut(at..at + mem::size_of::<u32>())?;
150        Some(unsafe { &mut *bytes.as_mut_ptr().cast() })
151    }
152
153    /// Mark an outgoing frame as done from the previous start point.
154    ///
155    /// If no start point is recorded, calling this method does nothing.
156    #[inline]
157    fn done(&mut self, start: usize) {
158        let delta = self
159            .buffer
160            .len()
161            .saturating_sub(start)
162            .saturating_sub(mem::size_of::<u32>());
163
164        let l = u32::try_from(delta).unwrap_or(u32::MAX).to_le_bytes();
165
166        let Some(len) = self.len_at_mut(start) else {
167            return;
168        };
169
170        *len = l;
171    }
172
173    /// Reset the buffer to the previous start point.
174    ///
175    /// If no start point is set, this method does nothing.
176    #[inline]
177    fn reset(&mut self, start: usize) {
178        self.buffer.truncate(start);
179    }
180
181    #[inline]
182    pub(crate) fn clear(&mut self) {
183        self.buffer.clear();
184        self.read.set(0);
185    }
186
187    /// Release any allocation beyond `capacity`.
188    ///
189    /// A single large message would otherwise pin its allocation for as long as
190    /// the buffer is pooled.
191    #[inline]
192    pub(crate) fn shrink_to(&mut self, capacity: usize) {
193        self.buffer.shrink_to(capacity);
194    }
195
196    /// Get the next frame starting at the given location.
197    #[inline]
198    pub(crate) fn read(&self) -> Result<Option<&[u8]>, InvalidFrame> {
199        let read = self.read.get();
200
201        if self.buffer.len() == read {
202            return Ok(None);
203        }
204
205        let Some(tail) = self.buffer.get(read..) else {
206            return Err(InvalidFrame {
207                what: InvalidFrameWhat::ReadPosition(read),
208                range: 0..read,
209                size: self.buffer.len(),
210            });
211        };
212
213        let Some((head, tail)) = tail.split_at_checked(mem::size_of::<u32>()) else {
214            return Err(InvalidFrame {
215                what: InvalidFrameWhat::InsufficientLength(mem::size_of::<u32>()),
216                range: 0..read,
217                size: self.buffer.len(),
218            });
219        };
220
221        let frame = read..read + mem::size_of::<u32>();
222
223        let &[a, b, c, d] = head else {
224            return Err(InvalidFrame {
225                what: InvalidFrameWhat::LengthPrefix,
226                range: frame.clone(),
227                size: self.buffer.len(),
228            });
229        };
230
231        let len = u32::from_le_bytes([a, b, c, d]);
232
233        let Ok(len) = usize::try_from(len) else {
234            return Err(InvalidFrame {
235                what: InvalidFrameWhat::LengthPrefixOverflow(len),
236                range: frame.clone(),
237                size: self.buffer.len(),
238            });
239        };
240
241        let Some(out) = tail.get(..len) else {
242            return Err(InvalidFrame {
243                what: InvalidFrameWhat::InsufficientFrame(len),
244                range: frame.start..frame.end + len,
245                size: self.buffer.len(),
246            });
247        };
248
249        let next = read
250            .saturating_add(mem::size_of::<u32>())
251            .saturating_add(len);
252
253        self.read.set(next);
254        Ok(Some(out))
255    }
256}
257
258pub(crate) struct BufPool {
259    pool: RefCell<Vec<Buf>>,
260    /// Buffers are shrunk back down to this when they are returned, so a single
261    /// large message does not pin its allocation for the lifetime of the
262    /// connection.
263    max_capacity: usize,
264}
265
266impl BufPool {
267    /// Construct a pool which shrinks returned buffers to `max_capacity`.
268    #[inline]
269    pub(crate) fn new(max_capacity: usize) -> Self {
270        Self {
271            pool: RefCell::new(Vec::new()),
272            max_capacity,
273        }
274    }
275
276    /// Try to run the given closure with a pool from the buffer.
277    ///
278    /// If the closure errors, the pool is returned.
279    #[inline]
280    pub(crate) fn with<E>(&self, f: impl FnOnce(&mut Buf) -> Result<(), E>) -> Result<Buf, E> {
281        let mut buf = self.get();
282        let result = f(&mut buf);
283
284        match result {
285            Ok(()) => Ok(buf),
286            Err(err) => {
287                self.put(buf);
288                Err(err)
289            }
290        }
291    }
292
293    #[inline]
294    pub(crate) fn get(&self) -> Buf {
295        self.pool.borrow_mut().pop().unwrap_or_default()
296    }
297
298    #[inline]
299    pub(crate) fn put(&self, mut buf: Buf) {
300        buf.clear();
301        buf.shrink_to(self.max_capacity);
302        self.pool.borrow_mut().push(buf);
303    }
304}
305
306#[cfg(test)]
307mod tests {
308    use alloc::string::{String, ToString};
309
310    use musli::Encode;
311
312    use super::{Buf, BufPool};
313    use crate::api::Format;
314
315    /// A pooled buffer which grew past the pool's capacity must give the
316    /// allocation back when it is returned, or one large message would pin it
317    /// for the lifetime of the connection.
318    #[test]
319    fn test_pool_shrinks_returned_buffers() {
320        let pool = BufPool::new(16);
321
322        let mut buf = pool.get();
323        buf.buffer.extend_from_slice(&[0; 1024]);
324        assert!(buf.buffer.capacity() >= 1024);
325
326        pool.put(buf);
327
328        let buf = pool.get();
329        assert!(buf.buffer.is_empty());
330
331        assert!(
332            buf.buffer.capacity() <= 16,
333            "Expected the allocation to be released, got {}",
334            buf.buffer.capacity()
335        );
336    }
337
338    #[test]
339    fn test_empty_buf() {
340        let buf = Buf::default();
341        assert!(buf.is_empty());
342        assert_eq!(buf.read(), Ok(None));
343    }
344
345    #[derive(Encode, musli::Decode)]
346    struct Message {
347        a: u32,
348        b: String,
349    }
350
351    #[test]
352    fn test_two_elements() {
353        let mut buf = Buf::default();
354
355        assert!(buf.is_empty());
356        assert_eq!(buf.read(), Ok(None));
357
358        // Buffer not consumed, so should leave empty.
359        buf.writer()
360            .body(
361                Format::DEFAULT,
362                &Message {
363                    a: 42,
364                    b: "hello".to_string(),
365                },
366            )
367            .unwrap();
368
369        assert!(buf.is_empty());
370        assert_eq!(buf.read(), Ok(None));
371
372        // Buffer consumed, so should be available for reading.
373        let mut writer = buf.writer();
374        writer
375            .body(
376                Format::DEFAULT,
377                &Message {
378                    a: 42,
379                    b: "hello".to_string(),
380                },
381            )
382            .unwrap();
383
384        writer.flush();
385
386        assert!(!buf.is_empty());
387        assert!(matches!(buf.read(), Ok(Some(..))));
388
389        assert!(buf.is_empty());
390        assert_eq!(buf.read(), Ok(None));
391    }
392}