use serde::{Serialize, de::DeserializeOwned};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum DecodeError {
#[error("failed to decode term: {0}")]
Deserialize(#[from] postcard::Error),
}
pub trait Term: Sized + Send + 'static {
fn encode(&self) -> Vec<u8>;
fn decode(bytes: &[u8]) -> Result<Self, DecodeError>;
fn try_encode(&self) -> Option<Vec<u8>>;
}
impl<T> Term for T
where
T: Serialize + DeserializeOwned + Send + 'static,
{
fn encode(&self) -> Vec<u8> {
postcard::to_allocvec(self).expect("term serialization failed")
}
fn decode(bytes: &[u8]) -> Result<Self, DecodeError> {
postcard::from_bytes(bytes).map_err(DecodeError::from)
}
fn try_encode(&self) -> Option<Vec<u8>> {
postcard::to_allocvec(self).ok()
}
}
#[deprecated(since = "0.2.0", note = "Use `Term` instead of `Message`")]
pub trait Message: Term {}
#[allow(deprecated)]
impl<T: Term> Message for T {}
#[cfg(test)]
mod tests {
use super::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
struct TestTerm {
id: u32,
name: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
enum TestEnum {
Ping(u64),
Pong { value: String },
}
#[test]
fn test_encode_decode_struct() {
let term = TestTerm {
id: 42,
name: "hello".to_string(),
};
let bytes = term.encode();
let decoded = TestTerm::decode(&bytes).unwrap();
assert_eq!(term, decoded);
}
#[test]
fn test_encode_decode_enum() {
let term = TestEnum::Ping(123);
let bytes = term.encode();
let decoded = TestEnum::decode(&bytes).unwrap();
assert_eq!(term, decoded);
let term = TestEnum::Pong {
value: "world".to_string(),
};
let bytes = term.encode();
let decoded = TestEnum::decode(&bytes).unwrap();
assert_eq!(term, decoded);
}
#[test]
fn test_decode_error() {
let bad_bytes = vec![0xFF, 0xFF, 0xFF];
let result = TestTerm::decode(&bad_bytes);
assert!(result.is_err());
}
#[test]
fn test_try_encode() {
let term = TestTerm {
id: 1,
name: "test".to_string(),
};
let bytes = term.try_encode();
assert!(bytes.is_some());
}
#[test]
fn test_primitive_types() {
let num: u32 = 42;
let bytes = num.encode();
let decoded = u32::decode(&bytes).unwrap();
assert_eq!(num, decoded);
let s = "hello world".to_string();
let bytes = s.encode();
let decoded = String::decode(&bytes).unwrap();
assert_eq!(s, decoded);
let v: Vec<u8> = vec![1, 2, 3, 4];
let bytes = v.encode();
let decoded = Vec::<u8>::decode(&bytes).unwrap();
assert_eq!(v, decoded);
}
#[test]
fn test_option_types() {
let some: Option<u32> = Some(42);
let bytes = some.encode();
let decoded = Option::<u32>::decode(&bytes).unwrap();
assert_eq!(some, decoded);
let none: Option<u32> = None;
let bytes = none.encode();
let decoded = Option::<u32>::decode(&bytes).unwrap();
assert_eq!(none, decoded);
}
#[test]
fn test_tuple_types() {
let tuple: (u32, String, bool) = (42, "test".to_string(), true);
let bytes = tuple.encode();
let decoded = <(u32, String, bool)>::decode(&bytes).unwrap();
assert_eq!(tuple, decoded);
}
#[test]
fn test_unit_type() {
let unit: () = ();
let bytes = unit.encode();
<()>::decode(&bytes).unwrap();
assert_eq!(unit, ());
}
#[test]
fn test_tuple_as_registry_key() {
let key = ("room".to_string(), "lobby".to_string());
let bytes = key.encode();
let decoded: (String, String) = Term::decode(&bytes).unwrap();
assert_eq!(key, decoded);
let key = ("game".to_string(), 123u64, "player1".to_string());
let bytes = key.encode();
let decoded: (String, u64, String) = Term::decode(&bytes).unwrap();
assert_eq!(key, decoded);
}
}