bufferfish_core/
lib.rs

1pub mod decodable;
2pub mod encodable;
3
4use std::{
5    convert::TryFrom,
6    io::{Cursor, Read, Seek, Write},
7    sync::Arc,
8};
9
10pub use decodable::Decodable;
11pub use encodable::Encodable;
12
13/// Errors that can occur when encoding or decoding a `Bufferfish`.
14#[derive(Debug)]
15pub enum BufferfishError {
16    /// std::io::Error that occurred during a write operation.
17    FailedWrite(std::io::Error),
18    /// Invalid - typically non-u16 - packet ID encountered during a write.
19    InvalidPacketId,
20    /// Invalid enum variant encountered during encoding/decoding.
21    InvalidEnumVariant,
22}
23
24impl std::fmt::Display for BufferfishError {
25    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
26        match self {
27            BufferfishError::FailedWrite(e) => write!(f, "failed to write to buffer: {}", e),
28            BufferfishError::InvalidPacketId => write!(f, "invalid packet id"),
29            BufferfishError::InvalidEnumVariant => write!(f, "invalid enum variant"),
30        }
31    }
32}
33
34impl From<std::io::Error> for BufferfishError {
35    fn from(e: std::io::Error) -> Self {
36        BufferfishError::FailedWrite(e)
37    }
38}
39
40impl std::error::Error for BufferfishError {
41    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
42        match self {
43            BufferfishError::FailedWrite(e) => Some(e),
44            BufferfishError::InvalidPacketId => None,
45            BufferfishError::InvalidEnumVariant => None,
46        }
47    }
48}
49
50/// A wrapper around a `Cursor<Vec<u8>>` that provides a simple API for reading
51/// and writing bytes. This is meant to be used with its companion library in
52/// TypeScript to provide consistent encoding and decoding interop.
53#[derive(Debug, Default)]
54pub struct Bufferfish {
55    inner: Cursor<Vec<u8>>,
56    reading: bool,
57    capacity: usize,
58}
59
60impl Write for Bufferfish {
61    fn write(&mut self, bf: &[u8]) -> std::io::Result<usize> {
62        if self.capacity > 0
63            && (bf.len() >= self.capacity || self.as_ref().len() + bf.len() > self.capacity)
64        {
65            return Err(std::io::Error::new(
66                std::io::ErrorKind::Other,
67                format!(
68                    "write of {} bytes exceeds the max capacity of {} bytes on this Bufferfish",
69                    bf.len(),
70                    self.capacity
71                ),
72            ));
73        }
74
75        self.reading = false;
76        self.inner.write(bf)
77    }
78
79    fn flush(&mut self) -> std::io::Result<()> {
80        self.inner.flush()
81    }
82}
83
84impl Seek for Bufferfish {
85    fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
86        self.inner.seek(pos)
87    }
88}
89
90impl Bufferfish {
91    /// Creates a new `Bufferfish` with a default max capacity (1024 bytes).
92    pub fn new() -> Self {
93        Self {
94            inner: Cursor::new(Vec::new()),
95            reading: false,
96            capacity: 1024,
97        }
98    }
99
100    /// Creates a new `Bufferfish` with a max capacity (in bytes).
101    /// A value of 0 will allow the buffer to grow indefinitely.
102    pub fn with_capacity(capacity: usize) -> Self {
103        Self {
104            inner: Cursor::new(Vec::with_capacity(capacity)),
105            reading: false,
106            capacity,
107        }
108    }
109
110    /// Returns the current length (bytes) of the buffer.
111    pub fn len(&self) -> usize {
112        self.inner.get_ref().len()
113    }
114
115    /// Returns true if the buffer is empty.
116    pub fn is_empty(&self) -> bool {
117        self.inner.get_ref().is_empty()
118    }
119
120    /// #[doc(hidden)]
121    /// Resets the buffer cursor to the start position when reading after a
122    /// write.
123    fn start_reading(&mut self) {
124        if self.reading {
125            return;
126        }
127
128        self.inner.set_position(0);
129        self.reading = true;
130    }
131
132    /// Returns a `Vec<u8>` of the internal byte buffer.
133    pub fn to_vec(&self) -> Vec<u8> {
134        self.inner.get_ref().to_vec()
135    }
136
137    /// Returns an `Arc<[u8]>` of the internal byte buffer for cheaply cloning
138    /// and sharing the buffer.
139    pub fn as_bytes(&self) -> Arc<[u8]> {
140        self.inner.get_ref().clone().into()
141    }
142
143    /// Set the max capacity (in bytes) for the internal buffer.
144    /// A value of 0 will allow the buffer to grow indefinitely.
145    pub fn set_max_capacity(&mut self, capacity: usize) {
146        self.capacity = capacity;
147    }
148
149    /// Adds a `Bufferfish` or `Vec<u8>` to the end of the buffer.
150    /// See `try_extends` for a version that returns a `Result`.
151    ///
152    /// # Panics
153    /// Panics if the buffer is at max capacity.
154    pub fn extend<T: Into<Bufferfish>>(&mut self, other: T) {
155        self.try_extend(other).unwrap();
156    }
157
158    /// Adds a `Bufferfish` or `Vec<u8>` to the end of the buffer.
159    /// Returns a `Result` if the buffer is at max capacity.
160    pub fn try_extend<T: Into<Bufferfish>>(&mut self, other: T) -> Result<(), BufferfishError> {
161        let other = other.into();
162        self.write_all(other.as_ref())?;
163
164        Ok(())
165    }
166
167    /// Returns the next byte in the buffer without advancing the cursor.
168    /// Returns a `Result` if the cursor is at the end of the buffer.
169    pub fn peek(&mut self) -> Result<u8, BufferfishError> {
170        self.start_reading();
171        let pos = self.inner.position();
172
173        let Some(byte) = self.inner.get_ref().get(pos as usize) else {
174            return Err(std::io::Error::new(
175                std::io::ErrorKind::Other,
176                format!(
177                    "peek of 1 byte exceeds the max capacity of {} bytes on this Bufferfish",
178                    self.capacity
179                ),
180            ))?;
181        };
182
183        let byte = *byte;
184
185        self.inner.set_position(pos);
186
187        Ok(byte)
188    }
189
190    /// Returns the next n-bytes in the buffer without advancing the cursor.
191    /// Returns a Result if the cursor is at the end of the buffer.
192    pub fn peek_n(&mut self, n: usize) -> Result<Vec<u8>, BufferfishError> {
193        self.start_reading();
194        let pos = self.inner.position();
195
196        let Some(bytes) = self.inner.get_ref().get(pos as usize..pos as usize + n) else {
197            return Err(std::io::Error::new(
198                std::io::ErrorKind::Other,
199                format!(
200                    "peek of {} bytes exceeds the max capacity of {} bytes on this Bufferfish",
201                    n, self.capacity
202                ),
203            ))?;
204        };
205
206        let bytes = bytes.to_vec();
207
208        self.inner.set_position(pos);
209
210        Ok(bytes)
211    }
212
213    /// Writes a u8 to the buffer as one byte.
214    pub fn write_u8(&mut self, value: u8) -> Result<(), BufferfishError> {
215        self.write_all(&[value])?;
216
217        Ok(())
218    }
219
220    /// Writes a u16 to the buffer as two bytes.
221    pub fn write_u16(&mut self, value: u16) -> Result<(), BufferfishError> {
222        self.write_all(&value.to_be_bytes())?;
223
224        Ok(())
225    }
226
227    /// Writes a u32 to the buffer as four bytes.
228    pub fn write_u32(&mut self, value: u32) -> Result<(), BufferfishError> {
229        self.write_all(&value.to_be_bytes())?;
230
231        Ok(())
232    }
233
234    /// Writes an i8 to the buffer as one byte.
235    pub fn write_i8(&mut self, value: i8) -> Result<(), BufferfishError> {
236        self.write_all(&[value as u8])?;
237
238        Ok(())
239    }
240
241    /// Writes an i16 to the buffer as two bytes.
242    pub fn write_i16(&mut self, value: i16) -> Result<(), BufferfishError> {
243        self.write_all(&value.to_be_bytes())?;
244
245        Ok(())
246    }
247
248    /// Writes an i32 to the buffer as four bytes.
249    pub fn write_i32(&mut self, value: i32) -> Result<(), BufferfishError> {
250        self.write_all(&value.to_be_bytes())?;
251
252        Ok(())
253    }
254
255    /// Writes a bool to the buffer as one byte.
256    pub fn write_bool(&mut self, value: bool) -> Result<(), BufferfishError> {
257        self.write_u8(if value { 1 } else { 0 })?;
258
259        Ok(())
260    }
261
262    /// Writes a packed array of booleans to the buffer as a single byte.
263    /// Can pack up to 8 booleans into a single byte.
264    pub fn write_packed_bools(&mut self, values: &[bool]) -> Result<(), BufferfishError> {
265        if values.len() > 8 {
266            return Err(std::io::Error::new(
267                std::io::ErrorKind::InvalidInput,
268                "Cannot pack more than 8 booleans into a single byte.",
269            ))?;
270        }
271
272        let mut packed = 0u8;
273
274        for (i, value) in values.iter().enumerate() {
275            if *value {
276                packed |= 1 << (7 - i); // Pack from most significant bit to least significant bit
277            }
278        }
279
280        self.write_u8(packed)?;
281
282        Ok(())
283    }
284
285    /// Writes a variable length string to the buffer. It will be prefixed with
286    /// its length in bytes as a u16 (two bytes).
287    pub fn write_string(&mut self, value: &str) -> Result<(), BufferfishError> {
288        let len = u16::try_from(value.len()).map_err(|_| {
289            std::io::Error::new(
290                std::io::ErrorKind::InvalidInput,
291                "String length exceeds u16 max value",
292            )
293        })?;
294
295        self.write_u16(len)?;
296        self.write_all(value.as_bytes())?;
297
298        Ok(())
299    }
300
301    /// Writes an array to the buffer, where the items implement the Encodable
302    /// trait. The array will be prefixed with its length as a u16 (two bytes).
303    pub fn write_array<T: Encodable>(&mut self, vec: &[T]) -> Result<(), BufferfishError> {
304        self.write_u16(vec.len() as u16)?;
305
306        for item in vec {
307            item.encode(self)?;
308        }
309
310        Ok(())
311    }
312
313    /// Writes an array of raw bytes to the buffer. Useful for encoding
314    /// distinct structs into byte arrays and appending them to a buffer later.
315    pub fn write_raw_bytes(&mut self, bytes: &[u8]) -> Result<(), BufferfishError> {
316        self.write_all(bytes)?;
317        Ok(())
318    }
319
320    /// Reads a u8 from the buffer.
321    pub fn read_u8(&mut self) -> Result<u8, BufferfishError> {
322        self.start_reading();
323
324        let mut bf = [0u8; 1];
325        self.inner.read_exact(&mut bf)?;
326
327        Ok(bf[0])
328    }
329
330    /// Reads a u16 from the buffer.
331    pub fn read_u16(&mut self) -> Result<u16, BufferfishError> {
332        self.start_reading();
333
334        let mut bf = [0u8; 2];
335        self.inner.read_exact(&mut bf)?;
336
337        Ok(u16::from_be_bytes(bf))
338    }
339
340    /// Reads a u32 from the buffer.
341    pub fn read_u32(&mut self) -> Result<u32, BufferfishError> {
342        self.start_reading();
343
344        let mut bf = [0u8; 4];
345        self.inner.read_exact(&mut bf)?;
346
347        Ok(u32::from_be_bytes(bf))
348    }
349
350    /// Reads an i8 from the buffer.
351    pub fn read_i8(&mut self) -> Result<i8, BufferfishError> {
352        self.start_reading();
353
354        let mut bf = [0u8; 1];
355        self.inner.read_exact(&mut bf)?;
356
357        Ok(i8::from_be_bytes(bf))
358    }
359
360    /// Reads an i16 from the buffer.
361    pub fn read_i16(&mut self) -> Result<i16, BufferfishError> {
362        self.start_reading();
363
364        let mut bf = [0u8; 2];
365        self.inner.read_exact(&mut bf)?;
366
367        Ok(i16::from_be_bytes(bf))
368    }
369
370    /// Reads an i32 from the buffer.
371    pub fn read_i32(&mut self) -> Result<i32, BufferfishError> {
372        self.start_reading();
373
374        let mut bf = [0u8; 4];
375        self.inner.read_exact(&mut bf)?;
376
377        Ok(i32::from_be_bytes(bf))
378    }
379
380    /// Reads a bool from the buffer.
381    pub fn read_bool(&mut self) -> Result<bool, BufferfishError> {
382        let value = self.read_u8()?;
383
384        Ok(value != 0)
385    }
386
387    /// Attempts to read a packed array of booleans from the buffer.
388    /// You must specify the number of booleans to read.
389    pub fn read_packed_bools(&mut self, count: u8) -> Result<Vec<bool>, BufferfishError> {
390        if count > 8 {
391            return Err(std::io::Error::new(
392                std::io::ErrorKind::InvalidInput,
393                "Cannot pack more than 8 booleans into a single byte.",
394            ))?;
395        }
396
397        let packed = self.read_u8()?;
398        let mut bools = Vec::with_capacity(count as usize);
399
400        for i in 0..count {
401            bools.push(packed & (1 << (7 - i)) != 0);
402        }
403
404        Ok(bools)
405    }
406
407    /// Reads a variable length string from the buffer.
408    pub fn read_string(&mut self) -> Result<String, BufferfishError> {
409        self.start_reading();
410
411        let len = self.read_u16()? as usize;
412        let pos = self.inner.position() as usize;
413        self.inner.set_position((pos + len) as u64);
414
415        let Some(slice) = &mut self.inner.get_mut().get(pos..pos + len) else {
416            return Err(std::io::Error::new(
417                std::io::ErrorKind::UnexpectedEof,
418                "Unexpected EOF",
419            ))?;
420        };
421
422        let string = String::from_utf8(slice.to_vec());
423
424        match string {
425            Ok(s) => Ok(s),
426            Err(e) => Err(std::io::Error::new(
427                std::io::ErrorKind::InvalidData,
428                e.to_string(),
429            ))?,
430        }
431    }
432
433    /// Reads an array from the buffer, where the items implement the Decodable
434    /// trait.
435    pub fn read_array<T: Decodable>(&mut self) -> Result<Vec<T>, BufferfishError> {
436        self.start_reading();
437
438        let len = self.read_u16()? as usize;
439        let mut vec = Vec::with_capacity(len);
440
441        for _ in 0..len {
442            vec.push(T::decode(self)?);
443        }
444
445        Ok(vec)
446    }
447}
448
449impl std::fmt::Display for Bufferfish {
450    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
451        let inner = self.inner.get_ref();
452        write!(f, " Byte: ")?;
453
454        for val in inner {
455            write!(f, " {} ", val)?;
456        }
457
458        write!(f, "\nIndex: ")?;
459        #[allow(unused_variables)]
460        for (i, c) in inner.iter().enumerate() {
461            #[cfg(feature = "pretty-print")]
462            let width = unicode_width::UnicodeWidthStr::width(c.to_string().as_str());
463
464            #[cfg(not(feature = "pretty-print"))]
465            let width = 1;
466
467            write!(f, " {:width$} ", i, width = width)?;
468        }
469
470        Ok(())
471    }
472}
473
474impl AsRef<[u8]> for Bufferfish {
475    fn as_ref(&self) -> &[u8] {
476        self.inner.get_ref()
477    }
478}
479
480impl AsMut<[u8]> for Bufferfish {
481    fn as_mut(&mut self) -> &mut [u8] {
482        self.inner.get_mut()
483    }
484}
485
486impl PartialEq for Bufferfish {
487    fn eq(&self, other: &Self) -> bool {
488        self.inner.get_ref() == other.inner.get_ref()
489    }
490}
491
492impl From<&[u8]> for Bufferfish {
493    fn from(slice: &[u8]) -> Self {
494        Self {
495            inner: Cursor::new(slice.to_vec()),
496            reading: false,
497            capacity: slice.len(),
498        }
499    }
500}
501
502impl From<Vec<u8>> for Bufferfish {
503    fn from(vec: Vec<u8>) -> Self {
504        let capacity = vec.len();
505        Self {
506            inner: Cursor::new(vec),
507            reading: false,
508            capacity,
509        }
510    }
511}
512
513impl From<Bufferfish> for Vec<u8> {
514    fn from(buffer: Bufferfish) -> Self {
515        buffer.inner.into_inner()
516    }
517}
518
519impl From<bytes::Bytes> for Bufferfish {
520    fn from(bytes: bytes::Bytes) -> Self {
521        Self {
522            inner: Cursor::new(bytes.to_vec()),
523            reading: false,
524            capacity: bytes.len(),
525        }
526    }
527}
528
529impl From<Bufferfish> for bytes::Bytes {
530    fn from(buffer: Bufferfish) -> Self {
531        buffer.inner.into_inner().into()
532    }
533}