1use crate::Value;
35
36pub trait MessageField: Sized {
41 fn to_value(self) -> Value;
42 fn from_value(v: &Value) -> Option<Self>;
44}
45
46#[derive(Clone, Debug, PartialEq, Eq)]
48pub enum MessageError {
49 NoKind,
52 UnknownKind(String),
54 Field { kind: String, field: &'static str },
56}
57
58impl std::fmt::Display for MessageError {
59 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60 match self {
61 MessageError::NoKind => f.write_str("the payload has no `kind`"),
62 MessageError::UnknownKind(k) => write!(f, "no message is of kind {k:?}"),
63 MessageError::Field { kind, field } => write!(
64 f,
65 "a {kind:?} message's `{field}` is missing or of the wrong type"
66 ),
67 }
68 }
69}
70
71impl std::error::Error for MessageError {}
72
73pub fn field<T: MessageField>(v: &Value, kind: &str, key: &'static str) -> Result<T, MessageError> {
76 T::from_value(v.get(key).unwrap_or(&Value::Null)).ok_or_else(|| MessageError::Field {
77 kind: kind.to_string(),
78 field: key,
79 })
80}
81
82pub fn kind_of(v: &Value) -> Result<&str, MessageError> {
84 v.get_str("kind").ok_or(MessageError::NoKind)
85}
86
87impl MessageField for Value {
88 fn to_value(self) -> Value {
89 self
90 }
91 fn from_value(v: &Value) -> Option<Self> {
92 Some(v.clone())
93 }
94}
95
96impl MessageField for bool {
97 fn to_value(self) -> Value {
98 Value::Bool(self)
99 }
100 fn from_value(v: &Value) -> Option<Self> {
101 v.as_bool()
102 }
103}
104
105impl MessageField for String {
106 fn to_value(self) -> Value {
107 Value::Str(self)
108 }
109 fn from_value(v: &Value) -> Option<Self> {
110 v.as_str().map(str::to_string)
111 }
112}
113
114impl MessageField for f64 {
115 fn to_value(self) -> Value {
116 Value::Float(self)
117 }
118 fn from_value(v: &Value) -> Option<Self> {
119 v.as_float()
120 }
121}
122
123impl MessageField for f32 {
124 fn to_value(self) -> Value {
125 Value::float(self)
126 }
127 fn from_value(v: &Value) -> Option<Self> {
128 v.as_float().map(|f| f as f32)
129 }
130}
131
132macro_rules! int_fields {
135 ($($t:ty),*) => {$(
136 impl MessageField for $t {
137 fn to_value(self) -> Value {
138 Value::Int(i64::try_from(self).unwrap_or(i64::MAX))
139 }
140 fn from_value(v: &Value) -> Option<Self> {
141 v.as_int().and_then(|n| <$t>::try_from(n).ok())
142 }
143 }
144 )*};
145}
146int_fields!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
147
148impl<T: MessageField> MessageField for Option<T> {
149 fn to_value(self) -> Value {
150 self.map_or(Value::Null, T::to_value)
151 }
152 fn from_value(v: &Value) -> Option<Self> {
153 match v {
154 Value::Null => Some(None),
155 v => T::from_value(v).map(Some),
156 }
157 }
158}
159
160impl<T: MessageField> MessageField for Vec<T> {
161 fn to_value(self) -> Value {
162 Value::List(self.into_iter().map(T::to_value).collect())
163 }
164 fn from_value(v: &Value) -> Option<Self> {
165 v.as_list()?.iter().map(T::from_value).collect()
166 }
167}
168
169impl<T: MessageField> MessageField for Box<T> {
170 fn to_value(self) -> Value {
171 (*self).to_value()
172 }
173 fn from_value(v: &Value) -> Option<Self> {
174 T::from_value(v).map(Box::new)
175 }
176}