@@ -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 `1 + ` (or `1` if it is the last element).
241
+ // 0 is inserted if the object has a trailing comma.
242
+ //
243
+ // Must be invoked as: json_internal!(@object_capacity () ($($tt)*) ($($tt)*))
244
+ //
245
+ // We require two copies of the input tokens so that we can match on one
246
+ // copy and trigger errors on the other copy.
247
+ //////////////////////////////////////////////////////////////////////////
248
+
249
+ // Done.
250
+ ( @object_capacity ( ) ( ) ( ) ) => { 0 } ;
251
+
252
+ // Current entry followed by trailing comma.
253
+ ( @object_capacity entry , $( $rest: tt) * ) => {
254
+ 1 + json_internal!( @object_capacity ( ) ( $( $rest) * ) ( $( $rest) * ) )
255
+ } ;
256
+
257
+ // Current entry followed by unexpected token.
258
+ ( @object_capacity entry $unexpected: tt $( $rest: tt) * ) => {
259
+ json_unexpected!( $unexpected)
260
+ } ;
261
+
262
+ // Insert the last entry without trailing comma.
263
+ ( @object_capacity entry) => {
264
+ 1
265
+ } ;
266
+
267
+ // Next value is `null`.
268
+ ( @object_capacity ( $( $key: tt) +) ( : null $( $rest: tt) * ) $copy: tt) => {
269
+ json_internal!( @object_capacity entry $( $rest) * )
270
+ } ;
271
+
272
+ // Next value is `true`.
273
+ ( @object_capacity ( $( $key: tt) +) ( : true $( $rest: tt) * ) $copy: tt) => {
274
+ json_internal!( @object_capacity entry $( $rest) * )
275
+ } ;
276
+
277
+ // Next value is `false`.
278
+ ( @object_capacity ( $( $key: tt) +) ( : false $( $rest: tt) * ) $copy: tt) => {
279
+ json_internal!( @object_capacity entry $( $rest) * )
280
+ } ;
281
+
282
+ // Next value is an array.
283
+ ( @object_capacity ( $( $key: tt) +) ( : [ $( $array: tt) * ] $( $rest: tt) * ) $copy: tt) => {
284
+ json_internal!( @object_capacity entry $( $rest) * )
285
+ } ;
286
+
287
+ // Next value is a map.
288
+ ( @object_capacity ( $( $key: tt) +) ( : { $( $map: tt) * } $( $rest: tt) * ) $copy: tt) => {
289
+ json_internal!( @object_capacity entry $( $rest) * )
290
+ } ;
291
+
292
+ // Next value is an expression followed by comma.
293
+ ( @object_capacity ( $( $key: tt) +) ( : $value: expr , $( $rest: tt) * ) $copy: tt) => {
294
+ json_internal!( @object_capacity entry , $( $rest) * )
295
+ } ;
296
+
297
+ // Last value is an expression with no trailing comma.
298
+ ( @object_capacity ( $( $key: tt) +) ( : $value: expr) $copy: tt) => {
299
+ json_internal!( @object_capacity entry)
300
+ } ;
301
+
302
+ // Missing value for last entry. Trigger a reasonable error message.
303
+ ( @object_capacity ( $( $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 ( $( $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 ( ) ( : $( $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 ( $( $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 is not necessary for counting capacity
328
+ // since we don't evaluate $key anyway, so just use the munching below.
329
+ // (@object_capacity () (($key:expr) : $($rest:tt)*) $copy:tt) => {
330
+ // json_internal!(@object_capacity ($key) (: $($rest)*) (: $($rest)*))
331
+ // };
332
+
333
+ // Refuse to absorb colon token into key expression.
334
+ ( @object_capacity ( $( $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 ( $( $key: tt) * ) ( $tt: tt $( $rest: tt) * ) $copy: tt) => {
340
+ json_internal!( @object_capacity ( $( $key) * $tt) ( $( $rest) * ) ( $( $rest) * ) )
341
+ } ;
342
+
237
343
//////////////////////////////////////////////////////////////////////////
238
344
// The main implementation.
239
345
//
@@ -266,7 +372,8 @@ macro_rules! json_internal {
266
372
267
373
( { $( $tt: tt) + } ) => {
268
374
$crate:: Value :: Object ( {
269
- let mut object = $crate:: Map :: new( ) ;
375
+ let capacity = json_internal!( @object_capacity ( ) ( $( $tt) +) ( $( $tt) +) ) ;
376
+ let mut object = $crate:: Map :: with_capacity( capacity) ;
270
377
json_internal!( @object object ( ) ( $( $tt) +) ( $( $tt) +) ) ;
271
378
object
272
379
} )
0 commit comments