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 {}