1
- use crate :: hasher:: { blake2b_512 , blake2s_256 , sha2_256, sha2_512 , sha3_256 , sha3_512 } ;
2
- use crate :: Error :: PoisonedLock ;
3
- use crate :: Result ;
1
+ use crate :: hasher:: sha2_256;
2
+ use crate :: Error :: { PoisonedLock , UnsupportedHasher } ;
3
+ use crate :: { Result , THESEUS_POSTGRESQL_BINARIES_URL } ;
4
4
use lazy_static:: lazy_static;
5
- use std:: collections:: HashMap ;
6
5
use std:: sync:: { Arc , Mutex , RwLock } ;
7
6
8
7
lazy_static ! {
9
8
static ref REGISTRY : Arc <Mutex <HasherRegistry >> =
10
9
Arc :: new( Mutex :: new( HasherRegistry :: default ( ) ) ) ;
11
10
}
12
11
12
+ pub type SupportsFn = fn ( & str , & str ) -> Result < bool > ;
13
13
pub type HasherFn = fn ( & Vec < u8 > ) -> Result < String > ;
14
14
15
15
/// Singleton struct to store hashers
16
+ #[ allow( clippy:: type_complexity) ]
16
17
struct HasherRegistry {
17
- hashers : HashMap < String , Arc < RwLock < HasherFn > > > ,
18
+ hashers : Vec < ( Arc < RwLock < SupportsFn > > , Arc < RwLock < HasherFn > > ) > ,
18
19
}
19
20
20
21
impl HasherRegistry {
21
22
/// Creates a new hasher registry.
22
23
fn new ( ) -> Self {
23
24
Self {
24
- hashers : HashMap :: new ( ) ,
25
+ hashers : Vec :: new ( ) ,
25
26
}
26
27
}
27
28
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
+ ) ;
34
39
}
35
40
36
- /// Get a hasher for the specified extension.
41
+ /// Get a hasher for the specified url and extension.
37
42
///
38
43
/// # Errors
39
44
/// * 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
44
50
. read ( )
45
51
. 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
+ }
47
58
}
48
59
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 ( UnsupportedHasher ( url. to_string ( ) ) )
60
61
}
61
62
}
62
63
63
64
impl Default for HasherRegistry {
64
65
/// Creates a new hasher registry with the default hashers registered.
65
66
fn default ( ) -> Self {
66
67
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 (
69
+ |url , extension| {
70
+ Ok ( url . starts_with ( THESEUS_POSTGRESQL_BINARIES_URL ) && extension == "sha256" )
71
+ } ,
72
+ sha2_256 :: hash,
73
+ ) ;
73
74
registry
74
75
}
75
76
}
76
77
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.
79
80
///
80
81
/// # Errors
81
82
/// * If the registry is poisoned.
82
83
#[ 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 < ( ) > {
84
85
let mut registry = REGISTRY
85
86
. lock ( )
86
87
. map_err ( |error| PoisonedLock ( error. to_string ( ) ) ) ?;
87
- registry. register ( extension , hasher_fn) ;
88
+ registry. register ( supports_fn , hasher_fn) ;
88
89
Ok ( ( ) )
89
90
}
90
91
91
- /// Get a hasher for the specified extension.
92
+ /// Get a hasher for the specified url and extension.
92
93
///
93
94
/// # Errors
94
95
/// * If the registry is poisoned.
95
- pub fn get < S : AsRef < str > > ( extension : S ) -> Result < Option < HasherFn > > {
96
+ pub fn get < S : AsRef < str > > ( url : S , extension : S ) -> Result < HasherFn > {
96
97
let registry = REGISTRY
97
98
. lock ( )
98
99
. map_err ( |error| PoisonedLock ( error. to_string ( ) ) ) ?;
99
- registry. get ( extension)
100
- }
101
-
102
- /// Get the number of matchers in the registry.
103
- ///
104
- /// # Errors
105
- /// * If the registry is poisoned.
106
- pub fn len ( ) -> Result < usize > {
107
- let registry = REGISTRY
108
- . lock ( )
109
- . 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)
122
101
}
123
102
124
103
#[ cfg( test) ]
125
104
mod tests {
126
105
use super :: * ;
127
106
128
107
fn test_hasher ( extension : & str , expected : & str ) -> Result < ( ) > {
129
- let hasher = get ( extension) ?. unwrap ( ) ;
108
+ let hasher = get ( "https://foo.com" , extension) ?;
130
109
let data = vec ! [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 0 ] ;
131
110
let hash = hasher ( & data) ?;
132
111
assert_eq ! ( expected, hash) ;
@@ -135,69 +114,33 @@ mod tests {
135
114
136
115
#[ test]
137
116
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
- )
154
- }
155
-
156
- #[ test]
157
- fn test_sha2_256 ( ) -> Result < ( ) > {
158
- test_hasher (
159
- "sha256" ,
160
- "9a89c68c4c5e28b8c4a5567673d462fff515db46116f9900624d09c474f593fb" ,
161
- )
162
- }
163
-
164
- #[ test]
165
- fn test_sha2_512 ( ) -> Result < ( ) > {
166
- test_hasher (
167
- "sha512" ,
168
- "3ad3f36979450d4f53366244ecf1010f4f9121d6888285ff14104fd5aded85d48aa171bf1e33a112602f92b7a7088b298789012fb87b9056321241a19fb74e0b" ,
169
- )
170
- }
171
-
172
- #[ test]
173
- fn test_sha3_256 ( ) -> Result < ( ) > {
174
- test_hasher (
175
- "sha3-256" ,
176
- "c0188232190e0427fc9cc78597221c76c799528660889bd6ce1f3563148ff84d" ,
177
- )
117
+ register (
118
+ |_, extension| Ok ( extension == "test" ) ,
119
+ |_| Ok ( "42" . to_string ( ) ) ,
120
+ ) ?;
121
+ test_hasher ( "test" , "42" )
178
122
}
179
123
180
124
#[ test]
181
- fn test_sha3_512 ( ) -> Result < ( ) > {
182
- test_hasher (
183
- "sha3-512" ,
184
- "9429fc1f9772cc1d8039fe75cc1b033cd60f0ec4face0f8a514d25b0649ba8a5954b6c7a41cc3697a56db3ff321475be1fa14b70c7eb78fec6ce62dbfc54c9d3" ,
185
- )
125
+ fn test_get_invalid_url_error ( ) {
126
+ let error = get ( "https://foo.com" , "foo" ) . unwrap_err ( ) ;
127
+ assert_eq ! (
128
+ "unsupported hasher for 'https://foo.com'" ,
129
+ error. to_string( )
130
+ ) ;
186
131
}
187
132
188
133
#[ test]
189
- fn test_blake2s_256 ( ) -> Result < ( ) > {
190
- test_hasher (
191
- "blake2s" ,
192
- "7125921e06071710350390fe902856dbea366a5d6f5ee26c18e741143ac80061" ,
193
- )
134
+ fn test_get_invalid_extension_error ( ) {
135
+ let error = get ( THESEUS_POSTGRESQL_BINARIES_URL , "foo" ) . unwrap_err ( ) ;
136
+ assert_eq ! (
137
+ format!( "unsupported hasher for '{THESEUS_POSTGRESQL_BINARIES_URL}'" ) ,
138
+ error. to_string( )
139
+ ) ;
194
140
}
195
141
196
142
#[ test]
197
- fn test_blake2b_512 ( ) -> Result < ( ) > {
198
- test_hasher (
199
- "blake2b" ,
200
- "67767f1cab415502dcceec9f099fb84539b1c73c5ebdcfe1bb8ca7411e3b6cb33e304f49222edac9bdaa74129e9e13f11f215b8560f9081f0e8f1f869162bf46" ,
201
- )
143
+ fn test_get_theseus_postgresql_binaries ( ) {
144
+ assert ! ( get( THESEUS_POSTGRESQL_BINARIES_URL , "sha256" ) . is_ok( ) ) ;
202
145
}
203
146
}
0 commit comments