1 | /// Construct a `serde_json::Value` from a JSON literal. |
2 | /// |
3 | /// ``` |
4 | /// # use serde_json::json; |
5 | /// # |
6 | /// let value = json!({ |
7 | /// "code" : 200, |
8 | /// "success" : true, |
9 | /// "payload" : { |
10 | /// "features" : [ |
11 | /// "serde" , |
12 | /// "json" |
13 | /// ], |
14 | /// "homepage" : null |
15 | /// } |
16 | /// }); |
17 | /// ``` |
18 | /// |
19 | /// Variables or expressions can be interpolated into the JSON literal. Any type |
20 | /// interpolated into an array element or object value must implement Serde's |
21 | /// `Serialize` trait, while any type interpolated into a object key must |
22 | /// implement `Into<String>`. If the `Serialize` implementation of the |
23 | /// interpolated type decides to fail, or if the interpolated type contains a |
24 | /// map with non-string keys, the `json!` macro will panic. |
25 | /// |
26 | /// ``` |
27 | /// # use serde_json::json; |
28 | /// # |
29 | /// let code = 200; |
30 | /// let features = vec!["serde" , "json" ]; |
31 | /// |
32 | /// let value = json!({ |
33 | /// "code" : code, |
34 | /// "success" : code == 200, |
35 | /// "payload" : { |
36 | /// features[0]: features[1] |
37 | /// } |
38 | /// }); |
39 | /// ``` |
40 | /// |
41 | /// Trailing commas are allowed inside both arrays and objects. |
42 | /// |
43 | /// ``` |
44 | /// # use serde_json::json; |
45 | /// # |
46 | /// let value = json!([ |
47 | /// "notice" , |
48 | /// "the" , |
49 | /// "trailing" , |
50 | /// "comma -->" , |
51 | /// ]); |
52 | /// ``` |
53 | #[macro_export (local_inner_macros)] |
54 | macro_rules! json { |
55 | // Hide distracting implementation details from the generated rustdoc. |
56 | ($($json:tt)+) => { |
57 | json_internal!($($json)+) |
58 | }; |
59 | } |
60 | |
61 | // Rocket relies on this because they export their own `json!` with a different |
62 | // doc comment than ours, and various Rust bugs prevent them from calling our |
63 | // `json!` from their `json!` so they call `json_internal!` directly. Check with |
64 | // @SergioBenitez before making breaking changes to this macro. |
65 | // |
66 | // Changes are fine as long as `json_internal!` does not call any new helper |
67 | // macros and can still be invoked as `json_internal!($($json)+)`. |
68 | #[macro_export (local_inner_macros)] |
69 | #[doc (hidden)] |
70 | macro_rules! json_internal { |
71 | ////////////////////////////////////////////////////////////////////////// |
72 | // TT muncher for parsing the inside of an array [...]. Produces a vec![...] |
73 | // of the elements. |
74 | // |
75 | // Must be invoked as: json_internal!(@array [] $($tt)*) |
76 | ////////////////////////////////////////////////////////////////////////// |
77 | |
78 | // Done with trailing comma. |
79 | (@array [$($elems:expr,)*]) => { |
80 | json_internal_vec![$($elems,)*] |
81 | }; |
82 | |
83 | // Done without trailing comma. |
84 | (@array [$($elems:expr),*]) => { |
85 | json_internal_vec![$($elems),*] |
86 | }; |
87 | |
88 | // Next element is `null`. |
89 | (@array [$($elems:expr,)*] null $($rest:tt)*) => { |
90 | json_internal!(@array [$($elems,)* json_internal!(null)] $($rest)*) |
91 | }; |
92 | |
93 | // Next element is `true`. |
94 | (@array [$($elems:expr,)*] true $($rest:tt)*) => { |
95 | json_internal!(@array [$($elems,)* json_internal!(true)] $($rest)*) |
96 | }; |
97 | |
98 | // Next element is `false`. |
99 | (@array [$($elems:expr,)*] false $($rest:tt)*) => { |
100 | json_internal!(@array [$($elems,)* json_internal!(false)] $($rest)*) |
101 | }; |
102 | |
103 | // Next element is an array. |
104 | (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => { |
105 | json_internal!(@array [$($elems,)* json_internal!([$($array)*])] $($rest)*) |
106 | }; |
107 | |
108 | // Next element is a map. |
109 | (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => { |
110 | json_internal!(@array [$($elems,)* json_internal!({$($map)*})] $($rest)*) |
111 | }; |
112 | |
113 | // Next element is an expression followed by comma. |
114 | (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => { |
115 | json_internal!(@array [$($elems,)* json_internal!($next),] $($rest)*) |
116 | }; |
117 | |
118 | // Last element is an expression with no trailing comma. |
119 | (@array [$($elems:expr,)*] $last:expr) => { |
120 | json_internal!(@array [$($elems,)* json_internal!($last)]) |
121 | }; |
122 | |
123 | // Comma after the most recent element. |
124 | (@array [$($elems:expr),*] , $($rest:tt)*) => { |
125 | json_internal!(@array [$($elems,)*] $($rest)*) |
126 | }; |
127 | |
128 | // Unexpected token after most recent element. |
129 | (@array [$($elems:expr),*] $unexpected:tt $($rest:tt)*) => { |
130 | json_unexpected!($unexpected) |
131 | }; |
132 | |
133 | ////////////////////////////////////////////////////////////////////////// |
134 | // TT muncher for parsing the inside of an object {...}. Each entry is |
135 | // inserted into the given map variable. |
136 | // |
137 | // Must be invoked as: json_internal!(@object $map () ($($tt)*) ($($tt)*)) |
138 | // |
139 | // We require two copies of the input tokens so that we can match on one |
140 | // copy and trigger errors on the other copy. |
141 | ////////////////////////////////////////////////////////////////////////// |
142 | |
143 | // Done. |
144 | (@object $object:ident () () ()) => {}; |
145 | |
146 | // Insert the current entry followed by trailing comma. |
147 | (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => { |
148 | let _ = $object.insert(($($key)+).into(), $value); |
149 | json_internal!(@object $object () ($($rest)*) ($($rest)*)); |
150 | }; |
151 | |
152 | // Current entry followed by unexpected token. |
153 | (@object $object:ident [$($key:tt)+] ($value:expr) $unexpected:tt $($rest:tt)*) => { |
154 | json_unexpected!($unexpected); |
155 | }; |
156 | |
157 | // Insert the last entry without trailing comma. |
158 | (@object $object:ident [$($key:tt)+] ($value:expr)) => { |
159 | let _ = $object.insert(($($key)+).into(), $value); |
160 | }; |
161 | |
162 | // Next value is `null`. |
163 | (@object $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => { |
164 | json_internal!(@object $object [$($key)+] (json_internal!(null)) $($rest)*); |
165 | }; |
166 | |
167 | // Next value is `true`. |
168 | (@object $object:ident ($($key:tt)+) (: true $($rest:tt)*) $copy:tt) => { |
169 | json_internal!(@object $object [$($key)+] (json_internal!(true)) $($rest)*); |
170 | }; |
171 | |
172 | // Next value is `false`. |
173 | (@object $object:ident ($($key:tt)+) (: false $($rest:tt)*) $copy:tt) => { |
174 | json_internal!(@object $object [$($key)+] (json_internal!(false)) $($rest)*); |
175 | }; |
176 | |
177 | // Next value is an array. |
178 | (@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => { |
179 | json_internal!(@object $object [$($key)+] (json_internal!([$($array)*])) $($rest)*); |
180 | }; |
181 | |
182 | // Next value is a map. |
183 | (@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => { |
184 | json_internal!(@object $object [$($key)+] (json_internal!({$($map)*})) $($rest)*); |
185 | }; |
186 | |
187 | // Next value is an expression followed by comma. |
188 | (@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => { |
189 | json_internal!(@object $object [$($key)+] (json_internal!($value)) , $($rest)*); |
190 | }; |
191 | |
192 | // Last value is an expression with no trailing comma. |
193 | (@object $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => { |
194 | json_internal!(@object $object [$($key)+] (json_internal!($value))); |
195 | }; |
196 | |
197 | // Missing value for last entry. Trigger a reasonable error message. |
198 | (@object $object:ident ($($key:tt)+) (:) $copy:tt) => { |
199 | // "unexpected end of macro invocation" |
200 | json_internal!(); |
201 | }; |
202 | |
203 | // Missing colon and value for last entry. Trigger a reasonable error |
204 | // message. |
205 | (@object $object:ident ($($key:tt)+) () $copy:tt) => { |
206 | // "unexpected end of macro invocation" |
207 | json_internal!(); |
208 | }; |
209 | |
210 | // Misplaced colon. Trigger a reasonable error message. |
211 | (@object $object:ident () (: $($rest:tt)*) ($colon:tt $($copy:tt)*)) => { |
212 | // Takes no arguments so "no rules expected the token `:`". |
213 | json_unexpected!($colon); |
214 | }; |
215 | |
216 | // Found a comma inside a key. Trigger a reasonable error message. |
217 | (@object $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => { |
218 | // Takes no arguments so "no rules expected the token `,`". |
219 | json_unexpected!($comma); |
220 | }; |
221 | |
222 | // Key is fully parenthesized. This avoids clippy double_parens false |
223 | // positives because the parenthesization may be necessary here. |
224 | (@object $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => { |
225 | json_internal!(@object $object ($key) (: $($rest)*) (: $($rest)*)); |
226 | }; |
227 | |
228 | // Refuse to absorb colon token into key expression. |
229 | (@object $object:ident ($($key:tt)*) (: $($unexpected:tt)+) $copy:tt) => { |
230 | json_expect_expr_comma!($($unexpected)+); |
231 | }; |
232 | |
233 | // Munch a token into the current key. |
234 | (@object $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => { |
235 | json_internal!(@object $object ($($key)* $tt) ($($rest)*) ($($rest)*)); |
236 | }; |
237 | |
238 | ////////////////////////////////////////////////////////////////////////// |
239 | // The main implementation. |
240 | // |
241 | // Must be invoked as: json_internal!($($json)+) |
242 | ////////////////////////////////////////////////////////////////////////// |
243 | |
244 | (null) => { |
245 | $crate::Value::Null |
246 | }; |
247 | |
248 | (true) => { |
249 | $crate::Value::Bool(true) |
250 | }; |
251 | |
252 | (false) => { |
253 | $crate::Value::Bool(false) |
254 | }; |
255 | |
256 | ([]) => { |
257 | $crate::Value::Array(json_internal_vec![]) |
258 | }; |
259 | |
260 | ([ $($tt:tt)+ ]) => { |
261 | $crate::Value::Array(json_internal!(@array [] $($tt)+)) |
262 | }; |
263 | |
264 | ({}) => { |
265 | $crate::Value::Object($crate::Map::new()) |
266 | }; |
267 | |
268 | ({ $($tt:tt)+ }) => { |
269 | $crate::Value::Object({ |
270 | let mut object = $crate::Map::new(); |
271 | json_internal!(@object object () ($($tt)+) ($($tt)+)); |
272 | object |
273 | }) |
274 | }; |
275 | |
276 | // Any Serialize type: numbers, strings, struct literals, variables etc. |
277 | // Must be below every other rule. |
278 | ($other:expr) => { |
279 | $crate::to_value(&$other).unwrap() |
280 | }; |
281 | } |
282 | |
283 | // The json_internal macro above cannot invoke vec directly because it uses |
284 | // local_inner_macros. A vec invocation there would resolve to $crate::vec. |
285 | // Instead invoke vec here outside of local_inner_macros. |
286 | #[macro_export ] |
287 | #[doc (hidden)] |
288 | macro_rules! json_internal_vec { |
289 | ($($content:tt)*) => { |
290 | vec![$($content)*] |
291 | }; |
292 | } |
293 | |
294 | #[macro_export ] |
295 | #[doc (hidden)] |
296 | macro_rules! json_unexpected { |
297 | () => {}; |
298 | } |
299 | |
300 | #[macro_export ] |
301 | #[doc (hidden)] |
302 | macro_rules! json_expect_expr_comma { |
303 | ($e:expr , $($tt:tt)*) => {}; |
304 | } |
305 | |