Skip to main content

bincake_core/
serialize.rs

1//! Provides the `Serializable` trait for handling serialization to/from a consistent, opinionated binary format.
2//!
3//! The binary format specified by this crate is used to emit RVM bytecode,
4//! and exhibits the following properties to ensure cross-platform compatibility:
5//!
6//! - Byte-aligned data
7//! - Little-endian encoding for numeric types
8//! - Strings encoded in UTF-8 with a `u32` length prefix (see `StrLen`)
9//! - Arrays encoded with a length prefix of varying size (e.g., `u8`, `u16`, `u32`), followed by the serialized elements
10//!
11//! This module also provides trivial implementations of `Serializable` for `bool` and `String`.
12
13use taped::Tape;
14
15use crate::{DecodeError, EncodeError, Read, Vec32, Write};
16
17/// Writes all provided data to the destination, taking each argument as a reference.
18///
19/// This macro is useful for streaming known sequences of values to a destination.
20#[macro_export]
21macro_rules! stream {
22    ($($data:expr),* $(,)? => $dest:expr) => {
23        {
24            let mut result;
25            'cases: {
26                $(
27                    result = $dest.write(&$data);
28                    if result.is_err() {
29                        break 'cases;
30                    }
31                )*
32            }
33            result
34        }
35    };
36}
37
38/// A value that can be serialized to and deserialized from a byte buffer.
39pub trait Serialize: Sized {
40    /// Encodes this value by appending it to the buffer.
41    fn encode(&self, dest: &mut Vec<u8>) -> Result<(), EncodeError>;
42
43    /// Decodes the value by consuming the next one in the buffer.
44    ///
45    /// Returns `bincake::DeserializeError` if the encoded data is malformed.
46    fn decode(src: &mut Tape<'_, u8>) -> Result<Self, DecodeError>;
47}
48
49impl Serialize for bool {
50    fn encode(&self, dest: &mut Vec<u8>) -> Result<(), EncodeError> {
51        dest.push(if *self { 1u8 } else { 0u8 });
52        Ok(())
53    }
54
55    fn decode(src: &mut Tape<'_, u8>) -> Result<Self, DecodeError> {
56        src.next()
57            .ok_or(DecodeError::Exhausted { pos: src.pos })
58            .map(|b| b == 1)
59    }
60}
61
62impl Serialize for String {
63    fn encode(&self, dest: &mut Vec<u8>) -> Result<(), EncodeError> {
64        let len = self.len();
65        #[cfg(target_pointer_width = "64")]
66        if len > u32::MAX as usize {
67            return Err(EncodeError::LengthExceedsPrefix {
68                prefix_size: 32,
69                len,
70            });
71        }
72        dest.write(&len)?;
73        dest.extend_from_slice(self.as_bytes());
74        Ok(())
75    }
76
77    fn decode(src: &mut Tape<'_, u8>) -> Result<Self, DecodeError> {
78        let start = src.pos;
79        let data = src.read::<Vec32<u8>>()?.into_inner();
80        String::from_utf8(data).map_err(|e| DecodeError::Other {
81            pos: start,
82            cause: format!("Invalid UTF-8 ({e})"),
83        })
84    }
85}