Skip to main content

volli_core/
codec.rs

1use crate::Message;
2
3/// Error returned when decoding a [`Message`] fails.
4#[derive(Debug)]
5pub enum DecodeError {
6    Bincode(bincode::Error),
7    Json(serde_json::Error),
8}
9
10impl core::fmt::Display for DecodeError {
11    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
12        match self {
13            DecodeError::Bincode(e) => write!(f, "bincode decode error: {e}"),
14            DecodeError::Json(e) => write!(f, "json decode error: {e}"),
15        }
16    }
17}
18
19impl std::error::Error for DecodeError {
20    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
21        match self {
22            DecodeError::Bincode(e) => Some(e),
23            DecodeError::Json(e) => Some(e),
24        }
25    }
26}
27
28/// Codec trait for serialising and deserialising [`Message`]s.
29pub trait Codec {
30    /// Encode a high-level [`Message`] into a byte-vector.
31    fn encode(msg: &Message) -> Vec<u8>;
32
33    /// Decode a byte-slice into a [`Message`].
34    ///
35    /// # Errors
36    /// Returns [`DecodeError`] if the bytes are invalid for this codec.
37    fn decode(buf: &[u8]) -> Result<Message, DecodeError>;
38}
39
40/// Binary [`Codec`] based on `bincode`.
41pub struct BincodeCodec;
42
43impl Codec for BincodeCodec {
44    fn encode(msg: &Message) -> Vec<u8> {
45        bincode::serialize(msg).expect("bincode serialization should succeed")
46    }
47
48    fn decode(buf: &[u8]) -> Result<Message, DecodeError> {
49        bincode::deserialize(buf).map_err(DecodeError::Bincode)
50    }
51}
52
53/// JSON [`Codec`] useful for debugging and testing.
54pub struct JsonCodec;
55
56impl Codec for JsonCodec {
57    fn encode(msg: &Message) -> Vec<u8> {
58        serde_json::to_vec(msg).expect("json serialization should succeed")
59    }
60
61    fn decode(buf: &[u8]) -> Result<Message, DecodeError> {
62        serde_json::from_slice(buf).map_err(DecodeError::Json)
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69
70    #[test]
71    fn bincode_roundtrip() {
72        let msg = Message::Ping { version: 1 };
73        let bytes = BincodeCodec::encode(&msg);
74        let decoded = BincodeCodec::decode(&bytes).unwrap();
75        assert!(matches!(decoded, Message::Ping { .. }));
76    }
77
78    #[test]
79    fn json_roundtrip() {
80        let msg = Message::Pong {
81            mac: "aa".into(),
82            version: 1,
83        };
84        let bytes = JsonCodec::encode(&msg);
85        let decoded = JsonCodec::decode(&bytes).unwrap();
86        assert!(matches!(decoded, Message::Pong { .. }));
87    }
88}