@@ -234,6 +234,112 @@ macro_rules! json_internal {
234
234
json_internal!( @object $object ( $( $key) * $tt) ( $( $rest) * ) ( $( $rest) * ) ) ;
235
235
} ;
236
236
237
+
238
+ //////////////////////////////////////////////////////////////////////////
239
+ // TT muncher for counting the elements inside of an object {...}.
240
+ // Each entry is replaced with `$capacity += 1;`
241
+ //
242
+ // Must be invoked as: json_internal!(@object_capacity $capacity () ($($tt)*) ($($tt)*))
243
+ //
244
+ // We require two copies of the input tokens so that we can match on one
245
+ // copy and trigger errors on the other copy.
246
+ //////////////////////////////////////////////////////////////////////////
247
+
248
+ // Done.
249
+ ( @object_capacity $capacity: ident ( ) ( ) ( ) ) => { } ;
250
+
251
+ // Current entry followed by trailing comma.
252
+ ( @object_capacity $capacity: ident [ $( $key: tt) +] ( $value: expr) , $( $rest: tt) * ) => {
253
+ $capacity += 1 ;
254
+ json_internal!( @object_capacity $capacity ( ) ( $( $rest) * ) ( $( $rest) * ) ) ;
255
+ } ;
256
+
257
+ // Current entry followed by unexpected token.
258
+ ( @object_capacity $capacity: ident [ $( $key: tt) +] ( $value: expr) $unexpected: tt $( $rest: tt) * ) => {
259
+ json_unexpected!( $unexpected) ;
260
+ } ;
261
+
262
+ // Insert the last entry without trailing comma.
263
+ ( @object_capacity $capacity: ident [ $( $key: tt) +] ( $value: expr) ) => {
264
+ $capacity += 1 ;
265
+ } ;
266
+
267
+ // Next value is `null`.
268
+ ( @object_capacity $capacity: ident ( $( $key: tt) +) ( : null $( $rest: tt) * ) $copy: tt) => {
269
+ json_internal!( @object_capacity $capacity [ $( $key) +] ( json_internal!( null) ) $( $rest) * )
270
+ } ;
271
+
272
+ // Next value is `true`.
273
+ ( @object_capacity $capacity: ident ( $( $key: tt) +) ( : true $( $rest: tt) * ) $copy: tt) => {
274
+ json_internal!( @object_capacity $capacity [ $( $key) +] ( json_internal!( true ) ) $( $rest) * )
275
+ } ;
276
+
277
+ // Next value is `false`.
278
+ ( @object_capacity $capacity: ident ( $( $key: tt) +) ( : false $( $rest: tt) * ) $copy: tt) => {
279
+ json_internal!( @object_capacity $capacity [ $( $key) +] ( json_internal!( false ) ) $( $rest) * )
280
+ } ;
281
+
282
+ // Next value is an array.
283
+ ( @object_capacity $capacity: ident ( $( $key: tt) +) ( : [ $( $array: tt) * ] $( $rest: tt) * ) $copy: tt) => {
284
+ json_internal!( @object_capacity $capacity [ $( $key) +] ( json_internal!( [ $( $array) * ] ) ) $( $rest) * )
285
+ } ;
286
+
287
+ // Next value is a map.
288
+ ( @object_capacity $capacity: ident ( $( $key: tt) +) ( : { $( $map: tt) * } $( $rest: tt) * ) $copy: tt) => {
289
+ json_internal!( @object_capacity $capacity [ $( $key) +] ( json_internal!( { $( $map) * } ) ) $( $rest) * )
290
+ } ;
291
+
292
+ // Next value is an expression followed by comma.
293
+ ( @object_capacity $capacity: ident ( $( $key: tt) +) ( : $value: expr , $( $rest: tt) * ) $copy: tt) => {
294
+ json_internal!( @object_capacity $capacity [ $( $key) +] ( json_internal!( $value) ) , $( $rest) * )
295
+ } ;
296
+
297
+ // Last value is an expression with no trailing comma.
298
+ ( @object_capacity $capacity: ident ( $( $key: tt) +) ( : $value: expr) $copy: tt) => {
299
+ json_internal!( @object_capacity $capacity [ $( $key) +] ( json_internal!( $value) ) )
300
+ } ;
301
+
302
+ // Missing value for last entry. Trigger a reasonable error message.
303
+ ( @object_capacity $capacity: ident ( $( $key: tt) +) ( : ) $copy: tt) => {
304
+ // "unexpected end of macro invocation"
305
+ json_internal!( )
306
+ } ;
307
+
308
+ // Missing colon and value for last entry. Trigger a reasonable error
309
+ // message.
310
+ ( @object_capacity $capacity: ident ( $( $key: tt) +) ( ) $copy: tt) => {
311
+ // "unexpected end of macro invocation"
312
+ json_internal!( )
313
+ } ;
314
+
315
+ // Misplaced colon. Trigger a reasonable error message.
316
+ ( @object_capacity $capacity: ident ( ) ( : $( $rest: tt) * ) ( $colon: tt $( $copy: tt) * ) ) => {
317
+ // Takes no arguments so "no rules expected the token `:`".
318
+ json_unexpected!( $colon)
319
+ } ;
320
+
321
+ // Found a comma inside a key. Trigger a reasonable error message.
322
+ ( @object_capacity $capacity: ident ( $( $key: tt) * ) ( , $( $rest: tt) * ) ( $comma: tt $( $copy: tt) * ) ) => {
323
+ // Takes no arguments so "no rules expected the token `,`".
324
+ json_unexpected!( $comma)
325
+ } ;
326
+
327
+ // Key is fully parenthesized. This avoids clippy double_parens false
328
+ // positives because the parenthesization may be necessary here.
329
+ ( @object_capacity $capacity: ident ( ) ( ( $key: expr) : $( $rest: tt) * ) $copy: tt) => {
330
+ json_internal!( @object_capacity $capacity ( $key) ( : $( $rest) * ) ( : $( $rest) * ) )
331
+ } ;
332
+
333
+ // Refuse to absorb colon token into key expression.
334
+ ( @object_capacity $capacity: ident ( $( $key: tt) * ) ( : $( $unexpected: tt) +) $copy: tt) => {
335
+ json_expect_expr_comma!( $( $unexpected) +)
336
+ } ;
337
+
338
+ // Munch a token into the current key.
339
+ ( @object_capacity $capacity: ident ( $( $key: tt) * ) ( $tt: tt $( $rest: tt) * ) $copy: tt) => {
340
+ json_internal!( @object_capacity $capacity ( $( $key) * $tt) ( $( $rest) * ) ( $( $rest) * ) )
341
+ } ;
342
+
237
343
//////////////////////////////////////////////////////////////////////////
238
344
// The main implementation.
239
345
//
@@ -266,7 +372,9 @@ macro_rules! json_internal {
266
372
267
373
( { $( $tt: tt) + } ) => {
268
374
$crate:: Value :: Object ( {
269
- let mut object = $crate:: Map :: new( ) ;
375
+ let mut capacity = 0 ;
376
+ json_internal!( @object_capacity capacity ( ) ( $( $tt) +) ( $( $tt) +) ) ;
377
+ let mut object = $crate:: Map :: with_capacity( capacity) ;
270
378
json_internal!( @object object ( ) ( $( $tt) +) ( $( $tt) +) ) ;
271
379
object
272
380
} )
0 commit comments