1use std::{
107 collections::HashSet,
108 hash::{
109 BuildHasher,
110 Hash,
111 },
112};
113
114pub use battler_wamp_values_proc_macro::{
115 WampDictionary,
116 WampList,
117};
118use serde::{
119 Deserialize,
120 Serialize,
121};
122use thiserror::Error;
123
124pub type Integer = u64;
126
127pub type Dictionary = ahash::HashMap<String, Value>;
129
130pub type List = Vec<Value>;
132
133#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
138#[serde(untagged)]
139pub enum Value {
140 Null,
141 Integer(Integer),
142 String(String),
143 Bool(bool),
144 Dictionary(Dictionary),
145 List(List),
146}
147
148impl Value {
149 pub fn integer(&self) -> Option<Integer> {
151 match self {
152 Self::Integer(val) => Some(*val),
153 _ => None,
154 }
155 }
156
157 pub fn string(&self) -> Option<&str> {
159 match self {
160 Self::String(val) => Some(val),
161 _ => None,
162 }
163 }
164
165 pub fn bool(&self) -> Option<bool> {
167 match self {
168 Self::Bool(val) => Some(*val),
169 _ => None,
170 }
171 }
172
173 pub fn dictionary(&self) -> Option<&Dictionary> {
175 match self {
176 Self::Dictionary(val) => Some(val),
177 _ => None,
178 }
179 }
180
181 pub fn dictionary_mut(&mut self) -> Option<&mut Dictionary> {
183 match self {
184 Self::Dictionary(val) => Some(val),
185 _ => None,
186 }
187 }
188
189 pub fn list(&self) -> Option<&List> {
191 match self {
192 Self::List(val) => Some(val),
193 _ => None,
194 }
195 }
196
197 pub fn list_mut(&mut self) -> Option<&mut List> {
199 match self {
200 Self::List(val) => Some(val),
201 _ => None,
202 }
203 }
204}
205
206impl From<Integer> for Value {
207 fn from(value: Integer) -> Self {
208 Self::Integer(value)
209 }
210}
211
212impl From<String> for Value {
213 fn from(value: String) -> Self {
214 Self::String(value)
215 }
216}
217
218impl From<&str> for Value {
219 fn from(value: &str) -> Self {
220 Self::String(value.to_owned())
221 }
222}
223
224impl From<bool> for Value {
225 fn from(value: bool) -> Self {
226 Self::Bool(value)
227 }
228}
229
230impl From<Dictionary> for Value {
231 fn from(value: Dictionary) -> Self {
232 Self::Dictionary(value)
233 }
234}
235
236impl From<List> for Value {
237 fn from(value: List) -> Self {
238 Self::List(value)
239 }
240}
241
242impl<T> From<Option<T>> for Value
243where
244 T: Into<Value>,
245{
246 fn from(value: Option<T>) -> Self {
247 match value {
248 Some(value) => value.into(),
249 None => Value::Null,
250 }
251 }
252}
253
254#[derive(Debug, Error)]
257#[error("{msg}")]
258pub struct WampSerializeError {
259 msg: String,
260}
261
262impl WampSerializeError {
263 pub fn new<S>(msg: S) -> Self
264 where
265 S: Into<String>,
266 {
267 Self { msg: msg.into() }
268 }
269
270 pub fn annotate(&self, msg: String) -> Self {
271 Self::new(format!("{}; {msg}", self.msg))
272 }
273}
274
275#[derive(Debug, Error)]
278#[error("{msg}")]
279pub struct WampDeserializeError {
280 msg: String,
281}
282
283impl WampDeserializeError {
284 pub fn new<S>(msg: S) -> Self
285 where
286 S: Into<String>,
287 {
288 Self { msg: msg.into() }
289 }
290
291 pub fn annotate(&self, msg: String) -> Self {
292 Self::new(format!("{}; {msg}", self.msg))
293 }
294}
295
296pub trait WampSerialize {
298 fn wamp_serialize(self) -> Result<Value, WampSerializeError>;
300}
301
302impl WampSerialize for Integer {
303 fn wamp_serialize(self) -> Result<Value, WampSerializeError> {
304 Ok(Value::Integer(self))
305 }
306}
307
308impl WampSerialize for String {
309 fn wamp_serialize(self) -> Result<Value, WampSerializeError> {
310 Ok(Value::String(self))
311 }
312}
313
314impl WampSerialize for bool {
315 fn wamp_serialize(self) -> Result<Value, WampSerializeError> {
316 Ok(Value::Bool(self))
317 }
318}
319
320impl WampSerialize for List {
321 fn wamp_serialize(self) -> Result<Value, WampSerializeError> {
322 Ok(Value::List(self))
323 }
324}
325
326impl WampSerialize for Dictionary {
327 fn wamp_serialize(self) -> Result<Value, WampSerializeError> {
328 Ok(Value::Dictionary(self))
329 }
330}
331
332impl<T> WampSerialize for Option<T>
333where
334 T: WampSerialize,
335{
336 fn wamp_serialize(self) -> Result<Value, WampSerializeError> {
337 match self {
338 Some(val) => val.wamp_serialize(),
339 None => Ok(Value::Null),
340 }
341 }
342}
343
344impl<T> WampSerialize for Vec<T>
345where
346 T: WampSerialize,
347{
348 fn wamp_serialize(self) -> Result<Value, WampSerializeError> {
349 Ok(Value::List(
350 self.into_iter()
351 .map(|val| val.wamp_serialize())
352 .collect::<Result<Vec<_>, _>>()?,
353 ))
354 }
355}
356
357impl<T, S> WampSerialize for std::collections::HashSet<T, S>
358where
359 T: WampSerialize,
360{
361 fn wamp_serialize(self) -> Result<Value, WampSerializeError> {
362 Ok(Value::List(
363 self.into_iter()
364 .map(|val| val.wamp_serialize())
365 .collect::<Result<Vec<_>, _>>()?,
366 ))
367 }
368}
369
370impl<T> WampSerialize for ahash::HashMap<String, T>
371where
372 T: WampSerialize,
373{
374 fn wamp_serialize(self) -> Result<Value, WampSerializeError> {
375 Ok(Value::Dictionary(
376 self.into_iter()
377 .map(|(key, val)| Ok((key, val.wamp_serialize()?)))
378 .collect::<Result<Dictionary, _>>()?,
379 ))
380 }
381}
382
383pub trait WampDeserialize: Sized {
385 fn wamp_deserialize(value: Value) -> Result<Self, WampDeserializeError>;
387}
388
389impl WampDeserialize for Integer {
390 fn wamp_deserialize(value: Value) -> Result<Self, WampDeserializeError> {
391 match value {
392 Value::Integer(val) => Ok(val),
393 _ => Err(WampDeserializeError::new("value must be an integer")),
394 }
395 }
396}
397
398impl WampDeserialize for String {
399 fn wamp_deserialize(value: Value) -> Result<Self, WampDeserializeError> {
400 match value {
401 Value::String(val) => Ok(val),
402 _ => Err(WampDeserializeError::new("value must be a string")),
403 }
404 }
405}
406
407impl WampDeserialize for bool {
408 fn wamp_deserialize(value: Value) -> Result<Self, WampDeserializeError> {
409 match value {
410 Value::Bool(val) => Ok(val),
411 _ => Err(WampDeserializeError::new("value must be a bool")),
412 }
413 }
414}
415
416impl WampDeserialize for List {
417 fn wamp_deserialize(value: Value) -> Result<Self, WampDeserializeError> {
418 match value {
419 Value::List(val) => Ok(val),
420 _ => Err(WampDeserializeError::new("value must be a list")),
421 }
422 }
423}
424
425impl WampDeserialize for Dictionary {
426 fn wamp_deserialize(value: Value) -> Result<Self, WampDeserializeError> {
427 match value {
428 Value::Dictionary(val) => Ok(val),
429 _ => Err(WampDeserializeError::new("value must be a dictionary")),
430 }
431 }
432}
433
434impl<T> WampDeserialize for Option<T>
435where
436 T: WampDeserialize,
437{
438 fn wamp_deserialize(value: Value) -> Result<Self, WampDeserializeError> {
439 match value {
440 Value::Null => Ok(None),
441 value @ _ => Ok(Some(T::wamp_deserialize(value)?)),
442 }
443 }
444}
445
446impl<T> WampDeserialize for Vec<T>
447where
448 T: WampDeserialize,
449{
450 fn wamp_deserialize(value: Value) -> Result<Self, WampDeserializeError> {
451 match value {
452 Value::List(val) => val
453 .into_iter()
454 .map(|val| WampDeserialize::wamp_deserialize(val))
455 .collect::<Result<Vec<_>, _>>(),
456 _ => Err(WampDeserializeError::new("value must be a list")),
457 }
458 }
459}
460
461impl<T, S> WampDeserialize for HashSet<T, S>
462where
463 T: WampDeserialize + Eq + Hash,
464 S: BuildHasher + Default,
465{
466 fn wamp_deserialize(value: Value) -> Result<Self, WampDeserializeError> {
467 match value {
468 Value::List(val) => val
469 .into_iter()
470 .map(|val| WampDeserialize::wamp_deserialize(val))
471 .collect::<Result<HashSet<_, S>, _>>(),
472 _ => Err(WampDeserializeError::new("value must be a list")),
473 }
474 }
475}
476
477impl<T> WampDeserialize for ahash::HashMap<String, T>
478where
479 T: WampDeserialize,
480{
481 fn wamp_deserialize(value: Value) -> Result<Self, WampDeserializeError> {
482 match value {
483 Value::Dictionary(val) => val
484 .into_iter()
485 .map(|(key, val)| Ok((key, WampDeserialize::wamp_deserialize(val)?)))
486 .collect::<Result<ahash::HashMap<_, _>, _>>(),
487 _ => Err(WampDeserializeError::new("value must be a dictionary")),
488 }
489 }
490}