19
19
// See the License for the specific language governing permissions and
20
20
// limitations under the License.
21
21
22
+ use std:: collections:: HashMap ;
22
23
use std:: fmt:: { self , Display , Formatter } ;
23
24
use std:: str:: FromStr ;
24
25
@@ -374,13 +375,37 @@ pub enum ImplInconsistency {
374
375
375
376
/// implementation references unknown interface error '{0}'.
376
377
IfaceErrorAbsent ( VariantName ) ,
378
+
379
+ /// metadata field '{0}' is repeated {1} times
380
+ RepeatedMetaData ( FieldName , i32 ) ,
381
+
382
+ /// global state field '{0}' is repeated {1} times
383
+ RepeatedGlobalState ( FieldName , i32 ) ,
384
+
385
+ /// assignments field '{0}' is repeated {1} times
386
+ RepeatedAssignments ( FieldName , i32 ) ,
387
+
388
+ /// valencies field '{0}' is repeated {1} times
389
+ RepeatedValencies ( FieldName , i32 ) ,
390
+
391
+ /// transition field '{0}' is repeated {1} times
392
+ RepeatedTransitions ( FieldName , i32 ) ,
393
+
394
+ /// extension field '{0}' is repeated {1} times
395
+ RepeatedExtensions ( FieldName , i32 ) ,
377
396
}
378
397
379
398
impl IfaceImpl {
380
399
pub fn check ( & self , iface : & Iface , schema : & Schema ) -> Result < ( ) , Vec < ImplInconsistency > > {
381
400
let mut errors = vec ! [ ] ;
382
-
383
401
let now = Utc :: now ( ) ;
402
+ let mut dup_metadata = HashMap :: new ( ) ;
403
+ let mut dup_global_state = HashMap :: new ( ) ;
404
+ let mut dup_assignments = HashMap :: new ( ) ;
405
+ let mut dup_valencies = HashMap :: new ( ) ;
406
+ let mut dup_transitions = HashMap :: new ( ) ;
407
+ let mut dup_extensions = HashMap :: new ( ) ;
408
+
384
409
match Utc . timestamp_opt ( self . timestamp , 0 ) . single ( ) {
385
410
Some ( ts) if ts > now => errors. push ( ImplInconsistency :: FutureTimestamp ( ts) ) ,
386
411
None => errors. push ( ImplInconsistency :: InvalidTimestamp ( self . timestamp ) ) ,
@@ -393,76 +418,142 @@ impl IfaceImpl {
393
418
}
394
419
}
395
420
for field in & self . metadata {
421
+ dup_metadata
422
+ . entry ( field. name . clone ( ) )
423
+ . and_modify ( |counter| * counter += 1 )
424
+ . or_insert ( 0 ) ;
396
425
if !schema. meta_types . contains_key ( & field. id ) {
397
426
errors. push ( ImplInconsistency :: SchemaMetaAbsent ( field. name . clone ( ) , field. id ) ) ;
398
427
}
399
428
}
400
429
430
+ dup_metadata
431
+ . iter ( )
432
+ . filter ( |( _, & count) | count > 1 )
433
+ . for_each ( |( field_name, & count) | {
434
+ errors. push ( ImplInconsistency :: RepeatedMetaData ( field_name. clone ( ) , count) ) ;
435
+ } ) ;
436
+
401
437
for name in iface. global_state . keys ( ) {
402
438
if self . global_state . iter ( ) . all ( |field| & field. name != name) {
403
439
errors. push ( ImplInconsistency :: IfaceGlobalAbsent ( name. clone ( ) ) ) ;
404
440
}
405
441
}
406
442
for field in & self . global_state {
443
+ dup_global_state
444
+ . entry ( field. name . clone ( ) )
445
+ . and_modify ( |counter| * counter += 1 )
446
+ . or_insert ( 0 ) ;
407
447
if !schema. global_types . contains_key ( & field. id ) {
408
448
errors. push ( ImplInconsistency :: SchemaGlobalAbsent ( field. name . clone ( ) , field. id ) ) ;
409
449
}
410
450
}
411
451
452
+ dup_global_state
453
+ . iter ( )
454
+ . filter ( |( _, & count) | count > 1 )
455
+ . for_each ( |( field_name, & count) | {
456
+ errors. push ( ImplInconsistency :: RepeatedGlobalState ( field_name. clone ( ) , count) ) ;
457
+ } ) ;
458
+
412
459
for name in iface. assignments . keys ( ) {
413
460
if self . assignments . iter ( ) . all ( |field| & field. name != name) {
414
461
errors. push ( ImplInconsistency :: IfaceAssignmentAbsent ( name. clone ( ) ) ) ;
415
462
}
416
463
}
417
464
for field in & self . assignments {
465
+ dup_assignments
466
+ . entry ( field. name . clone ( ) )
467
+ . and_modify ( |counter| * counter += 1 )
468
+ . or_insert ( 0 ) ;
418
469
if !schema. owned_types . contains_key ( & field. id ) {
419
470
errors
420
471
. push ( ImplInconsistency :: SchemaAssignmentAbsent ( field. name . clone ( ) , field. id ) ) ;
421
472
}
422
473
}
423
474
475
+ dup_assignments
476
+ . iter ( )
477
+ . filter ( |( _, & count) | count > 1 )
478
+ . for_each ( |( field_name, & count) | {
479
+ errors. push ( ImplInconsistency :: RepeatedAssignments ( field_name. clone ( ) , count) ) ;
480
+ } ) ;
481
+
424
482
for name in iface. valencies . keys ( ) {
425
483
if self . valencies . iter ( ) . all ( |field| & field. name != name) {
426
484
errors. push ( ImplInconsistency :: IfaceValencyAbsent ( name. clone ( ) ) ) ;
427
485
}
428
486
}
429
487
for field in & self . valencies {
488
+ dup_valencies
489
+ . entry ( field. name . clone ( ) )
490
+ . and_modify ( |counter| * counter += 1 )
491
+ . or_insert ( 0 ) ;
492
+
430
493
if !schema. valency_types . contains ( & field. id ) {
431
494
errors. push ( ImplInconsistency :: SchemaValencyAbsent ( field. name . clone ( ) , field. id ) ) ;
432
495
}
433
496
}
497
+ dup_valencies
498
+ . iter ( )
499
+ . filter ( |( _, & count) | count > 1 )
500
+ . for_each ( |( field_name, & count) | {
501
+ errors. push ( ImplInconsistency :: RepeatedValencies ( field_name. clone ( ) , count) ) ;
502
+ } ) ;
434
503
435
504
for name in iface. transitions . keys ( ) {
436
505
if self . transitions . iter ( ) . all ( |field| & field. name != name) {
437
506
errors. push ( ImplInconsistency :: IfaceTransitionAbsent ( name. clone ( ) ) ) ;
438
507
}
439
508
}
440
509
for field in & self . transitions {
510
+ dup_transitions
511
+ . entry ( field. name . clone ( ) )
512
+ . and_modify ( |counter| * counter += 1 )
513
+ . or_insert ( 0 ) ;
514
+
441
515
if !schema. transitions . contains_key ( & field. id ) {
442
516
errors
443
517
. push ( ImplInconsistency :: SchemaTransitionAbsent ( field. name . clone ( ) , field. id ) ) ;
444
518
}
445
519
}
446
520
521
+ dup_transitions
522
+ . iter ( )
523
+ . filter ( |( _, & count) | count > 1 )
524
+ . for_each ( |( field_name, & count) | {
525
+ errors. push ( ImplInconsistency :: RepeatedTransitions ( field_name. clone ( ) , count) ) ;
526
+ } ) ;
527
+
447
528
for name in iface. extensions . keys ( ) {
448
529
if self . extensions . iter ( ) . all ( |field| & field. name != name) {
449
530
errors. push ( ImplInconsistency :: IfaceExtensionAbsent ( name. clone ( ) ) ) ;
450
531
}
451
532
}
452
533
for field in & self . extensions {
534
+ dup_extensions
535
+ . entry ( field. name . clone ( ) )
536
+ . and_modify ( |counter| * counter += 1 )
537
+ . or_insert ( 0 ) ;
538
+
453
539
if !schema. extensions . contains_key ( & field. id ) {
454
540
errors. push ( ImplInconsistency :: SchemaExtensionAbsent ( field. name . clone ( ) , field. id ) ) ;
455
541
}
456
542
}
457
543
544
+ dup_extensions
545
+ . iter ( )
546
+ . filter ( |( _, & count) | count > 1 )
547
+ . for_each ( |( field_name, & count) | {
548
+ errors. push ( ImplInconsistency :: RepeatedExtensions ( field_name. clone ( ) , count) ) ;
549
+ } ) ;
550
+
458
551
for var in & self . errors {
459
552
if iface. errors . keys ( ) . all ( |name| name != & var. name ) {
460
553
errors. push ( ImplInconsistency :: IfaceErrorAbsent ( var. name . clone ( ) ) ) ;
461
554
}
462
555
}
463
556
464
- // TODO: Warn about repeated field names
465
-
466
557
if errors. is_empty ( ) {
467
558
Ok ( ( ) )
468
559
} else {
0 commit comments