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::{
16    error::{DecodeError, EncodeError},
17    read_write::Read,
18    sized_vec::Vec32,
19};
20
21/// Writes all provided data to the destination.
22#[macro_export]
23macro_rules! write_all {
24    ($dest:expr; $($data:expr),* $(,)?) => {
25        {
26            let mut result;
27            'cases: {
28                $(
29                    result = $dest.write($data);
30                    if result.is_err() {
31                        break 'cases;
32                    }
33                )*
34            }
35            result
36        }
37    };
38}
39
40/// A value that can be serialized to and deserialized from a byte buffer.
41pub trait Serialize: Sized {
42    /// Encodes this value by appending it to the buffer.
43    fn encode(&self, dest: &mut Vec<u8>) -> Result<(), EncodeError>;
44
45    /// Decodes the value by consuming the next one in the buffer.
46    ///
47    /// Returns `bincake::DeserializeError` if the encoded data is malformed.
48    fn decode(src: &mut Tape<'_, u8>) -> Result<Self, DecodeError>;
49}
50
51impl Serialize for bool {
52    fn encode(&self, dest: &mut Vec<u8>) -> Result<(), EncodeError> {
53        dest.push(if *self { 1u8 } else { 0u8 });
54        Ok(())
55    }
56
57    fn decode(src: &mut Tape<'_, u8>) -> Result<Self, DecodeError> {
58        src.next()
59            .ok_or(DecodeError::Exhausted { pos: src.pos })
60            .map(|b| b == 1)
61    }
62}
63
64impl Serialize for String {
65    fn encode(&self, dest: &mut Vec<u8>) -> Result<(), EncodeError> {
66        let len = self.len();
67        #[cfg(target_pointer_width = "64")]
68        if len > u32::MAX as usize {
69            return Err(EncodeError::LengthExceedsPrefix {
70                prefix_size: 32,
71                len,
72            });
73        }
74        crate::write_le_num!(u32; dest, len);
75        dest.extend_from_slice(self.as_bytes());
76        Ok(())
77    }
78
79    fn decode(src: &mut Tape<'_, u8>) -> Result<Self, DecodeError> {
80        let start = src.pos;
81        let data = src.read::<Vec32<u8>>()?.into_inner();
82        String::from_utf8(data).map_err(|e| DecodeError::Other {
83            pos: start,
84            cause: format!("Invalid UTF-8 ({e})"),
85        })
86    }
87}