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