1use alloc::collections::BTreeMap;
17use alloc::string::String;
18use alloc::vec::Vec;
19
20pub use crate::json::Value;
21
22pub trait Field: Sized + Default {
24 fn put(&self) -> Value;
25 fn take(v: Option<&Value>) -> Self;
26}
27
28pub trait Json: Sized {
30 fn to_json(&self) -> Value;
31 fn from_json(v: &Value) -> Option<Self>;
32}
33
34impl Field for String {
35 fn put(&self) -> Value {
36 Value::string(self.as_str())
37 }
38 fn take(v: Option<&Value>) -> Self {
39 v.and_then(Value::as_str).map(String::from).unwrap_or_default()
40 }
41}
42
43impl Field for bool {
44 fn put(&self) -> Value {
45 Value::Bool(*self)
46 }
47 fn take(v: Option<&Value>) -> Self {
48 v.and_then(Value::as_bool).unwrap_or(false)
49 }
50}
51
52impl Field for u64 {
53 fn put(&self) -> Value {
54 Value::u64(*self)
55 }
56 fn take(v: Option<&Value>) -> Self {
57 v.and_then(Value::as_u64).unwrap_or(0)
58 }
59}
60
61impl Field for i64 {
62 fn put(&self) -> Value {
63 Value::i64(*self)
64 }
65 fn take(v: Option<&Value>) -> Self {
66 v.and_then(Value::as_i64).unwrap_or(0)
67 }
68}
69
70impl Field for u32 {
71 fn put(&self) -> Value {
72 Value::u64(*self as u64)
73 }
74 fn take(v: Option<&Value>) -> Self {
75 v.and_then(Value::as_u64).map_or(0, |x| x.min(u32::MAX as u64) as u32)
76 }
77}
78
79impl Field for i32 {
80 fn put(&self) -> Value {
81 Value::i64(*self as i64)
82 }
83 fn take(v: Option<&Value>) -> Self {
84 v.and_then(Value::as_i64).map_or(0, |x| x.clamp(i32::MIN as i64, i32::MAX as i64) as i32)
85 }
86}
87
88impl Field for u16 {
89 fn put(&self) -> Value {
90 Value::u64(*self as u64)
91 }
92 fn take(v: Option<&Value>) -> Self {
93 v.and_then(Value::as_u64).map_or(0, |x| x.min(u16::MAX as u64) as u16)
94 }
95}
96
97impl Field for u8 {
98 fn put(&self) -> Value {
99 Value::u64(*self as u64)
100 }
101 fn take(v: Option<&Value>) -> Self {
102 v.and_then(Value::as_u64).map_or(0, |x| x.min(255) as u8)
103 }
104}
105
106impl Default for Value {
107 fn default() -> Value {
108 Value::Null
109 }
110}
111
112impl Field for Value {
114 fn put(&self) -> Value {
115 self.clone()
116 }
117 fn take(v: Option<&Value>) -> Self {
118 v.cloned().unwrap_or(Value::Null)
119 }
120}
121
122impl<T: Field> Field for Vec<T> {
123 fn put(&self) -> Value {
124 Value::Array(self.iter().map(Field::put).collect())
125 }
126 fn take(v: Option<&Value>) -> Self {
127 v.and_then(Value::as_array).map(|a| a.iter().map(|x| T::take(Some(x))).collect()).unwrap_or_default()
128 }
129}
130
131impl<T: Field> Field for Option<T> {
132 fn put(&self) -> Value {
133 match self {
134 Some(x) => x.put(),
135 None => Value::Null,
136 }
137 }
138 fn take(v: Option<&Value>) -> Self {
139 match v {
140 None | Some(Value::Null) => None,
141 Some(x) => Some(T::take(Some(x))),
142 }
143 }
144}
145
146impl<T: Field> Field for BTreeMap<String, T> {
148 fn put(&self) -> Value {
149 Value::Object(self.iter().map(|(k, v)| (k.clone(), v.put())).collect())
150 }
151 fn take(v: Option<&Value>) -> Self {
152 v.and_then(Value::as_object).map(|o| o.iter().map(|(k, x)| (k.clone(), T::take(Some(x)))).collect()).unwrap_or_default()
153 }
154}
155
156pub fn empty_object() -> Value {
158 Value::Object(Vec::new())
159}
160
161#[macro_export]
164macro_rules! record {
165 ($(#[$m:meta])* pub struct $name:ident { $( $(#[$fm:meta])* pub $f:ident : $t:ty ),* $(,)? }) => {
166 $(#[$m])*
167 #[derive(Clone, Debug, Default, PartialEq)]
168 pub struct $name { $( $(#[$fm])* pub $f: $t ),* }
169 impl $crate::jmap::Json for $name {
170 fn to_json(&self) -> $crate::jmap::Value {
171 #[allow(unused_mut)]
172 let mut o = $crate::jmap::empty_object();
173 $( o.insert(stringify!($f), $crate::jmap::Field::put(&self.$f)); )*
174 o
175 }
176 fn from_json(v: &$crate::jmap::Value) -> Option<Self> {
177 v.as_object()?;
178 Some($name { $( $f: $crate::jmap::Field::take(v.get(stringify!($f))) ),* })
179 }
180 }
181 impl $crate::jmap::Field for $name {
182 fn put(&self) -> $crate::jmap::Value {
183 $crate::jmap::Json::to_json(self)
184 }
185 fn take(v: Option<&$crate::jmap::Value>) -> Self {
186 v.and_then(<$name as $crate::jmap::Json>::from_json).unwrap_or_default()
187 }
188 }
189 };
190}
191
192#[macro_export]
195macro_rules! wire_enum {
196 ($(#[$m:meta])* pub enum $name:ident { $first:ident = $fs:literal $(, $v:ident = $s:literal)* $(,)? }) => {
197 $(#[$m])*
198 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
199 pub enum $name { #[default] $first $(, $v)* }
200 impl $name {
201 pub const ALL: &'static [$name] = &[$name::$first $(, $name::$v)*];
203 pub fn as_str(&self) -> &'static str {
205 match self { $name::$first => $fs $(, $name::$v => $s)* }
206 }
207 pub fn parse(s: &str) -> Option<$name> {
209 match s { $fs => Some($name::$first) $(, $s => Some($name::$v))*, _ => None }
210 }
211 }
212 impl $crate::jmap::Field for $name {
213 fn put(&self) -> $crate::jmap::Value {
214 $crate::jmap::Value::string(self.as_str())
215 }
216 fn take(v: Option<&$crate::jmap::Value>) -> Self {
217 v.and_then($crate::jmap::Value::as_str).and_then($name::parse).unwrap_or_default()
218 }
219 }
220 };
221}
222
223pub fn list<T: Json>(items: &[T]) -> Value {
225 Value::Array(items.iter().map(Json::to_json).collect())
226}
227
228pub fn from_list<T: Json>(v: &Value) -> Vec<T> {
230 let arr = v.as_array().or_else(|| v.get("items").and_then(Value::as_array));
231 arr.map(|a| a.iter().filter_map(T::from_json).collect()).unwrap_or_default()
232}
233
234pub fn str_of<'a>(v: &'a Value, k: &str) -> &'a str {
236 v.get(k).and_then(Value::as_str).unwrap_or("")
237}
238
239pub fn u64_of(v: &Value, k: &str) -> u64 {
241 v.get(k).and_then(Value::as_u64).unwrap_or(0)
242}
243
244pub fn obj<const N: usize>(fields: [(&str, Value); N]) -> Value {
246 Value::object(fields)
247}