1#[macro_export]
49macro_rules! json {
50 (null) => { $crate::Value::Null };
51
52 ([]) => { $crate::Value::Array(::std::vec::Vec::new()) };
53 ([ $($elem:tt)+ ]) => {
54 $crate::Value::Array($crate::json_array![[] $($elem)+])
55 };
56
57 ({}) => { $crate::Value::Object(::std::vec::Vec::new()) };
58 ({ $($member:tt)+ }) => {
59 $crate::Value::Object($crate::json_object![[] $($member)+])
60 };
61
62 ($other:expr) => { $crate::Value::from($other) };
65}
66
67#[macro_export]
69#[doc(hidden)]
70macro_rules! json_array {
71 ([$($done:expr),*]) => { ::std::vec![$($done),*] };
73 ([$($done:expr),*] ,) => { ::std::vec![$($done),*] };
74
75 ([$($done:expr),*] [$($arr:tt)*] , $($rest:tt)*) => {
78 $crate::json_array![[$($done,)* $crate::json!([$($arr)*])] $($rest)*]
79 };
80 ([$($done:expr),*] [$($arr:tt)*]) => {
81 $crate::json_array![[$($done,)* $crate::json!([$($arr)*])]]
82 };
83 ([$($done:expr),*] {$($obj:tt)*} , $($rest:tt)*) => {
84 $crate::json_array![[$($done,)* $crate::json!({$($obj)*})] $($rest)*]
85 };
86 ([$($done:expr),*] {$($obj:tt)*}) => {
87 $crate::json_array![[$($done,)* $crate::json!({$($obj)*})]]
88 };
89
90 ([$($done:expr),*] null , $($rest:tt)*) => {
94 $crate::json_array![[$($done,)* $crate::Value::Null] $($rest)*]
95 };
96 ([$($done:expr),*] null) => {
97 $crate::json_array![[$($done,)* $crate::Value::Null]]
98 };
99
100 ([$($done:expr),*] $next:expr , $($rest:tt)*) => {
101 $crate::json_array![[$($done,)* $crate::json!($next)] $($rest)*]
102 };
103 ([$($done:expr),*] $last:expr) => {
104 $crate::json_array![[$($done,)* $crate::json!($last)]]
105 };
106}
107
108#[macro_export]
110#[doc(hidden)]
111macro_rules! json_object {
112 ([$($done:expr),*]) => { ::std::vec![$($done),*] };
113 ([$($done:expr),*] ,) => { ::std::vec![$($done),*] };
114
115 ([$($done:expr),*] $key:tt : [$($arr:tt)*] , $($rest:tt)*) => {
117 $crate::json_object![[$($done,)* ($crate::json_key!($key), $crate::json!([$($arr)*]))] $($rest)*]
118 };
119 ([$($done:expr),*] $key:tt : [$($arr:tt)*]) => {
120 $crate::json_object![[$($done,)* ($crate::json_key!($key), $crate::json!([$($arr)*]))]]
121 };
122 ([$($done:expr),*] $key:tt : {$($obj:tt)*} , $($rest:tt)*) => {
123 $crate::json_object![[$($done,)* ($crate::json_key!($key), $crate::json!({$($obj)*}))] $($rest)*]
124 };
125 ([$($done:expr),*] $key:tt : {$($obj:tt)*}) => {
126 $crate::json_object![[$($done,)* ($crate::json_key!($key), $crate::json!({$($obj)*}))]]
127 };
128
129 ([$($done:expr),*] $key:tt : null , $($rest:tt)*) => {
131 $crate::json_object![[$($done,)* ($crate::json_key!($key), $crate::Value::Null)] $($rest)*]
132 };
133 ([$($done:expr),*] $key:tt : null) => {
134 $crate::json_object![[$($done,)* ($crate::json_key!($key), $crate::Value::Null)]]
135 };
136
137 ([$($done:expr),*] $key:tt : $val:expr , $($rest:tt)*) => {
138 $crate::json_object![[$($done,)* ($crate::json_key!($key), $crate::json!($val))] $($rest)*]
139 };
140 ([$($done:expr),*] $key:tt : $val:expr) => {
141 $crate::json_object![[$($done,)* ($crate::json_key!($key), $crate::json!($val))]]
142 };
143}
144
145#[macro_export]
150#[doc(hidden)]
151macro_rules! json_key {
152 (($key:expr)) => {
153 ::std::string::ToString::to_string(&$key)
154 };
155 ($key:literal) => {
156 ::std::string::ToString::to_string(&$key)
157 };
158 ($key:tt) => {
159 ::std::stringify!($key).to_string()
160 };
161}
162
163#[cfg(test)]
164mod tests {
165 use crate::Value;
166
167 #[test]
168 fn builds_scalars_and_empties() {
169 assert_eq!(json!(null), Value::Null);
170 assert_eq!(json!(true), Value::Bool(true));
171 assert_eq!(json!(42), Value::Int(42));
172 assert_eq!(json!(2.5), Value::Float(2.5));
173 assert_eq!(json!("s"), Value::Str("s".into()));
174 assert_eq!(json!([]).to_json(), "[]");
175 assert_eq!(json!({}).to_json(), "{}");
176 }
177
178 #[test]
179 fn nests_arrays_and_objects_and_tolerates_trailing_commas() {
180 let v = json!({
181 "a": [1, 2, [3, {"deep": true}]],
182 "b": { "c": { "d": null } },
183 });
184 assert_eq!(
185 v.to_json(),
186 r#"{"a":[1,2,[3,{"deep":true}]],"b":{"c":{"d":null}}}"#
187 );
188 assert_eq!(json!([1, 2, 3,]).to_json(), "[1,2,3]");
189 }
190
191 #[test]
192 fn object_keys_preserve_insertion_order() {
193 let v = json!({ "z": 1, "a": 2, "m": 3 });
196 assert_eq!(v.to_json(), r#"{"z":1,"a":2,"m":3}"#);
197 }
198
199 #[test]
200 fn interpolates_expressions_in_key_and_value_position() {
201 let key = "dynamic";
202 let n = 3_i64;
203 let owned = String::from("owned");
204 let v = json!({ (key): n * 2, "s": owned, "computed": n > 1 });
205 assert_eq!(v.to_json(), r#"{"dynamic":6,"s":"owned","computed":true}"#);
206 }
207
208 #[test]
209 fn nests_an_existing_value_through_the_identity_conversion() {
210 let inner = json!({ "already": "built" });
211 let outer = json!({ "wrapped": inner });
212 assert_eq!(outer.to_json(), r#"{"wrapped":{"already":"built"}}"#);
213 }
214
215 #[test]
216 fn converts_options_vecs_and_slices() {
217 let some: Option<i64> = Some(7);
218 let none: Option<i64> = None;
219 let xs: Vec<i64> = vec![1, 2];
220 let slice: &[&str] = &["a", "b"];
221 let v = json!({ "some": some, "none": none, "xs": xs, "slice": slice });
222 assert_eq!(
223 v.to_json(),
224 r#"{"some":7,"none":null,"xs":[1,2],"slice":["a","b"]}"#
225 );
226 }
227
228 #[test]
229 fn collects_pairs_into_an_object() {
230 let v: Value = [("a", 1_i64), ("b", 2)].into_iter().collect();
231 assert_eq!(v.to_json(), r#"{"a":1,"b":2}"#);
232 }
233
234 #[test]
235 fn integer_widths_all_convert() {
236 assert_eq!(json!(1_i8), Value::Int(1));
237 assert_eq!(json!(1_u32), Value::Int(1));
238 assert_eq!(json!(-1_isize), Value::Int(-1));
239 assert_eq!(json!(1.5_f32), Value::Float(1.5));
240 }
241}