commonware_codec/
codec.rs

1//! Core codec traits and implementations
2
3use crate::error::Error;
4use bytes::{Buf, BufMut, BytesMut};
5
6/// Trait for types that can be encoded to and decoded from bytes
7pub trait Codec: Sized {
8    /// Encodes this value to a writer.
9    fn write(&self, buf: &mut impl BufMut);
10
11    /// Returns the encoded length of this value.
12    fn len_encoded(&self) -> usize;
13
14    /// Encodes a value to bytes.
15    fn encode(&self) -> BytesMut {
16        let len = self.len_encoded();
17        let mut buffer = BytesMut::with_capacity(len);
18        self.write(&mut buffer);
19        assert_eq!(buffer.len(), len);
20        buffer
21    }
22
23    /// Reads a value from a buffer, returning an error if there is an error while reading.
24    fn read(buf: &mut impl Buf) -> Result<Self, Error>;
25
26    /// Decodes a value from a buffer.
27    ///
28    /// Returns an error if there is an error while decoding or if there is extra data remaining
29    /// after decoding the value from the buffer.
30    fn decode<B: Buf>(mut buf: B) -> Result<Self, Error> {
31        let result = Self::read(&mut buf);
32        let remaining = buf.remaining();
33        if remaining > 0 {
34            return Err(Error::ExtraData(remaining));
35        }
36        result
37    }
38}
39
40/// Trait for types that have a fixed-length encoding
41pub trait SizedCodec: Codec {
42    /// The encoded length of this value.
43    const LEN_ENCODED: usize;
44
45    /// Returns the encoded length of this value.
46    ///
47    /// Should not be overridden by implementations.
48    fn len_encoded(&self) -> usize {
49        Self::LEN_ENCODED
50    }
51
52    /// Encodes a value to fixed-size bytes.
53    fn encode_fixed<const N: usize>(&self) -> [u8; N] {
54        // Ideally this is a compile-time check, but we can't do that in the current Rust version
55        // without adding a new generic parameter to the trait.
56        assert_eq!(
57            N,
58            Self::LEN_ENCODED,
59            "Can't encode {} bytes into {} bytes",
60            Self::LEN_ENCODED,
61            N
62        );
63
64        let mut array = [0u8; N];
65        let mut buf = &mut array[..];
66        self.write(&mut buf);
67        assert_eq!(buf.len(), 0);
68        array
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75    use crate::{Codec, Error};
76    use bytes::Bytes;
77
78    #[test]
79    fn test_insufficient_buffer() {
80        let mut reader = Bytes::from_static(&[0x01, 0x02]);
81        assert!(matches!(u32::read(&mut reader), Err(Error::EndOfBuffer)));
82    }
83
84    #[test]
85    fn test_extra_data() {
86        let encoded = Bytes::from_static(&[0x01, 0x02]);
87        assert!(matches!(u8::decode(encoded), Err(Error::ExtraData(1))));
88    }
89
90    #[test]
91    fn test_encode_fixed() {
92        let value = 42u32;
93        let encoded: [u8; 4] = value.encode_fixed();
94        let decoded = u32::decode(Bytes::copy_from_slice(&encoded)).unwrap();
95        assert_eq!(value, decoded);
96    }
97
98    #[test]
99    #[should_panic(expected = "Can't encode 4 bytes into 5 bytes")]
100    fn test_encode_fixed_panic() {
101        let _: [u8; 5] = 42u32.encode_fixed();
102    }
103}