1
1
use std:: cmp:: { self , Ordering } ;
2
+ use std:: collections:: HashSet ;
2
3
use std:: fmt:: { self , Formatter } ;
3
4
use std:: hash:: { self , Hash } ;
4
5
use std:: path:: Path ;
5
- use std:: sync:: Arc ;
6
+ use std:: ptr;
7
+ use std:: sync:: Mutex ;
6
8
use std:: sync:: atomic:: { AtomicBool , ATOMIC_BOOL_INIT } ;
7
9
use std:: sync:: atomic:: Ordering :: SeqCst ;
8
10
@@ -16,13 +18,17 @@ use sources::{GitSource, PathSource, RegistrySource, CRATES_IO_INDEX};
16
18
use sources:: DirectorySource ;
17
19
use util:: { CargoResult , Config , ToUrl } ;
18
20
21
+ lazy_static ! {
22
+ static ref SOURCE_ID_CACHE : Mutex <HashSet <& ' static SourceIdInner >> = Mutex :: new( HashSet :: new( ) ) ;
23
+ }
24
+
19
25
/// Unique identifier for a source of packages.
20
- #[ derive( Clone , Eq , Debug ) ]
26
+ #[ derive( Clone , Copy , Eq , Debug ) ]
21
27
pub struct SourceId {
22
- inner : Arc < SourceIdInner > ,
28
+ inner : & ' static SourceIdInner ,
23
29
}
24
30
25
- #[ derive( Eq , Clone , Debug ) ]
31
+ #[ derive( PartialEq , Eq , Clone , Debug , Hash ) ]
26
32
struct SourceIdInner {
27
33
/// The source URL
28
34
url : Url ,
@@ -68,18 +74,28 @@ impl SourceId {
68
74
///
69
75
/// The canonical url will be calculated, but the precise field will not
70
76
fn new ( kind : Kind , url : Url ) -> CargoResult < SourceId > {
71
- let source_id = SourceId {
72
- inner : Arc :: new ( SourceIdInner {
77
+ let source_id = SourceId :: wrap (
78
+ SourceIdInner {
73
79
kind,
74
80
canonical_url : git:: canonicalize_url ( & url) ?,
75
81
url,
76
82
precise : None ,
77
83
name : None ,
78
- } ) ,
79
- } ;
84
+ }
85
+ ) ;
80
86
Ok ( source_id)
81
87
}
82
88
89
+ fn wrap ( inner : SourceIdInner ) -> SourceId {
90
+ let mut cache = SOURCE_ID_CACHE . lock ( ) . unwrap ( ) ;
91
+ let inner = cache. get ( & inner) . map ( |& x| x) . unwrap_or_else ( || {
92
+ let inner = Box :: leak ( Box :: new ( inner) ) ;
93
+ cache. insert ( inner) ;
94
+ inner
95
+ } ) ;
96
+ SourceId { inner }
97
+ }
98
+
83
99
/// Parses a source URL and returns the corresponding ID.
84
100
///
85
101
/// ## Example
@@ -193,15 +209,15 @@ impl SourceId {
193
209
194
210
pub fn alt_registry ( config : & Config , key : & str ) -> CargoResult < SourceId > {
195
211
let url = config. get_registry_index ( key) ?;
196
- Ok ( SourceId {
197
- inner : Arc :: new ( SourceIdInner {
212
+ Ok ( SourceId :: wrap (
213
+ SourceIdInner {
198
214
kind : Kind :: Registry ,
199
215
canonical_url : git:: canonicalize_url ( & url) ?,
200
216
url,
201
217
precise : None ,
202
218
name : Some ( key. to_string ( ) ) ,
203
- } ) ,
204
- } )
219
+ }
220
+ ) )
205
221
}
206
222
207
223
/// Get this source URL
@@ -288,12 +304,12 @@ impl SourceId {
288
304
289
305
/// Create a new SourceId from this source with the given `precise`
290
306
pub fn with_precise ( & self , v : Option < String > ) -> SourceId {
291
- SourceId {
292
- inner : Arc :: new ( SourceIdInner {
307
+ SourceId :: wrap (
308
+ SourceIdInner {
293
309
precise : v,
294
310
..( * self . inner ) . clone ( )
295
- } ) ,
296
- }
311
+ }
312
+ )
297
313
}
298
314
299
315
/// Whether the remote registry is the standard https://crates.io
@@ -326,12 +342,6 @@ impl SourceId {
326
342
}
327
343
}
328
344
329
- impl PartialEq for SourceId {
330
- fn eq ( & self , other : & SourceId ) -> bool {
331
- ( * self . inner ) . eq ( & * other. inner )
332
- }
333
- }
334
-
335
345
impl PartialOrd for SourceId {
336
346
fn partial_cmp ( & self , other : & SourceId ) -> Option < Ordering > {
337
347
Some ( self . cmp ( other) )
@@ -425,24 +435,23 @@ impl fmt::Display for SourceId {
425
435
}
426
436
}
427
437
428
- // This custom implementation handles situations such as when two git sources
429
- // point at *almost* the same URL, but not quite, even when they actually point
430
- // to the same repository.
431
- /// This method tests for self and other values to be equal, and is used by ==.
432
- ///
433
- /// For git repositories, the canonical url is checked.
434
- impl PartialEq for SourceIdInner {
435
- fn eq ( & self , other : & SourceIdInner ) -> bool {
436
- if self . kind != other. kind {
438
+ // Custom equality defined as canonical URL equality for git sources and
439
+ // URL equality for other sources, ignoring the `precise` and `name` fields.
440
+ impl PartialEq for SourceId {
441
+ fn eq ( & self , other : & SourceId ) -> bool {
442
+ if ptr:: eq ( self . inner , other. inner ) {
443
+ return true ;
444
+ }
445
+ if self . inner . kind != other. inner . kind {
437
446
return false ;
438
447
}
439
- if self . url == other. url {
448
+ if self . inner . url == other. inner . url {
440
449
return true ;
441
450
}
442
451
443
- match ( & self . kind , & other. kind ) {
444
- ( & Kind :: Git ( ref ref1) , & Kind :: Git ( ref ref2) ) => {
445
- ref1 == ref2 && self . canonical_url == other. canonical_url
452
+ match ( & self . inner . kind , & other. inner . kind ) {
453
+ ( Kind :: Git ( ref1) , Kind :: Git ( ref2) ) => {
454
+ ref1 == ref2 && self . inner . canonical_url == other. inner . canonical_url
446
455
}
447
456
_ => false ,
448
457
}
0 commit comments