Skip to main content

hoy_protocol/
frame_buffer.rs

1//! Wire frame buffer module.
2
3use serde::de::DeserializeOwned;
4
5use crate::codec::try_decode_frame;
6use crate::error::ProtocolError;
7
8/// Incremental buffer for decoding length-prefixed protocol frames.
9#[derive(Debug, Clone, Default, PartialEq, Eq)]
10pub struct FrameBuffer {
11    /// Raw buffered bytes received from wire.
12    bytes: Vec<u8>,
13}
14
15impl FrameBuffer {
16    /// Default frame buffer constructor.
17    #[must_use]
18    pub const fn new() -> Self {
19        Self { bytes: Vec::new() }
20    }
21
22    /// Construct an empty frame buffer with a preallocated capacity.
23    #[must_use]
24    pub fn with_capacity(capacity: usize) -> Self {
25        Self {
26            bytes: Vec::with_capacity(capacity),
27        }
28    }
29
30    /**
31     * Append a new chunk of transported bytes to buffer.
32     *
33     * # Arguments
34     * - `chunk`: array of bytes to append.
35     *
36     * # Returns
37     * `Ok(())` on succesfull byte insertion.
38     *
39     * # Errors
40     * Returns `ProtocolError` if buffer would overflow.
41     */
42    pub fn append(&mut self, chunk: &[u8]) -> Result<(), ProtocolError> {
43        let _new_len: usize = self
44            .bytes
45            .len()
46            .checked_add(chunk.len())
47            .ok_or(ProtocolError::CapacityOverflow)?;
48
49        self.bytes.extend_from_slice(chunk);
50        Ok(())
51    }
52
53    /**
54     * Attempt to decode a single frame from the buffer.
55     *
56     * If a complete frame is available, it is decoded and then removed
57     * from the internal buffer.
58     *
59     * If the buffer does not yet contain a full frame, no data is discarded from the buffer.
60     *
61     * # Returns
62     * - `Ok(None)` - if no complete frame available in the buffer,
63     * - decoded frame value - if a full frame is present in the buffer and succesfully decoded.
64     *
65     * # Errors
66     * Returns `ProtocolError` if:
67     * - buffer data contains a malformed complete frame,
68     * - frame length is out of range,
69     * - deserialization fails.
70     */
71    pub fn try_decode<T>(&mut self) -> Result<Option<T>, ProtocolError>
72    where
73        T: DeserializeOwned,
74    {
75        let Some((value, consumed)) = try_decode_frame::<T>(&self.bytes)? else {
76            return Ok(None);
77        };
78
79        self.discard_prefix(consumed)?;
80        Ok(Some(value))
81    }
82
83    /// Returns the number of currently buffered bytes.
84    #[must_use]
85    pub fn len(&self) -> usize {
86        self.bytes.len()
87    }
88
89    /// Returns `true` if buffer empty, `false` otherwise.
90    #[must_use]
91    pub fn is_empty(&self) -> bool {
92        self.bytes.is_empty()
93    }
94
95    /// Clears buffer - removes all buffered bytes.
96    pub fn clear(&mut self) {
97        self.bytes.clear();
98    }
99
100    /// Returns a read-only view of buffered bytes.
101    #[must_use]
102    pub fn as_slice(&self) -> &[u8] {
103        &self.bytes
104    }
105
106    /**
107     * Discard a prefix of already-consumed bytes.
108     *
109     * # Arguments
110     * - `count`: number of bytes to discard.
111     *
112     * # Returns
113     * `Ok(())` on success.
114     *
115     * # Errors
116     * Returns `ProtocolError` if `count` exceeds the current buffered length.
117     */
118    fn discard_prefix(&mut self, count: usize) -> Result<(), ProtocolError> {
119        if count > self.len() {
120            return Err(ProtocolError::InvalidDiscard {
121                count,
122                buffer_len: self.len(),
123            });
124        }
125
126        if count == 0 {
127            return Ok(());
128        }
129
130        if count == self.len() {
131            self.bytes.clear();
132            return Ok(());
133        }
134
135        self.bytes.copy_within(count.., 0);
136
137        let new_len: usize = self
138            .bytes
139            .len()
140            .checked_sub(count)
141            .ok_or(ProtocolError::CapacityOverflow)?;
142
143        self.bytes.truncate(new_len);
144        Ok(())
145    }
146}
147
148#[cfg(test)]
149#[allow(dead_code, unused)]
150mod tests {
151    use hoy_test::assert_err;
152    use serde::de::DeserializeOwned;
153
154    use crate::codec::encode_frame;
155    use crate::error::ProtocolError;
156    use crate::frame_buffer::FrameBuffer;
157    use crate::packet::ClientPacket;
158
159    fn encode_ok(value: &impl serde::Serialize) -> Vec<u8> {
160        encode_frame(value).expect("Frame encoding failed unexpectedly.")
161    }
162
163    fn append_ok(buffer: &mut FrameBuffer, chunk: &[u8]) {
164        let len_og = buffer.len();
165        buffer.append(chunk).expect("Append failed unexpectedly.");
166        assert!(!buffer.is_empty());
167        assert_eq!(
168            buffer.len(),
169            chunk
170                .len()
171                .checked_add(len_og)
172                .expect("Unexpected buffer length overflow.")
173        );
174    }
175
176    fn try_decode_ok<T>(buffer: &mut FrameBuffer) -> T
177    where
178        T: DeserializeOwned,
179    {
180        buffer
181            .try_decode::<T>()
182            .expect("Decoding failed unexpectedly.")
183            .expect("Decoded frame should not be None.")
184    }
185
186    fn try_decode_none<T>(buffer: &mut FrameBuffer) -> Option<T>
187    where
188        T: DeserializeOwned + std::fmt::Debug + PartialEq,
189    {
190        let result = buffer
191            .try_decode::<T>()
192            .expect("Decoding failed unexpectedly.");
193        assert_eq!(result, None);
194        result
195    }
196
197    fn try_decode_err<T>(buffer: &mut FrameBuffer, error: &str) -> ProtocolError
198    where
199        T: DeserializeOwned + std::fmt::Debug,
200    {
201        buffer
202            .try_decode::<T>()
203            .expect_err(&format!("Decoding should return error: {error}"))
204    }
205
206    #[test]
207    fn new_buffer_is_empty() {
208        let buffer = FrameBuffer::new();
209
210        assert!(buffer.is_empty());
211        assert_eq!(buffer.len(), 0);
212    }
213
214    #[test]
215    fn append_adds_bytes_to_buffer() {
216        let mut buffer = FrameBuffer::new();
217
218        append_ok(&mut buffer, b"abcd");
219
220        assert_eq!(buffer.len(), 4);
221        assert_eq!(buffer.as_slice(), b"abcd");
222    }
223
224    #[test]
225    fn try_decode_returns_none_for_incomplete_frame() {
226        let mut buffer = FrameBuffer::new();
227
228        buffer
229            .append(&[0, 0, 0])
230            .expect("Append failed unexpectedly.");
231
232        let decoded = buffer
233            .try_decode::<ClientPacket>()
234            .expect("Decoding failed unexpectedly");
235        assert_eq!(decoded, None);
236        assert_eq!(buffer.as_slice(), &[0, 0, 0]);
237    }
238
239    #[test]
240    fn try_decode_returns_complete_frame_and_consumes_it() {
241        let mut buffer = FrameBuffer::new();
242        let packet = ClientPacket::Ping;
243        let frame = encode_ok(&packet);
244
245        append_ok(&mut buffer, &frame);
246
247        let decoded = try_decode_ok::<ClientPacket>(&mut buffer);
248        assert_eq!(decoded, packet);
249        assert!(buffer.is_empty());
250    }
251
252    #[test]
253    fn try_decode_keeps_trailing_bytes_for_next_frame() {
254        let mut buffer = FrameBuffer::new();
255
256        let packet1 = ClientPacket::Ping;
257        let packet2 = ClientPacket::Hello {
258            username: String::from("bruce_lee"),
259        };
260
261        let frame1 = encode_ok(&packet1);
262        let frame2 = encode_ok(&packet2);
263
264        append_ok(&mut buffer, &frame1);
265        append_ok(&mut buffer, &frame2);
266
267        let decoded1 = try_decode_ok::<ClientPacket>(&mut buffer);
268        assert_eq!(decoded1, packet1);
269        assert!(!buffer.is_empty());
270        assert_eq!(buffer.len(), frame2.len());
271
272        let decoded2 = try_decode_ok::<ClientPacket>(&mut buffer);
273        assert_eq!(decoded2, packet2);
274        assert!(buffer.is_empty());
275    }
276
277    #[test]
278    fn try_decode_returns_error_for_malformed_complete_frame() {
279        let mut buffer = FrameBuffer::new();
280
281        append_ok(&mut buffer, &[0, 0, 0, 4, b'b', b'a', b'd', b'!']);
282
283        let error = try_decode_err::<ClientPacket>(&mut buffer, "Serde error");
284        assert_err!(error, ProtocolError::Serde(_));
285    }
286
287    #[test]
288    fn clear_removes_all_buffered_data() {
289        let mut buffer = FrameBuffer::with_capacity(16);
290
291        append_ok(&mut buffer, b"1234567890123456");
292
293        buffer.clear();
294
295        assert!(buffer.is_empty());
296        assert_eq!(buffer.len(), 0);
297    }
298}