@@ -76,7 +76,9 @@ use rustc_data_structures::sync::{FreezeLock, FreezeWriteGuard, Lock, Lrc};
76
76
77
77
use std:: borrow:: Cow ;
78
78
use std:: cmp:: { self , Ordering } ;
79
+ use std:: fmt:: Display ;
79
80
use std:: hash:: Hash ;
81
+ use std:: io:: { self , Read } ;
80
82
use std:: ops:: { Add , Range , Sub } ;
81
83
use std:: path:: { Path , PathBuf } ;
82
84
use std:: str:: FromStr ;
@@ -1456,6 +1458,27 @@ pub enum SourceFileHashAlgorithm {
1456
1458
Md5 ,
1457
1459
Sha1 ,
1458
1460
Sha256 ,
1461
+ Blake3 ,
1462
+ }
1463
+
1464
+ impl SourceFileHashAlgorithm {
1465
+ pub fn supported_in_cargo ( & self ) -> bool {
1466
+ match self {
1467
+ Self :: Md5 | Self :: Sha1 => false ,
1468
+ Self :: Sha256 | Self :: Blake3 => true ,
1469
+ }
1470
+ }
1471
+ }
1472
+
1473
+ impl Display for SourceFileHashAlgorithm {
1474
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1475
+ f. write_str ( match self {
1476
+ Self :: Md5 => "md5" ,
1477
+ Self :: Sha1 => "sha1" ,
1478
+ Self :: Sha256 => "sha256" ,
1479
+ Self :: Blake3 => "blake3" ,
1480
+ } )
1481
+ }
1459
1482
}
1460
1483
1461
1484
impl FromStr for SourceFileHashAlgorithm {
@@ -1466,25 +1489,36 @@ impl FromStr for SourceFileHashAlgorithm {
1466
1489
"md5" => Ok ( SourceFileHashAlgorithm :: Md5 ) ,
1467
1490
"sha1" => Ok ( SourceFileHashAlgorithm :: Sha1 ) ,
1468
1491
"sha256" => Ok ( SourceFileHashAlgorithm :: Sha256 ) ,
1492
+ "blake3" => Ok ( SourceFileHashAlgorithm :: Blake3 ) ,
1469
1493
_ => Err ( ( ) ) ,
1470
1494
}
1471
1495
}
1472
1496
}
1473
1497
1474
- /// The hash of the on-disk source file used for debug info.
1498
+ /// The hash of the on-disk source file used for debug info and cargo freshness checks .
1475
1499
#[ derive( Copy , Clone , PartialEq , Eq , Debug , Hash ) ]
1476
1500
#[ derive( HashStable_Generic , Encodable , Decodable ) ]
1477
1501
pub struct SourceFileHash {
1478
1502
pub kind : SourceFileHashAlgorithm ,
1479
1503
value : [ u8 ; 32 ] ,
1480
1504
}
1481
1505
1506
+ impl Display for SourceFileHash {
1507
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1508
+ write ! ( f, "{}=" , self . kind) ?;
1509
+ for byte in self . value [ 0 ..self . hash_len ( ) ] . into_iter ( ) {
1510
+ write ! ( f, "{byte:02x}" ) ?;
1511
+ }
1512
+ Ok ( ( ) )
1513
+ }
1514
+ }
1515
+
1482
1516
impl SourceFileHash {
1483
- pub fn new ( kind : SourceFileHashAlgorithm , src : & str ) -> SourceFileHash {
1517
+ pub fn new_in_memory ( kind : SourceFileHashAlgorithm , src : impl AsRef < [ u8 ] > ) -> SourceFileHash {
1484
1518
let mut hash = SourceFileHash { kind, value : Default :: default ( ) } ;
1485
1519
let len = hash. hash_len ( ) ;
1486
1520
let value = & mut hash. value [ ..len] ;
1487
- let data = src. as_bytes ( ) ;
1521
+ let data = src. as_ref ( ) ;
1488
1522
match kind {
1489
1523
SourceFileHashAlgorithm :: Md5 => {
1490
1524
value. copy_from_slice ( & Md5 :: digest ( data) ) ;
@@ -1495,13 +1529,94 @@ impl SourceFileHash {
1495
1529
SourceFileHashAlgorithm :: Sha256 => {
1496
1530
value. copy_from_slice ( & Sha256 :: digest ( data) ) ;
1497
1531
}
1498
- }
1532
+ SourceFileHashAlgorithm :: Blake3 => value. copy_from_slice ( blake3:: hash ( data) . as_bytes ( ) ) ,
1533
+ } ;
1499
1534
hash
1500
1535
}
1501
1536
1537
+ pub fn new ( kind : SourceFileHashAlgorithm , src : impl Read ) -> Result < SourceFileHash , io:: Error > {
1538
+ let mut hash = SourceFileHash { kind, value : Default :: default ( ) } ;
1539
+ let len = hash. hash_len ( ) ;
1540
+ let value = & mut hash. value [ ..len] ;
1541
+ // Buffer size is the recommended amount to fully leverage SIMD instructions on AVX-512 as per
1542
+ // blake3 documentation.
1543
+ let mut buf = vec ! [ 0 ; 16 * 1024 ] ;
1544
+
1545
+ fn digest < T > (
1546
+ mut hasher : T ,
1547
+ mut update : impl FnMut ( & mut T , & [ u8 ] ) ,
1548
+ finish : impl FnOnce ( T , & mut [ u8 ] ) ,
1549
+ mut src : impl Read ,
1550
+ buf : & mut [ u8 ] ,
1551
+ value : & mut [ u8 ] ,
1552
+ ) -> Result < ( ) , io:: Error > {
1553
+ loop {
1554
+ let bytes_read = src. read ( buf) ?;
1555
+ if bytes_read == 0 {
1556
+ break ;
1557
+ }
1558
+ update ( & mut hasher, & buf[ 0 ..bytes_read] ) ;
1559
+ }
1560
+ finish ( hasher, value) ;
1561
+ Ok ( ( ) )
1562
+ }
1563
+
1564
+ match kind {
1565
+ SourceFileHashAlgorithm :: Sha256 => {
1566
+ digest (
1567
+ Sha256 :: new ( ) ,
1568
+ |h, b| {
1569
+ h. update ( b) ;
1570
+ } ,
1571
+ |h, out| out. copy_from_slice ( & h. finalize ( ) ) ,
1572
+ src,
1573
+ & mut buf,
1574
+ value,
1575
+ ) ?;
1576
+ }
1577
+ SourceFileHashAlgorithm :: Sha1 => {
1578
+ digest (
1579
+ Sha1 :: new ( ) ,
1580
+ |h, b| {
1581
+ h. update ( b) ;
1582
+ } ,
1583
+ |h, out| out. copy_from_slice ( & h. finalize ( ) ) ,
1584
+ src,
1585
+ & mut buf,
1586
+ value,
1587
+ ) ?;
1588
+ }
1589
+ SourceFileHashAlgorithm :: Md5 => {
1590
+ digest (
1591
+ Md5 :: new ( ) ,
1592
+ |h, b| {
1593
+ h. update ( b) ;
1594
+ } ,
1595
+ |h, out| out. copy_from_slice ( & h. finalize ( ) ) ,
1596
+ src,
1597
+ & mut buf,
1598
+ value,
1599
+ ) ?;
1600
+ }
1601
+ SourceFileHashAlgorithm :: Blake3 => {
1602
+ digest (
1603
+ blake3:: Hasher :: new ( ) ,
1604
+ |h, b| {
1605
+ h. update ( b) ;
1606
+ } ,
1607
+ |h, out| out. copy_from_slice ( h. finalize ( ) . as_bytes ( ) ) ,
1608
+ src,
1609
+ & mut buf,
1610
+ value,
1611
+ ) ?;
1612
+ }
1613
+ }
1614
+ Ok ( hash)
1615
+ }
1616
+
1502
1617
/// Check if the stored hash matches the hash of the string.
1503
1618
pub fn matches ( & self , src : & str ) -> bool {
1504
- Self :: new ( self . kind , src) == * self
1619
+ Self :: new_in_memory ( self . kind , src. as_bytes ( ) ) == * self
1505
1620
}
1506
1621
1507
1622
/// The bytes of the hash.
@@ -1514,7 +1629,7 @@ impl SourceFileHash {
1514
1629
match self . kind {
1515
1630
SourceFileHashAlgorithm :: Md5 => 16 ,
1516
1631
SourceFileHashAlgorithm :: Sha1 => 20 ,
1517
- SourceFileHashAlgorithm :: Sha256 => 32 ,
1632
+ SourceFileHashAlgorithm :: Sha256 | SourceFileHashAlgorithm :: Blake3 => 32 ,
1518
1633
}
1519
1634
}
1520
1635
}
@@ -1570,6 +1685,10 @@ pub struct SourceFile {
1570
1685
pub src : Option < Lrc < String > > ,
1571
1686
/// The source code's hash.
1572
1687
pub src_hash : SourceFileHash ,
1688
+ /// Used to enable cargo to use checksums to check if a crate is fresh rather
1689
+ /// than mtimes. This might be the same as `src_hash`, and if the requested algorithm
1690
+ /// is identical we won't compute it twice.
1691
+ pub checksum_hash : Option < SourceFileHash > ,
1573
1692
/// The external source code (used for external crates, which will have a `None`
1574
1693
/// value as `self.src`.
1575
1694
pub external_src : FreezeLock < ExternalSource > ,
@@ -1599,6 +1718,7 @@ impl Clone for SourceFile {
1599
1718
name : self . name . clone ( ) ,
1600
1719
src : self . src . clone ( ) ,
1601
1720
src_hash : self . src_hash ,
1721
+ checksum_hash : self . checksum_hash ,
1602
1722
external_src : self . external_src . clone ( ) ,
1603
1723
start_pos : self . start_pos ,
1604
1724
source_len : self . source_len ,
@@ -1616,6 +1736,7 @@ impl<S: SpanEncoder> Encodable<S> for SourceFile {
1616
1736
fn encode ( & self , s : & mut S ) {
1617
1737
self . name . encode ( s) ;
1618
1738
self . src_hash . encode ( s) ;
1739
+ self . checksum_hash . encode ( s) ;
1619
1740
// Do not encode `start_pos` as it's global state for this session.
1620
1741
self . source_len . encode ( s) ;
1621
1742
@@ -1690,6 +1811,7 @@ impl<D: SpanDecoder> Decodable<D> for SourceFile {
1690
1811
fn decode ( d : & mut D ) -> SourceFile {
1691
1812
let name: FileName = Decodable :: decode ( d) ;
1692
1813
let src_hash: SourceFileHash = Decodable :: decode ( d) ;
1814
+ let checksum_hash: Option < SourceFileHash > = Decodable :: decode ( d) ;
1693
1815
let source_len: RelativeBytePos = Decodable :: decode ( d) ;
1694
1816
let lines = {
1695
1817
let num_lines: u32 = Decodable :: decode ( d) ;
@@ -1716,6 +1838,7 @@ impl<D: SpanDecoder> Decodable<D> for SourceFile {
1716
1838
source_len,
1717
1839
src : None ,
1718
1840
src_hash,
1841
+ checksum_hash,
1719
1842
// Unused - the metadata decoder will construct
1720
1843
// a new SourceFile, filling in `external_src` properly
1721
1844
external_src : FreezeLock :: frozen ( ExternalSource :: Unneeded ) ,
@@ -1800,9 +1923,17 @@ impl SourceFile {
1800
1923
name : FileName ,
1801
1924
mut src : String ,
1802
1925
hash_kind : SourceFileHashAlgorithm ,
1926
+ checksum_hash_kind : Option < SourceFileHashAlgorithm > ,
1803
1927
) -> Result < Self , OffsetOverflowError > {
1804
1928
// Compute the file hash before any normalization.
1805
- let src_hash = SourceFileHash :: new ( hash_kind, & src) ;
1929
+ let src_hash = SourceFileHash :: new_in_memory ( hash_kind, src. as_bytes ( ) ) ;
1930
+ let checksum_hash = checksum_hash_kind. map ( |checksum_hash_kind| {
1931
+ if checksum_hash_kind == hash_kind {
1932
+ src_hash
1933
+ } else {
1934
+ SourceFileHash :: new_in_memory ( checksum_hash_kind, src. as_bytes ( ) )
1935
+ }
1936
+ } ) ;
1806
1937
let normalized_pos = normalize_src ( & mut src) ;
1807
1938
1808
1939
let stable_id = StableSourceFileId :: from_filename_in_current_crate ( & name) ;
@@ -1816,6 +1947,7 @@ impl SourceFile {
1816
1947
name,
1817
1948
src : Some ( Lrc :: new ( src) ) ,
1818
1949
src_hash,
1950
+ checksum_hash,
1819
1951
external_src : FreezeLock :: frozen ( ExternalSource :: Unneeded ) ,
1820
1952
start_pos : BytePos :: from_u32 ( 0 ) ,
1821
1953
source_len : RelativeBytePos :: from_u32 ( source_len) ,
0 commit comments