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