use crate::Message;
#[derive(Debug)]
pub enum DecodeError {
Bincode(bincode::Error),
Json(serde_json::Error),
}
impl core::fmt::Display for DecodeError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
DecodeError::Bincode(e) => write!(f, "bincode decode error: {e}"),
DecodeError::Json(e) => write!(f, "json decode error: {e}"),
}
}
}
impl std::error::Error for DecodeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
DecodeError::Bincode(e) => Some(e),
DecodeError::Json(e) => Some(e),
}
}
}
pub trait Codec {
fn encode(msg: &Message) -> Vec<u8>;
fn decode(buf: &[u8]) -> Result<Message, DecodeError>;
}
pub struct BincodeCodec;
impl Codec for BincodeCodec {
fn encode(msg: &Message) -> Vec<u8> {
bincode::serialize(msg).expect("bincode serialization should succeed")
}
fn decode(buf: &[u8]) -> Result<Message, DecodeError> {
bincode::deserialize(buf).map_err(DecodeError::Bincode)
}
}
pub struct JsonCodec;
impl Codec for JsonCodec {
fn encode(msg: &Message) -> Vec<u8> {
serde_json::to_vec(msg).expect("json serialization should succeed")
}
fn decode(buf: &[u8]) -> Result<Message, DecodeError> {
serde_json::from_slice(buf).map_err(DecodeError::Json)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bincode_roundtrip() {
let msg = Message::Ping { version: 1 };
let bytes = BincodeCodec::encode(&msg);
let decoded = BincodeCodec::decode(&bytes).unwrap();
assert!(matches!(decoded, Message::Ping { .. }));
}
#[test]
fn json_roundtrip() {
let msg = Message::Pong {
mac: "aa".into(),
version: 1,
};
let bytes = JsonCodec::encode(&msg);
let decoded = JsonCodec::decode(&bytes).unwrap();
assert!(matches!(decoded, Message::Pong { .. }));
}
}