@@ -445,6 +445,45 @@ pub fn deserialize_with_unknowns_derive(input: TokenStream) -> TokenStream {
445
445
use :: alloc:: string:: ToString ;
446
446
if base_path. is_empty( ) { [ "[" , & index. to_string( ) , "]" ] . concat( ) } else { [ base_path, "[" , & index. to_string( ) , "]" ] . concat( ) }
447
447
}
448
+ // Records unknowns for mismatched shapes by enumerating immediate children.
449
+ fn record_mismatch_unknowns(
450
+ input_json: & :: serde_json:: Value ,
451
+ base_path: & str ,
452
+ out_paths: & mut :: alloc:: vec:: Vec <:: alloc:: string:: String >,
453
+ ) {
454
+ use :: serde_json:: Value :: * ;
455
+ match input_json {
456
+ Object ( map) => {
457
+ for ( k, v) in map. iter( ) {
458
+ if !v. is_null( ) {
459
+ out_paths. push( join_path( base_path, k) ) ;
460
+ }
461
+ }
462
+ } ,
463
+ Array ( arr) => {
464
+ for ( idx, v) in arr. iter( ) . enumerate( ) {
465
+ if !v. is_null( ) {
466
+ out_paths. push( index_path( base_path, idx) ) ;
467
+ }
468
+ }
469
+ } ,
470
+ _ => { /* No-op */ }
471
+ }
472
+ }
473
+
474
+ // Marks extra non-null input array elements beyond recognized length as unknown.
475
+ fn record_extra_array_items(
476
+ input_array: & :: alloc:: vec:: Vec <:: serde_json:: Value >,
477
+ recognized_len: usize ,
478
+ base_path: & str ,
479
+ out_paths: & mut :: alloc:: vec:: Vec <:: alloc:: string:: String >,
480
+ ) {
481
+ for idx in recognized_len..input_array. len( ) {
482
+ if !input_array[ idx] . is_null( ) {
483
+ out_paths. push( index_path( base_path, idx) ) ;
484
+ }
485
+ }
486
+ }
448
487
// Recursively walk input vs recognized JSON and collect unknown field paths.
449
488
fn collect_unknown_paths(
450
489
input_json: & :: serde_json:: Value ,
@@ -463,29 +502,30 @@ pub fn deserialize_with_unknowns_derive(input: TokenStream) -> TokenStream {
463
502
out_paths. push( join_path( base_path, key) ) ;
464
503
}
465
504
} ,
466
- // Key known. Recurse based on the value shape.
467
- Some ( recognized_value) => match ( input_value, recognized_value) {
468
- ( Object ( _) , Object ( _) ) => collect_unknown_paths(
469
- input_value,
470
- recognized_value,
471
- & join_path( base_path, key) ,
472
- out_paths,
473
- ) ,
474
- ( Array ( input_array) , Array ( recognized_array) ) => {
475
- for ( idx, ( input_elem, recognized_elem) ) in input_array
476
- . iter( )
477
- . zip( recognized_array. iter( ) )
478
- . enumerate( )
479
- {
480
- collect_unknown_paths(
481
- input_elem,
482
- recognized_elem,
483
- & index_path( & join_path( base_path, key) , idx) ,
484
- out_paths,
485
- ) ;
486
- }
487
- } ,
488
- _ => { /* No-op */ }
505
+ // Key known. Recurse or record mismatch.
506
+ Some ( recognized_value) => {
507
+ let child_base = join_path( base_path, key) ;
508
+ match ( input_value, recognized_value) {
509
+ ( Object ( _) , Object ( _) ) => collect_unknown_paths(
510
+ input_value, recognized_value, & child_base, out_paths,
511
+ ) ,
512
+ ( Array ( input_array) , Array ( recognized_array) ) => {
513
+ for ( idx, ( input_elem, recognized_elem) ) in input_array
514
+ . iter( )
515
+ . zip( recognized_array. iter( ) )
516
+ . enumerate( )
517
+ {
518
+ collect_unknown_paths(
519
+ input_elem,
520
+ recognized_elem,
521
+ & index_path( & child_base, idx) ,
522
+ out_paths,
523
+ ) ;
524
+ }
525
+ record_extra_array_items( input_array, recognized_array. len( ) , & child_base, out_paths) ;
526
+ } ,
527
+ _ => record_mismatch_unknowns( input_value, & child_base, out_paths) ,
528
+ }
489
529
}
490
530
}
491
531
}
@@ -503,8 +543,17 @@ pub fn deserialize_with_unknowns_derive(input: TokenStream) -> TokenStream {
503
543
out_paths,
504
544
) ;
505
545
}
546
+ // If the input array is longer than the recognized array,
547
+ // mark the extra elements as unknown.
548
+ if input_array. len( ) > recognized_array. len( ) {
549
+ for idx in recognized_array. len( ) ..input_array. len( ) {
550
+ if !input_array[ idx] . is_null( ) {
551
+ out_paths. push( index_path( base_path, idx) ) ;
552
+ }
553
+ }
554
+ }
506
555
} ,
507
- _ => { /* No-op */ }
556
+ _ => record_mismatch_unknowns ( input_json , base_path , out_paths ) ,
508
557
}
509
558
}
510
559
0 commit comments