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 /// } 15 /// }); 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 /// 25 /// ``` 26 /// # use serde_json::json; 27 /// # 28 /// let code = 200; 29 /// let features = vec!["serde", "json"]; 30 /// 31 /// let value = json!({ 32 /// "code": code, 33 /// "success": code == 200, 34 /// "payload": { 35 /// features[0]: features[1] 36 /// } 37 /// }); 38 /// ``` 39 /// 40 /// Trailing commas are allowed inside both arrays and objects. 41 /// 42 /// ``` 43 /// # use serde_json::json; 44 /// # 45 /// let value = json!([ 46 /// "notice", 47 /// "the", 48 /// "trailing", 49 /// "comma -->", 50 /// ]); 51 /// ``` 52 #[macro_export(local_inner_macros)] 53 macro_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)+)`. 67 #[macro_export(local_inner_macros)] 68 #[doc(hidden)] 69 macro_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,)*]) => { 79 json_internal_vec![$($elems,)*] 80 }; 81 82 // Done without trailing comma. 83 (@array [$($elems:expr),*]) => { 84 json_internal_vec![$($elems),*] 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 127 // Unexpected token after most recent element. 128 (@array [$($elems:expr),*] $unexpected:tt $($rest:tt)*) => { 129 json_unexpected!($unexpected) 130 }; 131 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)*) => { 147 let _ = $object.insert(($($key)+).into(), $value); 148 json_internal!(@object $object () ($($rest)*) ($($rest)*)); 149 }; 150 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 156 // Insert the last entry without trailing comma. 157 (@object $object:ident [$($key:tt)+] ($value:expr)) => { 158 let _ = $object.insert(($($key)+).into(), $value); 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 `:`". 212 json_unexpected!($colon); 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 `,`". 218 json_unexpected!($comma); 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 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 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 ([]) => { 256 $crate::Value::Array(json_internal_vec![]) 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) => { 278 $crate::to_value(&$other).unwrap() 279 }; 280 } 281 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)] 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