@@ -9,6 +9,7 @@ pub mod role_index;
99
1010use std:: {
1111 fmt:: { Display , Formatter } ,
12+ hash:: Hash ,
1213 str:: FromStr ,
1314 sync:: Arc ,
1415} ;
@@ -42,7 +43,7 @@ pub struct CatalystId {
4243}
4344
4445/// A Catalyst ID data intended to be wrapper in `Arc`.
45- #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
46+ #[ derive( Debug , Clone ) ]
4647struct CatalystIdInner {
4748 /// Username
4849 username : Option < String > ,
@@ -535,6 +536,50 @@ impl CatalystId {
535536 . without_encryption ( )
536537 . as_id ( )
537538 }
539+
540+ /// Comparisons of `CatalystId` based on original `PartialEq` plus including
541+ /// `username` and `nonce` fields.
542+ #[ must_use]
543+ pub fn eq_with_userinfo (
544+ & self ,
545+ other : & Self ,
546+ ) -> bool {
547+ self . eq ( other) && self . username ( ) . eq ( & other. username ( ) ) && self . nonce ( ) . eq ( & other. nonce ( ) )
548+ }
549+
550+ /// Comparisons of `CatalystId` based on `CatalystId::eq_with_userinfo` plus including
551+ /// `role` and `rotation` fields.
552+ #[ must_use]
553+ pub fn eq_with_role (
554+ & self ,
555+ other : & Self ,
556+ ) -> bool {
557+ self . eq_with_userinfo ( other) && self . role_and_rotation ( ) . eq ( & other. role_and_rotation ( ) )
558+ }
559+ }
560+
561+ impl PartialEq for CatalystIdInner {
562+ fn eq (
563+ & self ,
564+ other : & Self ,
565+ ) -> bool {
566+ self . network . eq ( & other. network )
567+ && self . subnet . eq ( & other. subnet )
568+ && self . role0_pk . eq ( & other. role0_pk )
569+ }
570+ }
571+
572+ impl Eq for CatalystIdInner { }
573+
574+ impl Hash for CatalystIdInner {
575+ fn hash < H : std:: hash:: Hasher > (
576+ & self ,
577+ state : & mut H ,
578+ ) {
579+ self . network . hash ( state) ;
580+ self . subnet . hash ( state) ;
581+ self . role0_pk . hash ( state) ;
582+ }
538583}
539584
540585impl FromStr for CatalystId {
@@ -743,6 +788,7 @@ mod tests {
743788 use chrono:: { DateTime , Utc } ;
744789 use ed25519_dalek:: SigningKey ;
745790 use rand:: rngs:: OsRng ;
791+ use test_case:: test_case;
746792
747793 use super :: CatalystId ;
748794
@@ -796,7 +842,46 @@ mod tests {
796842 let uri_id = test_uri. parse :: < CatalystId > ( ) . unwrap ( ) ;
797843 let short_id = expected_id. parse :: < CatalystId > ( ) . unwrap ( ) ;
798844
799- assert_eq ! ( uri_id. as_short_id( ) , short_id) ;
845+ assert_eq ! ( uri_id. as_short_id( ) . inner, short_id. inner) ;
846+ }
847+
848+ #[ test_case( 0 , 1 , true , false , false ; "base vs user" ) ]
849+ #[ test_case( 0 , 2 , true , false , false ; "base vs user_nonce" ) ]
850+ #[ test_case( 0 , 3 , true , false , false ; "base vs nonce" ) ]
851+ #[ test_case( 0 , 4 , true , true , true ; "base vs base_duplicate" ) ]
852+ #[ test_case( 7 , 8 , true , true , false ; "midnight_0_1 vs midnight_2_1" ) ]
853+ #[ test_case( 0 , 5 , false , false , false ; "cardano vs preprod" ) ]
854+ #[ test_case( 5 , 6 , false , false , false ; "preprod vs preview" ) ]
855+ #[ test_case( 6 , 7 , false , false , false ; "preview vs midnight" ) ]
856+ #[ test_case( 1 , 2 , true , false , false ; "user vs user_nonce" ) ]
857+ #[ test_case( 2 , 3 , true , false , false ; "user_nonce vs nonce" ) ]
858+ #[ test_case( 8 , 8 , true , true , true ; "identical self comparison" ) ]
859+ #[ allow( clippy:: indexing_slicing, clippy:: similar_names) ]
860+ fn test_all_comparisons (
861+ idx_a : usize ,
862+ idx_b : usize ,
863+ expected_eq : bool ,
864+ expected_userinfo : bool ,
865+ expected_role : bool ,
866+ ) {
867+ let id_a = CATALYST_ID_TEST_VECTOR [ idx_a]
868+ . parse :: < CatalystId > ( )
869+ . unwrap ( ) ;
870+ let id_b = CATALYST_ID_TEST_VECTOR [ idx_b]
871+ . parse :: < CatalystId > ( )
872+ . unwrap ( ) ;
873+
874+ assert_eq ! ( id_a == id_b, expected_eq, "PartialEq failed" ) ;
875+ assert_eq ! (
876+ id_a. eq_with_userinfo( & id_b) ,
877+ expected_userinfo,
878+ "eq_with_userinfo failed"
879+ ) ;
880+ assert_eq ! (
881+ id_a. eq_with_role( & id_b) ,
882+ expected_role,
883+ "eq_with_role failed"
884+ ) ;
800885 }
801886
802887 #[ ignore = "Test to be fixed and re-enabled" ]
0 commit comments