asteroid_mq_model/codec/
bincode.rs

1use std::borrow::Cow;
2
3use bytes::Bytes;
4
5use crate::{
6    EdgeError, EdgePayload, Interest, MaybeBase64Bytes, MessageDurableConfig, Subject, TopicCode,
7};
8
9use super::Codec;
10#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
11pub struct Bincode;
12
13pub const BINCODE_CONFIG: bincode::config::Configuration = bincode::config::standard();
14
15impl Codec for Bincode {
16    fn decode(&self, bytes: &[u8]) -> Result<EdgePayload, super::CodecError> {
17        Ok(bincode::decode_from_slice(bytes, BINCODE_CONFIG)
18            .map_err(super::CodecError::decode_error)?
19            .0)
20    }
21    fn encode(&self, value: &EdgePayload) -> Result<Vec<u8>, super::CodecError> {
22        bincode::encode_to_vec(value, BINCODE_CONFIG).map_err(super::CodecError::encode_error)
23    }
24    fn kind(&self) -> super::CodecKind {
25        super::CodecKind::BINCODE
26    }
27}
28
29impl bincode::Encode for EdgeError {
30    fn encode<W: bincode::enc::Encoder>(
31        &self,
32        writer: &mut W,
33    ) -> Result<(), bincode::error::EncodeError> {
34        self.context.encode(writer)?;
35        self.message.encode(writer)?;
36        self.kind.encode(writer)
37    }
38}
39
40impl<'de, C> bincode::BorrowDecode<'de, C> for EdgeError {
41    fn borrow_decode<D: bincode::de::BorrowDecoder<'de>>(
42        decoder: &mut D,
43    ) -> Result<Self, bincode::error::DecodeError> {
44        Ok(Self {
45            context: Cow::Owned(String::borrow_decode(decoder)?),
46            message: <Option<String>>::borrow_decode(decoder)?.map(Cow::Owned),
47            kind: bincode::BorrowDecode::borrow_decode(decoder)?,
48        })
49    }
50}
51
52impl<C> bincode::Decode<C> for EdgeError {
53    fn decode<D: bincode::de::Decoder>(
54        decoder: &mut D,
55    ) -> Result<Self, bincode::error::DecodeError> {
56        Ok(Self {
57            context: bincode::Decode::decode(decoder)?,
58            message: bincode::Decode::decode(decoder)?,
59            kind: bincode::Decode::decode(decoder)?,
60        })
61    }
62}
63
64macro_rules! derive_bytes_wrapper {
65    ($T: ident) => {
66        impl bincode::Encode for $T {
67            fn encode<W: bincode::enc::Encoder>(
68                &self,
69                writer: &mut W,
70            ) -> Result<(), bincode::error::EncodeError> {
71                self.0.encode(writer)
72            }
73        }
74        impl<C> bincode::Decode<C> for $T {
75            fn decode<D: bincode::de::Decoder>(
76                decoder: &mut D,
77            ) -> Result<Self, bincode::error::DecodeError> {
78                Ok(Self(Bytes::from(<Vec<u8>>::decode(decoder)?)))
79            }
80        }
81        impl<'de, C> bincode::BorrowDecode<'de, C> for $T {
82            fn borrow_decode<D: bincode::de::BorrowDecoder<'de>>(
83                decoder: &mut D,
84            ) -> Result<Self, bincode::error::DecodeError> {
85                Ok(Self(Bytes::from(<Vec<u8>>::borrow_decode(decoder)?)))
86            }
87        }
88    };
89}
90derive_bytes_wrapper!(MaybeBase64Bytes);
91derive_bytes_wrapper!(TopicCode);
92derive_bytes_wrapper!(Interest);
93derive_bytes_wrapper!(Subject);
94
95impl bincode::Encode for MessageDurableConfig {
96    fn encode<E: bincode::enc::Encoder>(
97        &self,
98        encoder: &mut E,
99    ) -> Result<(), bincode::error::EncodeError> {
100        self.expire.timestamp().encode(encoder)?;
101        self.max_receiver.encode(encoder)?;
102        Ok(())
103    }
104}
105
106impl<C> bincode::Decode<C> for MessageDurableConfig {
107    fn decode<D: bincode::de::Decoder>(
108        decoder: &mut D,
109    ) -> Result<Self, bincode::error::DecodeError> {
110        Ok(Self {
111            expire: chrono::DateTime::<chrono::Utc>::from_timestamp(i64::decode(decoder)?, 0)
112                .ok_or(bincode::error::DecodeError::Other("invalid timestamp"))?,
113            max_receiver: Option::<u32>::decode(decoder)?,
114        })
115    }
116}
117
118impl<'de, C> bincode::BorrowDecode<'de, C> for MessageDurableConfig {
119    fn borrow_decode<D: bincode::de::BorrowDecoder<'de>>(
120        decoder: &mut D,
121    ) -> Result<Self, bincode::error::DecodeError> {
122        Ok(Self {
123            expire: chrono::DateTime::<chrono::Utc>::from_timestamp(
124                i64::borrow_decode(decoder)?,
125                0,
126            )
127            .ok_or(bincode::error::DecodeError::Other("invalid timestamp"))?,
128            max_receiver: Option::<u32>::borrow_decode(decoder)?,
129        })
130    }
131}
132
133#[cfg(test)]
134mod tests {
135    use bytes::Bytes;
136
137    use super::*;
138    use crate::{EdgePayload, Interest, TopicCode};
139
140    #[test]
141    fn test_bincode() {
142        let codec = Bincode;
143        let ep_online = EdgePayload::Request(crate::EdgeRequest {
144            seq_id: 1,
145            request: crate::EdgeRequestEnum::EndpointOnline(crate::EdgeEndpointOnline {
146                topic_code: TopicCode::const_new("test topic"),
147                interests: vec![Interest::new("test/interest")],
148            }),
149        });
150
151        let encoded = codec.encode(&ep_online).expect("encode failed");
152        println!("{:?}", Bytes::copy_from_slice(&encoded));
153
154        let decoded = codec.decode(&encoded).unwrap();
155        println!("{:?}", decoded);
156
157        let re_encoded = codec.encode(&decoded).expect("encode failed");
158        assert_eq!(encoded, re_encoded);
159    }
160}