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