use std::any::Any; use std::fmt::Debug; use crate::error::Result; use crate::io::{ByteStreamReader, ByteStreamWriter}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Direction { ClientToServer, ServerToClient, Bidirectional, } impl Direction { pub const fn accepts_from_client(self) -> bool { matches!(self, Direction::ClientToServer | Direction::Bidirectional) } pub const fn accepts_from_server(self) -> bool { matches!(self, Direction::ServerToClient | Direction::Bidirectional) } } pub trait Payload: Sized { fn encode(&self, writer: &mut ByteStreamWriter) -> Result<()>; fn decode(reader: &mut ByteStreamReader<'_>) -> Result; fn to_bytes(&self) -> Result> { let mut writer = ByteStreamWriter::with_capacity(64); self.encode(&mut writer)?; Ok(writer.into_inner()) } fn from_bytes(bytes: &[u8]) -> Result { let mut reader = ByteStreamReader::new(bytes); Self::decode(&mut reader) } } pub trait MessageMeta: Payload { const MESSAGE_TYPE: u16; const MESSAGE_VERSION: u16; const DIRECTION: Direction; const NAME: &'static str; } pub trait Message: Debug + Send + Sync + 'static { fn message_type(&self) -> u16; fn message_version(&self) -> u16; fn direction(&self) -> Direction; fn name(&self) -> &'static str; fn encode_payload(&self, writer: &mut ByteStreamWriter) -> Result<()>; fn as_any(&self) -> &dyn Any; } impl Message for T where T: MessageMeta + Debug + Send + Sync + 'static, { fn message_type(&self) -> u16 { T::MESSAGE_TYPE } fn message_version(&self) -> u16 { T::MESSAGE_VERSION } fn direction(&self) -> Direction { T::DIRECTION } fn name(&self) -> &'static str { T::NAME } fn encode_payload(&self, writer: &mut ByteStreamWriter) -> Result<()> { Payload::encode(self, writer) } fn as_any(&self) -> &dyn Any { self } }