11use crate :: hasher:: { blake2b_512, blake2s_256, sha2_256, sha2_512, sha3_256, sha3_512} ;
2- use crate :: Error :: PoisonedLock ;
2+ use crate :: Error :: { PoisonedLock , UnsupportedRepository } ;
33use crate :: Result ;
44use lazy_static:: lazy_static;
5- use std:: collections:: HashMap ;
65use std:: sync:: { Arc , Mutex , RwLock } ;
76
87lazy_static ! {
98 static ref REGISTRY : Arc <Mutex <HasherRegistry >> =
109 Arc :: new( Mutex :: new( HasherRegistry :: default ( ) ) ) ;
1110}
1211
12+ pub type SupportsFn = fn ( & str , & str ) -> Result < bool > ;
1313pub type HasherFn = fn ( & Vec < u8 > ) -> Result < String > ;
1414
1515/// Singleton struct to store hashers
16+ #[ allow( clippy:: type_complexity) ]
1617struct HasherRegistry {
17- hashers : HashMap < String , Arc < RwLock < HasherFn > > > ,
18+ hashers : Vec < ( Arc < RwLock < SupportsFn > > , Arc < RwLock < HasherFn > > ) > ,
1819}
1920
2021impl HasherRegistry {
2122 /// Creates a new hasher registry.
2223 fn new ( ) -> Self {
2324 Self {
24- hashers : HashMap :: new ( ) ,
25+ hashers : Vec :: new ( ) ,
2526 }
2627 }
2728
28- /// Registers a hasher for an extension. Newly registered hashers with the same extension will
29- /// override existing ones.
30- fn register < S : AsRef < str > > ( & mut self , extension : S , hasher_fn : HasherFn ) {
31- let extension = extension. as_ref ( ) . to_string ( ) ;
32- self . hashers
33- . insert ( extension, Arc :: new ( RwLock :: new ( hasher_fn) ) ) ;
29+ /// Registers a hasher for a supports function. Newly registered hashers will take precedence
30+ /// over existing ones.
31+ fn register ( & mut self , supports_fn : SupportsFn , hasher_fn : HasherFn ) {
32+ self . hashers . insert (
33+ 0 ,
34+ (
35+ Arc :: new ( RwLock :: new ( supports_fn) ) ,
36+ Arc :: new ( RwLock :: new ( hasher_fn) ) ,
37+ ) ,
38+ ) ;
3439 }
3540
36- /// Get a hasher for the specified extension.
41+ /// Get a hasher for the specified url and extension.
3742 ///
3843 /// # Errors
3944 /// * If the registry is poisoned.
40- fn get < S : AsRef < str > > ( & self , extension : S ) -> Result < Option < HasherFn > > {
41- let extension = extension. as_ref ( ) . to_string ( ) ;
42- if let Some ( hasher) = self . hashers . get ( & extension) {
43- let hasher = * hasher
45+ fn get < S : AsRef < str > > ( & self , url : S , extension : S ) -> Result < HasherFn > {
46+ let url = url. as_ref ( ) ;
47+ let extension = extension. as_ref ( ) ;
48+ for ( supports_fn, hasher_fn) in & self . hashers {
49+ let supports_function = supports_fn
4450 . read ( )
4551 . map_err ( |error| PoisonedLock ( error. to_string ( ) ) ) ?;
46- return Ok ( Some ( hasher) ) ;
52+ if supports_function ( url, extension) ? {
53+ let hasher_function = hasher_fn
54+ . read ( )
55+ . map_err ( |error| PoisonedLock ( error. to_string ( ) ) ) ?;
56+ return Ok ( * hasher_function) ;
57+ }
4758 }
4859
49- Ok ( None )
50- }
51-
52- /// Get the number of hashers in the registry.
53- fn len ( & self ) -> usize {
54- self . hashers . len ( )
55- }
56-
57- /// Check if the registry is empty.
58- fn is_empty ( & self ) -> bool {
59- self . hashers . is_empty ( )
60+ Err ( UnsupportedRepository ( url. to_string ( ) ) )
6061 }
6162}
6263
6364impl Default for HasherRegistry {
6465 /// Creates a new hasher registry with the default hashers registered.
6566 fn default ( ) -> Self {
6667 let mut registry = Self :: new ( ) ;
67- registry. register ( "blake2s" , blake2s_256:: hash) ;
68- registry. register ( "blake2b" , blake2b_512:: hash) ;
69- registry. register ( "sha256" , sha2_256:: hash) ;
70- registry. register ( "sha512" , sha2_512:: hash) ;
71- registry. register ( "sha3-256" , sha3_256:: hash) ;
72- registry. register ( "sha3-512" , sha3_512:: hash) ;
68+ registry. register ( |_ , extension| Ok ( extension == "blake2s" ) , blake2s_256:: hash) ;
69+ registry. register ( |_ , extension| Ok ( extension == "blake2b" ) , blake2b_512:: hash) ;
70+ registry. register ( |_ , extension| Ok ( extension == "sha256" ) , sha2_256:: hash) ;
71+ registry. register ( |_ , extension| Ok ( extension == "sha512" ) , sha2_512:: hash) ;
72+ registry. register ( |_ , extension| Ok ( extension == "sha3-256" ) , sha3_256:: hash) ;
73+ registry. register ( |_ , extension| Ok ( extension == "sha3-512" ) , sha3_512:: hash) ;
7374 registry
7475 }
7576}
7677
77- /// Registers a hasher for an extension . Newly registered hashers with the same extension will
78- /// override existing ones.
78+ /// Registers a hasher for a supports function . Newly registered hashers will take precedence
79+ /// over existing ones.
7980///
8081/// # Errors
8182/// * If the registry is poisoned.
8283#[ allow( dead_code) ]
83- pub fn register < S : AsRef < str > > ( extension : S , hasher_fn : HasherFn ) -> Result < ( ) > {
84+ pub fn register ( supports_fn : SupportsFn , hasher_fn : HasherFn ) -> Result < ( ) > {
8485 let mut registry = REGISTRY
8586 . lock ( )
8687 . map_err ( |error| PoisonedLock ( error. to_string ( ) ) ) ?;
87- registry. register ( extension , hasher_fn) ;
88+ registry. register ( supports_fn , hasher_fn) ;
8889 Ok ( ( ) )
8990}
9091
91- /// Get a hasher for the specified extension.
92- ///
93- /// # Errors
94- /// * If the registry is poisoned.
95- pub fn get < S : AsRef < str > > ( extension : S ) -> Result < Option < HasherFn > > {
96- let registry = REGISTRY
97- . lock ( )
98- . map_err ( |error| PoisonedLock ( error. to_string ( ) ) ) ?;
99- registry. get ( extension)
100- }
101-
102- /// Get the number of matchers in the registry.
92+ /// Get a hasher for the specified url and extension.
10393///
10494/// # Errors
10595/// * If the registry is poisoned.
106- pub fn len ( ) -> Result < usize > {
96+ pub fn get < S : AsRef < str > > ( url : S , extension : S ) -> Result < HasherFn > {
10797 let registry = REGISTRY
10898 . lock ( )
10999 . map_err ( |error| PoisonedLock ( error. to_string ( ) ) ) ?;
110- Ok ( registry. len ( ) )
111- }
112-
113- /// Check if the registry is empty.
114- ///
115- /// # Errors
116- /// * If the registry is poisoned.
117- pub fn is_empty ( ) -> Result < bool > {
118- let registry = REGISTRY
119- . lock ( )
120- . map_err ( |error| PoisonedLock ( error. to_string ( ) ) ) ?;
121- Ok ( registry. is_empty ( ) )
100+ registry. get ( url, extension)
122101}
123102
124103#[ cfg( test) ]
125104mod tests {
126105 use super :: * ;
127106
128107 fn test_hasher ( extension : & str , expected : & str ) -> Result < ( ) > {
129- let hasher = get ( extension) ?. unwrap ( ) ;
108+ let hasher = get ( "https://foo.com" , extension) ?;
130109 let data = vec ! [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 0 ] ;
131110 let hash = hasher ( & data) ?;
132111 assert_eq ! ( expected, hash) ;
@@ -135,22 +114,11 @@ mod tests {
135114
136115 #[ test]
137116 fn test_register ( ) -> Result < ( ) > {
138- let extension = "sha256" ;
139- let hashers = len ( ) ?;
140- assert ! ( !is_empty( ) ?) ;
141- REGISTRY
142- . lock ( )
143- . map_err ( |error| PoisonedLock ( error. to_string ( ) ) ) ?
144- . hashers
145- . remove ( extension) ;
146- assert_ne ! ( hashers, len( ) ?) ;
147- register ( extension, sha2_256:: hash) ?;
148- assert_eq ! ( hashers, len( ) ?) ;
149-
150- test_hasher (
151- extension,
152- "9a89c68c4c5e28b8c4a5567673d462fff515db46116f9900624d09c474f593fb" ,
153- )
117+ register (
118+ |_, extension| Ok ( extension == "foo" ) ,
119+ |_| Ok ( "42" . to_string ( ) ) ,
120+ ) ?;
121+ test_hasher ( "foo" , "42" )
154122 }
155123
156124 #[ test]
0 commit comments