Skip to main content

planck_pack_core/
encode.rs

1use crate::error::DecodeError;
2use crate::traits::Packable;
3
4#[cfg(feature = "alloc")]
5extern crate alloc;
6#[cfg(feature = "alloc")]
7use alloc::vec::Vec;
8
9/// High-level encode/decode that handles byte-level packing.
10///
11/// This trait is automatically implemented for all [`Packable`] types via a blanket impl.
12/// It converts ordinals to and from little-endian byte representations using the minimum
13/// number of bytes needed for the type's [`RADIX`](Packable::RADIX).
14///
15/// # Example
16///
17/// ```
18/// use planck_pack_core::{Packable, Pack};
19///
20/// // bool has RADIX = 2, so it encodes to 1 byte
21/// assert_eq!(bool::byte_size(), 1);
22/// assert_eq!(bool::bit_size(), 1);
23///
24/// let bytes = true.encode();
25/// assert_eq!(bool::decode(&bytes).unwrap(), true);
26/// ```
27pub trait Pack: Packable {
28    /// Number of bits needed to represent this type's full radix.
29    ///
30    /// Computed as `⌈log₂(RADIX)⌉`. Returns 0 for types with `RADIX ≤ 1`.
31    fn bit_size() -> u32 {
32        if Self::RADIX <= 1 {
33            0
34        } else {
35            128 - (Self::RADIX - 1).leading_zeros()
36        }
37    }
38
39    /// Number of bytes needed (byte-aligned).
40    ///
41    /// This is `⌈bit_size() / 8⌉`. Every value of this type encodes to exactly
42    /// this many bytes.
43    fn byte_size() -> usize {
44        (Self::bit_size() as usize + 7) / 8
45    }
46
47    /// Encode this value to bytes (little-endian).
48    ///
49    /// The returned `Vec` has exactly [`byte_size()`](Self::byte_size) bytes.
50    #[cfg(feature = "alloc")]
51    fn encode(&self) -> Vec<u8> {
52        let ord = self.to_ordinal();
53        let len = Self::byte_size();
54        if len == 0 {
55            return Vec::new();
56        }
57        ord.to_le_bytes()[..len].to_vec()
58    }
59
60    /// Encode this value into a fixed-size buffer. Returns number of bytes written.
61    ///
62    /// The buffer must be at least [`byte_size()`](Self::byte_size) bytes long.
63    /// Useful in `no_std` environments where allocation is unavailable.
64    fn encode_to_buf(&self, buf: &mut [u8]) -> usize {
65        let ord = self.to_ordinal();
66        let len = Self::byte_size();
67        let bytes = ord.to_le_bytes();
68        buf[..len].copy_from_slice(&bytes[..len]);
69        len
70    }
71
72    /// Decode from bytes (little-endian).
73    ///
74    /// Reads exactly [`byte_size()`](Self::byte_size) bytes from the front of the slice.
75    /// Returns [`DecodeError::InsufficientData`] if the slice is too short.
76    fn decode(bytes: &[u8]) -> Result<Self, DecodeError> {
77        let len = Self::byte_size();
78        if len == 0 {
79            return Self::from_ordinal(0);
80        }
81        if bytes.len() < len {
82            return Err(DecodeError::InsufficientData {
83                expected: len,
84                got: bytes.len(),
85            });
86        }
87        let mut buf = [0u8; 16];
88        buf[..len].copy_from_slice(&bytes[..len]);
89        let ord = u128::from_le_bytes(buf);
90        Self::from_ordinal(ord)
91    }
92}
93
94// Blanket implementation: every Packable gets Pack for free.
95impl<T: Packable> Pack for T {}