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] 54 macro_rules! json { 55 // Hide distracting implementation details from the generated rustdoc. 56 ($($json:tt)+) => { 57 $crate::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] 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 $crate::__private::vec![$($elems,)*] 81 }; 82 83 // Done without trailing comma. 84 (@array [$($elems:expr),*]) => { 85 $crate::__private::vec![$($elems),*] 86 }; 87 88 // Next element is `null`. 89 (@array [$($elems:expr,)*] null $($rest:tt)*) => { 90 $crate::json_internal!(@array [$($elems,)* $crate::json_internal!(null)] $($rest)*) 91 }; 92 93 // Next element is `true`. 94 (@array [$($elems:expr,)*] true $($rest:tt)*) => { 95 $crate::json_internal!(@array [$($elems,)* $crate::json_internal!(true)] $($rest)*) 96 }; 97 98 // Next element is `false`. 99 (@array [$($elems:expr,)*] false $($rest:tt)*) => { 100 $crate::json_internal!(@array [$($elems,)* $crate::json_internal!(false)] $($rest)*) 101 }; 102 103 // Next element is an array. 104 (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => { 105 $crate::json_internal!(@array [$($elems,)* $crate::json_internal!([$($array)*])] $($rest)*) 106 }; 107 108 // Next element is a map. 109 (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => { 110 $crate::json_internal!(@array [$($elems,)* $crate::json_internal!({$($map)*})] $($rest)*) 111 }; 112 113 // Next element is an expression followed by comma. 114 (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => { 115 $crate::json_internal!(@array [$($elems,)* $crate::json_internal!($next),] $($rest)*) 116 }; 117 118 // Last element is an expression with no trailing comma. 119 (@array [$($elems:expr,)*] $last:expr) => { 120 $crate::json_internal!(@array [$($elems,)* $crate::json_internal!($last)]) 121 }; 122 123 // Comma after the most recent element. 124 (@array [$($elems:expr),*] , $($rest:tt)*) => { 125 $crate::json_internal!(@array [$($elems,)*] $($rest)*) 126 }; 127 128 // Unexpected token after most recent element. 129 (@array [$($elems:expr),*] $unexpected:tt $($rest:tt)*) => { 130 $crate::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 $crate::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 $crate::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 $crate::json_internal!(@object $object [$($key)+] ($crate::json_internal!(null)) $($rest)*); 165 }; 166 167 // Next value is `true`. 168 (@object $object:ident ($($key:tt)+) (: true $($rest:tt)*) $copy:tt) => { 169 $crate::json_internal!(@object $object [$($key)+] ($crate::json_internal!(true)) $($rest)*); 170 }; 171 172 // Next value is `false`. 173 (@object $object:ident ($($key:tt)+) (: false $($rest:tt)*) $copy:tt) => { 174 $crate::json_internal!(@object $object [$($key)+] ($crate::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 $crate::json_internal!(@object $object [$($key)+] ($crate::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 $crate::json_internal!(@object $object [$($key)+] ($crate::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 $crate::json_internal!(@object $object [$($key)+] ($crate::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 $crate::json_internal!(@object $object [$($key)+] ($crate::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 $crate::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 $crate::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 $crate::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 $crate::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 $crate::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 $crate::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 $crate::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($crate::__private::vec![]) 258 }; 259 260 ([ $($tt:tt)+ ]) => { 261 $crate::Value::Array($crate::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 $crate::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 // Used by old versions of Rocket. 284 // Unused since https://github.com/rwf2/Rocket/commit/c74bcfd40a47b35330db6cafb88e4f3da83e0d17 285 #[macro_export] 286 #[doc(hidden)] 287 macro_rules! json_internal_vec { 288 ($($content:tt)*) => { 289 vec![$($content)*] 290 }; 291 } 292 293 #[macro_export] 294 #[doc(hidden)] 295 macro_rules! json_unexpected { 296 () => {}; 297 } 298 299 #[macro_export] 300 #[doc(hidden)] 301 macro_rules! json_expect_expr_comma { 302 ($e:expr , $($tt:tt)*) => {}; 303 } 304