use serde::{de::DeserializeOwned, Serialize};
use crate::Envelope;
#[derive(Debug, thiserror::Error)]
pub enum CodecError {
#[error("postcard encode failed: {0}")]
PostcardEncode(postcard::Error),
#[error("postcard decode failed: {0}")]
PostcardDecode(postcard::Error),
#[error("bincode encode failed: {0}")]
BincodeEncode(bincode::Error),
#[error("bincode decode failed: {0}")]
BincodeDecode(bincode::Error),
}
pub trait Codec {
fn encode<T: Serialize>(&self, value: &T) -> Result<Vec<u8>, CodecError>;
fn decode<T: DeserializeOwned>(&self, bytes: &[u8]) -> Result<T, CodecError>;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct PostcardCodec;
impl Codec for PostcardCodec {
fn encode<T: Serialize>(&self, value: &T) -> Result<Vec<u8>, CodecError> {
postcard::to_allocvec(value).map_err(CodecError::PostcardEncode)
}
fn decode<T: DeserializeOwned>(&self, bytes: &[u8]) -> Result<T, CodecError> {
postcard::from_bytes(bytes).map_err(CodecError::PostcardDecode)
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct BincodeCodec;
impl Codec for BincodeCodec {
fn encode<T: Serialize>(&self, value: &T) -> Result<Vec<u8>, CodecError> {
bincode::serialize(value).map_err(CodecError::BincodeEncode)
}
fn decode<T: DeserializeOwned>(&self, bytes: &[u8]) -> Result<T, CodecError> {
bincode::deserialize(bytes).map_err(CodecError::BincodeDecode)
}
}
pub fn encode_envelope<T: Serialize>(codec: &impl Codec, payload: T) -> Result<Vec<u8>, CodecError> {
codec.encode(&Envelope::new(payload))
}
pub fn decode_envelope<T: DeserializeOwned>(
codec: &impl Codec,
bytes: &[u8],
) -> Result<Envelope<T>, CodecError> {
codec.decode(bytes)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::{EntityState, TickDelta, Transform, WorldCoord};
fn sample_tick_delta() -> TickDelta {
TickDelta {
tick: 42,
entities: (0..15)
.map(|i| EntityState {
id: i + 1,
transform: Transform {
position: WorldCoord::surface(i as f32, i as f32 * 0.5),
yaw: 1.25,
velocity: crate::types::Velocity2D { vx: 0.5, vy: -0.2 },
},
})
.collect(),
}
}
#[test]
fn postcard_roundtrip_tick_delta() {
let codec = PostcardCodec;
let original = Envelope::new(sample_tick_delta());
let bytes = codec.encode(&original).expect("encode");
let decoded: Envelope<TickDelta> = codec.decode(&bytes).expect("decode");
assert_eq!(original, decoded);
}
#[test]
fn bincode_roundtrip_tick_delta() {
let codec = BincodeCodec;
let original = Envelope::new(sample_tick_delta());
let bytes = codec.encode(&original).expect("encode");
let decoded: Envelope<TickDelta> = codec.decode(&bytes).expect("decode");
assert_eq!(original, decoded);
}
}