use serde::{de::DeserializeOwned, Serialize};
use crate::error::WsError;
pub trait Codec: Sized {
fn encode(&self) -> String
where
Self: Serialize,
{
serde_json::to_string(self).unwrap_or_default()
}
fn encode_result(&self) -> Result<String, WsError>
where
Self: Serialize,
{
serde_json::to_string(self).map_err(|_| WsError::InvalidMessage)
}
fn decode(s: &str) -> Result<Self, WsError>
where
Self: DeserializeOwned,
{
serde_json::from_str(s).map_err(|_| WsError::InvalidMessage)
}
}
impl<T> Codec for T where T: Serialize + DeserializeOwned {}
pub struct JsonCodec;
impl JsonCodec {
pub fn encode<T: Serialize>(value: &T) -> Result<String, WsError> {
serde_json::to_string(value).map_err(|_| WsError::InvalidMessage)
}
pub fn decode<T: DeserializeOwned>(s: &str) -> Result<T, WsError> {
serde_json::from_str(s).map_err(|_| WsError::InvalidMessage)
}
pub fn encode_pretty<T: Serialize>(value: &T) -> Result<String, WsError> {
serde_json::to_string_pretty(value).map_err(|_| WsError::InvalidMessage)
}
}
#[allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::indexing_slicing,
clippy::panic
)]
#[cfg(test)]
mod tests {
use super::*;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
struct Payload {
id: u32,
msg: String,
}
#[test]
fn codec_roundtrip_trait() {
let p = Payload {
id: 42,
msg: "hello".into(),
};
let s = p.encode();
let d = Payload::decode(&s).unwrap();
assert_eq!(p, d);
}
#[test]
fn codec_roundtrip_result() {
let p = Payload {
id: 1,
msg: "world".into(),
};
let s = p.encode_result().unwrap();
let d = Payload::decode(&s).unwrap();
assert_eq!(p, d);
}
#[test]
fn codec_invalid_decode() {
let err = Payload::decode("not json").unwrap_err();
assert_eq!(err, WsError::InvalidMessage);
}
#[test]
fn json_codec_helpers() {
let p = Payload {
id: 7,
msg: "test".into(),
};
let s = JsonCodec::encode(&p).unwrap();
let d: Payload = JsonCodec::decode(&s).unwrap();
assert_eq!(p, d);
let pretty = JsonCodec::encode_pretty(&p).unwrap();
assert!(pretty.contains('\n'));
}
#[test]
fn encode_vec() {
let v = vec![1, 2, 3];
let s = v.encode();
let d: Vec<i32> = Vec::decode(&s).unwrap();
assert_eq!(v, d);
}
}