1use serde::{Serialize, de::DeserializeOwned};
16use thiserror::Error;
17
18#[derive(Debug, Error)]
20pub enum DecodeError {
21 #[error("failed to decode term: {0}")]
23 Deserialize(#[from] postcard::Error),
24}
25
26pub trait Term: Sized + Send + 'static {
72 fn encode(&self) -> Vec<u8>;
79
80 fn decode(bytes: &[u8]) -> Result<Self, DecodeError>;
86
87 fn try_encode(&self) -> Option<Vec<u8>>;
89}
90
91impl<T> Term for T
92where
93 T: Serialize + DeserializeOwned + Send + 'static,
94{
95 fn encode(&self) -> Vec<u8> {
96 postcard::to_allocvec(self).expect("term serialization failed")
97 }
98
99 fn decode(bytes: &[u8]) -> Result<Self, DecodeError> {
100 postcard::from_bytes(bytes).map_err(DecodeError::from)
101 }
102
103 fn try_encode(&self) -> Option<Vec<u8>> {
104 postcard::to_allocvec(self).ok()
105 }
106}
107
108#[deprecated(since = "0.2.0", note = "Use `Term` instead of `Message`")]
113pub trait Message: Term {}
114
115#[allow(deprecated)]
116impl<T: Term> Message for T {}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121 use serde::{Deserialize, Serialize};
122
123 #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
124 struct TestTerm {
125 id: u32,
126 name: String,
127 }
128
129 #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
130 enum TestEnum {
131 Ping(u64),
132 Pong { value: String },
133 }
134
135 #[test]
136 fn test_encode_decode_struct() {
137 let term = TestTerm {
138 id: 42,
139 name: "hello".to_string(),
140 };
141 let bytes = term.encode();
142 let decoded = TestTerm::decode(&bytes).unwrap();
143 assert_eq!(term, decoded);
144 }
145
146 #[test]
147 fn test_encode_decode_enum() {
148 let term = TestEnum::Ping(123);
149 let bytes = term.encode();
150 let decoded = TestEnum::decode(&bytes).unwrap();
151 assert_eq!(term, decoded);
152
153 let term = TestEnum::Pong {
154 value: "world".to_string(),
155 };
156 let bytes = term.encode();
157 let decoded = TestEnum::decode(&bytes).unwrap();
158 assert_eq!(term, decoded);
159 }
160
161 #[test]
162 fn test_decode_error() {
163 let bad_bytes = vec![0xFF, 0xFF, 0xFF];
164 let result = TestTerm::decode(&bad_bytes);
165 assert!(result.is_err());
166 }
167
168 #[test]
169 fn test_try_encode() {
170 let term = TestTerm {
171 id: 1,
172 name: "test".to_string(),
173 };
174 let bytes = term.try_encode();
175 assert!(bytes.is_some());
176 }
177
178 #[test]
179 fn test_primitive_types() {
180 let num: u32 = 42;
182 let bytes = num.encode();
183 let decoded = u32::decode(&bytes).unwrap();
184 assert_eq!(num, decoded);
185
186 let s = "hello world".to_string();
188 let bytes = s.encode();
189 let decoded = String::decode(&bytes).unwrap();
190 assert_eq!(s, decoded);
191
192 let v: Vec<u8> = vec![1, 2, 3, 4];
194 let bytes = v.encode();
195 let decoded = Vec::<u8>::decode(&bytes).unwrap();
196 assert_eq!(v, decoded);
197 }
198
199 #[test]
200 fn test_option_types() {
201 let some: Option<u32> = Some(42);
202 let bytes = some.encode();
203 let decoded = Option::<u32>::decode(&bytes).unwrap();
204 assert_eq!(some, decoded);
205
206 let none: Option<u32> = None;
207 let bytes = none.encode();
208 let decoded = Option::<u32>::decode(&bytes).unwrap();
209 assert_eq!(none, decoded);
210 }
211
212 #[test]
213 fn test_tuple_types() {
214 let tuple: (u32, String, bool) = (42, "test".to_string(), true);
216 let bytes = tuple.encode();
217 let decoded = <(u32, String, bool)>::decode(&bytes).unwrap();
218 assert_eq!(tuple, decoded);
219 }
220
221 #[test]
222 fn test_unit_type() {
223 let unit: () = ();
224 let bytes = unit.encode();
225 <()>::decode(&bytes).unwrap();
226 assert_eq!(unit, ());
227 }
228
229 #[test]
230 fn test_tuple_as_registry_key() {
231 let key = ("room".to_string(), "lobby".to_string());
234 let bytes = key.encode();
235 let decoded: (String, String) = Term::decode(&bytes).unwrap();
236 assert_eq!(key, decoded);
237
238 let key = ("game".to_string(), 123u64, "player1".to_string());
240 let bytes = key.encode();
241 let decoded: (String, u64, String) = Term::decode(&bytes).unwrap();
242 assert_eq!(key, decoded);
243 }
244}