use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum WsMessage {
Text(String),
Binary(Vec<u8>),
}
#[derive(Debug)]
pub enum EncodeError {
Json(serde_json::Error),
Custom(String),
}
impl fmt::Display for EncodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
EncodeError::Json(e) => write!(f, "JSON encode error: {e}"),
EncodeError::Custom(msg) => write!(f, "encode error: {msg}"),
}
}
}
impl std::error::Error for EncodeError {}
impl From<serde_json::Error> for EncodeError {
fn from(e: serde_json::Error) -> Self {
EncodeError::Json(e)
}
}
#[derive(Debug)]
pub enum DecodeError {
Json(serde_json::Error),
UnexpectedBinary,
UnexpectedText,
InvalidData(String),
}
impl fmt::Display for DecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DecodeError::Json(e) => write!(f, "JSON decode error: {e}"),
DecodeError::UnexpectedBinary => write!(f, "expected text frame, got binary"),
DecodeError::UnexpectedText => write!(f, "expected binary frame, got text"),
DecodeError::InvalidData(msg) => write!(f, "invalid data: {msg}"),
}
}
}
impl std::error::Error for DecodeError {}
impl From<serde_json::Error> for DecodeError {
fn from(e: serde_json::Error) -> Self {
DecodeError::Json(e)
}
}
pub trait WsCodec: Sized {
fn encode(&self) -> Result<WsMessage, EncodeError>;
fn decode(msg: WsMessage) -> Result<Self, DecodeError>;
}
impl<T: serde::Serialize + serde::de::DeserializeOwned> WsCodec for T {
fn encode(&self) -> Result<WsMessage, EncodeError> {
Ok(WsMessage::Text(serde_json::to_string(self)?))
}
fn decode(msg: WsMessage) -> Result<Self, DecodeError> {
match msg {
WsMessage::Text(text) => Ok(serde_json::from_str(&text)?),
WsMessage::Binary(_) => Err(DecodeError::UnexpectedBinary),
}
}
}
pub enum NoMessages {}
impl Clone for NoMessages {
fn clone(&self) -> Self {
match *self {}
}
}
impl WsCodec for NoMessages {
fn encode(&self) -> Result<WsMessage, EncodeError> {
match *self {}
}
fn decode(_msg: WsMessage) -> Result<Self, DecodeError> {
Err(DecodeError::InvalidData(
"this endpoint does not accept messages in this direction".into(),
))
}
}