1#![doc = include_str!("../README.md")]
2#![no_std]
3
4extern crate alloc;
5
6use alloc::vec::Vec;
7use core::fmt;
8
9#[cfg(test)]
10extern crate std;
11
12pub const AIRBENDER_CODEC_V0: u32 = 0;
14
15pub trait AirbenderCodec {
17 const VERSION: u32;
19
20 fn encode<T: serde::Serialize>(value: &T) -> Result<Vec<u8>, CodecError>;
22
23 fn decode<T: serde::de::DeserializeOwned>(bytes: &[u8]) -> Result<T, CodecError>;
25}
26
27pub struct AirbenderCodecV0;
29
30impl AirbenderCodec for AirbenderCodecV0 {
31 const VERSION: u32 = AIRBENDER_CODEC_V0;
32
33 fn encode<T: serde::Serialize>(value: &T) -> Result<Vec<u8>, CodecError> {
34 bincode::serde::encode_to_vec(value, bincode::config::standard())
35 .map_err(CodecError::Encode)
36 }
37
38 fn decode<T: serde::de::DeserializeOwned>(bytes: &[u8]) -> Result<T, CodecError> {
39 let (decoded, read_len) =
40 bincode::serde::decode_from_slice(bytes, bincode::config::standard())
41 .map_err(CodecError::Decode)?;
42 if read_len != bytes.len() {
43 return Err(CodecError::TrailingBytes {
44 expected: bytes.len(),
45 read: read_len,
46 });
47 }
48 Ok(decoded)
49 }
50}
51
52#[derive(Debug)]
53pub enum CodecError {
54 Encode(bincode::error::EncodeError),
55 Decode(bincode::error::DecodeError),
56 TrailingBytes { expected: usize, read: usize },
57}
58
59impl fmt::Display for CodecError {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 match self {
62 CodecError::Encode(_) => f.write_str("failed to encode value"),
63 CodecError::Decode(_) => f.write_str("failed to decode value"),
64 CodecError::TrailingBytes { expected, read } => {
65 write!(f, "decoded {read} bytes but expected {expected}")
66 }
67 }
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use alloc::vec;
75
76 #[derive(Debug, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
77 struct Sample {
78 value: u32,
79 payload: alloc::vec::Vec<u8>,
80 }
81
82 #[test]
83 fn codec_roundtrip() {
84 let sample = Sample {
85 value: 42,
86 payload: vec![1u8, 2, 3, 4, 5],
87 };
88 let encoded = AirbenderCodecV0::encode(&sample).expect("encode");
89 let decoded: Sample = AirbenderCodecV0::decode(&encoded).expect("decode");
90 assert_eq!(decoded, sample);
91 }
92}