1use serde::{de::DeserializeOwned, Serialize};
7
8use crate::error::WsError;
9
10pub trait Codec: Sized {
29 fn encode(&self) -> String
37 where
38 Self: Serialize,
39 {
40 serde_json::to_string(self).unwrap_or_default()
41 }
42
43 fn encode_result(&self) -> Result<String, WsError>
45 where
46 Self: Serialize,
47 {
48 serde_json::to_string(self).map_err(|_| WsError::InvalidMessage)
49 }
50
51 fn decode(s: &str) -> Result<Self, WsError>
53 where
54 Self: DeserializeOwned,
55 {
56 serde_json::from_str(s).map_err(|_| WsError::InvalidMessage)
57 }
58}
59
60impl<T> Codec for T where T: Serialize + DeserializeOwned {}
62
63pub struct JsonCodec;
66
67impl JsonCodec {
68 pub fn encode<T: Serialize>(value: &T) -> Result<String, WsError> {
70 serde_json::to_string(value).map_err(|_| WsError::InvalidMessage)
71 }
72
73 pub fn decode<T: DeserializeOwned>(s: &str) -> Result<T, WsError> {
75 serde_json::from_str(s).map_err(|_| WsError::InvalidMessage)
76 }
77
78 pub fn encode_pretty<T: Serialize>(value: &T) -> Result<String, WsError> {
80 serde_json::to_string_pretty(value).map_err(|_| WsError::InvalidMessage)
81 }
82}
83
84#[allow(
88 clippy::unwrap_used,
89 clippy::expect_used,
90 clippy::indexing_slicing,
91 clippy::panic
92)]
93#[cfg(test)]
94mod tests {
95 use super::*;
96 use serde::{Deserialize, Serialize};
97
98 #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
99 struct Payload {
100 id: u32,
101 msg: String,
102 }
103
104 #[test]
105 fn codec_roundtrip_trait() {
106 let p = Payload {
107 id: 42,
108 msg: "hello".into(),
109 };
110 let s = p.encode();
111 let d = Payload::decode(&s).unwrap();
112 assert_eq!(p, d);
113 }
114
115 #[test]
116 fn codec_roundtrip_result() {
117 let p = Payload {
118 id: 1,
119 msg: "world".into(),
120 };
121 let s = p.encode_result().unwrap();
122 let d = Payload::decode(&s).unwrap();
123 assert_eq!(p, d);
124 }
125
126 #[test]
127 fn codec_invalid_decode() {
128 let err = Payload::decode("not json").unwrap_err();
129 assert_eq!(err, WsError::InvalidMessage);
130 }
131
132 #[test]
133 fn json_codec_helpers() {
134 let p = Payload {
135 id: 7,
136 msg: "test".into(),
137 };
138 let s = JsonCodec::encode(&p).unwrap();
139 let d: Payload = JsonCodec::decode(&s).unwrap();
140 assert_eq!(p, d);
141
142 let pretty = JsonCodec::encode_pretty(&p).unwrap();
143 assert!(pretty.contains('\n'));
144 }
145
146 #[test]
147 fn encode_vec() {
148 let v = vec![1, 2, 3];
149 let s = v.encode();
150 let d: Vec<i32> = Vec::decode(&s).unwrap();
151 assert_eq!(v, d);
152 }
153}