@@ -21,6 +21,7 @@ pub(crate) fn gen_trait_fn_body(
21
21
"Default" => gen_default_impl ( adt, func) ,
22
22
"Hash" => gen_hash_impl ( adt, func) ,
23
23
"PartialEq" => gen_partial_eq ( adt, func) ,
24
+ "PartialOrd" => gen_partial_ord ( adt, func) ,
24
25
_ => None ,
25
26
}
26
27
}
@@ -572,6 +573,171 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
572
573
Some ( ( ) )
573
574
}
574
575
576
+ fn gen_partial_ord ( adt : & ast:: Adt , func : & ast:: Fn ) -> Option < ( ) > {
577
+ fn gen_eq_chain ( expr : Option < ast:: Expr > , cmp : ast:: Expr ) -> Option < ast:: Expr > {
578
+ match expr {
579
+ Some ( expr) => Some ( make:: expr_op ( ast:: BinOp :: BooleanAnd , expr, cmp) ) ,
580
+ None => Some ( cmp) ,
581
+ }
582
+ }
583
+
584
+ fn gen_record_pat_field ( field_name : & str , pat_name : & str ) -> ast:: RecordPatField {
585
+ let pat = make:: ext:: simple_ident_pat ( make:: name ( & pat_name) ) ;
586
+ let name_ref = make:: name_ref ( field_name) ;
587
+ make:: record_pat_field ( name_ref, pat. into ( ) )
588
+ }
589
+
590
+ fn gen_record_pat ( record_name : ast:: Path , fields : Vec < ast:: RecordPatField > ) -> ast:: RecordPat {
591
+ let list = make:: record_pat_field_list ( fields) ;
592
+ make:: record_pat_with_fields ( record_name, list)
593
+ }
594
+
595
+ fn gen_variant_path ( variant : & ast:: Variant ) -> Option < ast:: Path > {
596
+ make:: ext:: path_from_idents ( [ "Self" , & variant. name ( ) ?. to_string ( ) ] )
597
+ }
598
+
599
+ fn gen_tuple_field ( field_name : & String ) -> ast:: Pat {
600
+ ast:: Pat :: IdentPat ( make:: ident_pat ( false , false , make:: name ( field_name) ) )
601
+ }
602
+
603
+ // FIXME: return `None` if the trait carries a generic type; we can only
604
+ // generate this code `Self` for the time being.
605
+
606
+ let body = match adt {
607
+ // `Hash` cannot be derived for unions, so no default impl can be provided.
608
+ ast:: Adt :: Union ( _) => return None ,
609
+
610
+ ast:: Adt :: Enum ( enum_) => {
611
+ // => std::mem::discriminant(self) == std::mem::discriminant(other)
612
+ let lhs_name = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
613
+ let lhs = make:: expr_call ( make_discriminant ( ) ?, make:: arg_list ( Some ( lhs_name. clone ( ) ) ) ) ;
614
+ let rhs_name = make:: expr_path ( make:: ext:: ident_path ( "other" ) ) ;
615
+ let rhs = make:: expr_call ( make_discriminant ( ) ?, make:: arg_list ( Some ( rhs_name. clone ( ) ) ) ) ;
616
+ let eq_check = make:: expr_op ( ast:: BinOp :: EqualityTest , lhs, rhs) ;
617
+
618
+ let mut case_count = 0 ;
619
+ let mut arms = vec ! [ ] ;
620
+ for variant in enum_. variant_list ( ) ?. variants ( ) {
621
+ case_count += 1 ;
622
+ match variant. field_list ( ) {
623
+ // => (Self::Bar { bin: l_bin }, Self::Bar { bin: r_bin }) => l_bin == r_bin,
624
+ Some ( ast:: FieldList :: RecordFieldList ( list) ) => {
625
+ let mut expr = None ;
626
+ let mut l_fields = vec ! [ ] ;
627
+ let mut r_fields = vec ! [ ] ;
628
+
629
+ for field in list. fields ( ) {
630
+ let field_name = field. name ( ) ?. to_string ( ) ;
631
+
632
+ let l_name = & format ! ( "l_{}" , field_name) ;
633
+ l_fields. push ( gen_record_pat_field ( & field_name, & l_name) ) ;
634
+
635
+ let r_name = & format ! ( "r_{}" , field_name) ;
636
+ r_fields. push ( gen_record_pat_field ( & field_name, & r_name) ) ;
637
+
638
+ let lhs = make:: expr_path ( make:: ext:: ident_path ( l_name) ) ;
639
+ let rhs = make:: expr_path ( make:: ext:: ident_path ( r_name) ) ;
640
+ let cmp = make:: expr_op ( ast:: BinOp :: EqualityTest , lhs, rhs) ;
641
+ expr = gen_eq_chain ( expr, cmp) ;
642
+ }
643
+
644
+ let left = gen_record_pat ( gen_variant_path ( & variant) ?, l_fields) ;
645
+ let right = gen_record_pat ( gen_variant_path ( & variant) ?, r_fields) ;
646
+ let tuple = make:: tuple_pat ( vec ! [ left. into( ) , right. into( ) ] ) ;
647
+
648
+ if let Some ( expr) = expr {
649
+ arms. push ( make:: match_arm ( Some ( tuple. into ( ) ) , None , expr) ) ;
650
+ }
651
+ }
652
+
653
+ Some ( ast:: FieldList :: TupleFieldList ( list) ) => {
654
+ let mut expr = None ;
655
+ let mut l_fields = vec ! [ ] ;
656
+ let mut r_fields = vec ! [ ] ;
657
+
658
+ for ( i, _) in list. fields ( ) . enumerate ( ) {
659
+ let field_name = format ! ( "{}" , i) ;
660
+
661
+ let l_name = format ! ( "l{}" , field_name) ;
662
+ l_fields. push ( gen_tuple_field ( & l_name) ) ;
663
+
664
+ let r_name = format ! ( "r{}" , field_name) ;
665
+ r_fields. push ( gen_tuple_field ( & r_name) ) ;
666
+
667
+ let lhs = make:: expr_path ( make:: ext:: ident_path ( & l_name) ) ;
668
+ let rhs = make:: expr_path ( make:: ext:: ident_path ( & r_name) ) ;
669
+ let cmp = make:: expr_op ( ast:: BinOp :: EqualityTest , lhs, rhs) ;
670
+ expr = gen_eq_chain ( expr, cmp) ;
671
+ }
672
+
673
+ let left = make:: tuple_struct_pat ( gen_variant_path ( & variant) ?, l_fields) ;
674
+ let right = make:: tuple_struct_pat ( gen_variant_path ( & variant) ?, r_fields) ;
675
+ let tuple = make:: tuple_pat ( vec ! [ left. into( ) , right. into( ) ] ) ;
676
+
677
+ if let Some ( expr) = expr {
678
+ arms. push ( make:: match_arm ( Some ( tuple. into ( ) ) , None , expr) ) ;
679
+ }
680
+ }
681
+ None => continue ,
682
+ }
683
+ }
684
+
685
+ let expr = match arms. len ( ) {
686
+ 0 => eq_check,
687
+ _ => {
688
+ if case_count > arms. len ( ) {
689
+ let lhs = make:: wildcard_pat ( ) . into ( ) ;
690
+ arms. push ( make:: match_arm ( Some ( lhs) , None , eq_check) ) ;
691
+ }
692
+
693
+ let match_target = make:: expr_tuple ( vec ! [ lhs_name, rhs_name] ) ;
694
+ let list = make:: match_arm_list ( arms) . indent ( ast:: edit:: IndentLevel ( 1 ) ) ;
695
+ make:: expr_match ( match_target, list)
696
+ }
697
+ } ;
698
+
699
+ make:: block_expr ( None , Some ( expr) ) . indent ( ast:: edit:: IndentLevel ( 1 ) )
700
+ }
701
+ ast:: Adt :: Struct ( strukt) => match strukt. field_list ( ) {
702
+ Some ( ast:: FieldList :: RecordFieldList ( field_list) ) => {
703
+ let mut expr = None ;
704
+ for field in field_list. fields ( ) {
705
+ let lhs = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
706
+ let lhs = make:: expr_field ( lhs, & field. name ( ) ?. to_string ( ) ) ;
707
+ let rhs = make:: expr_path ( make:: ext:: ident_path ( "other" ) ) ;
708
+ let rhs = make:: expr_field ( rhs, & field. name ( ) ?. to_string ( ) ) ;
709
+ let cmp = make:: expr_op ( ast:: BinOp :: EqualityTest , lhs, rhs) ;
710
+ expr = gen_eq_chain ( expr, cmp) ;
711
+ }
712
+ make:: block_expr ( None , expr) . indent ( ast:: edit:: IndentLevel ( 1 ) )
713
+ }
714
+
715
+ Some ( ast:: FieldList :: TupleFieldList ( field_list) ) => {
716
+ let mut expr = None ;
717
+ for ( i, _) in field_list. fields ( ) . enumerate ( ) {
718
+ let idx = format ! ( "{}" , i) ;
719
+ let lhs = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
720
+ let lhs = make:: expr_field ( lhs, & idx) ;
721
+ let rhs = make:: expr_path ( make:: ext:: ident_path ( "other" ) ) ;
722
+ let rhs = make:: expr_field ( rhs, & idx) ;
723
+ let cmp = make:: expr_op ( ast:: BinOp :: EqualityTest , lhs, rhs) ;
724
+ expr = gen_eq_chain ( expr, cmp) ;
725
+ }
726
+ make:: block_expr ( None , expr) . indent ( ast:: edit:: IndentLevel ( 1 ) )
727
+ }
728
+
729
+ // No fields in the body means there's nothing to hash.
730
+ None => {
731
+ let expr = make:: expr_literal ( "true" ) . into ( ) ;
732
+ make:: block_expr ( None , Some ( expr) ) . indent ( ast:: edit:: IndentLevel ( 1 ) )
733
+ }
734
+ } ,
735
+ } ;
736
+
737
+ ted:: replace ( func. body ( ) ?. syntax ( ) , body. clone_for_update ( ) . syntax ( ) ) ;
738
+ Some ( ( ) )
739
+ }
740
+
575
741
fn make_discriminant ( ) -> Option < ast:: Expr > {
576
742
Some ( make:: expr_path ( make:: ext:: path_from_idents ( [ "core" , "mem" , "discriminant" ] ) ?) )
577
743
}
0 commit comments