Skip to content

Commit 1b5684f

Browse files
committed
remove unnecessary unsafe code
1 parent 6f5b12a commit 1b5684f

File tree

2 files changed

+26
-35
lines changed

2 files changed

+26
-35
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ serde_json = "1"
3737
bstr = "1.0.1"
3838
thiserror = "1.0.32"
3939
ahash = "0.8.0"
40+
hashbrown = { version = "0.13.1", features = ["raw"] }
4041

4142
[dev-dependencies]
4243
git-testtools = "0.9.0"

src/index/diff/delegate.rs

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,14 @@
11
use crate::index::diff::Error;
22
use crate::{Change, CrateVersion};
3-
use ahash::AHashSet;
3+
use ahash::{AHashSet, RandomState};
44
use bstr::BStr;
55
use git_repository as git;
6-
use std::hash::Hash;
7-
8-
#[repr(transparent)]
9-
struct ChecksumWithVersion(CrateVersion);
10-
11-
impl AsRef<ChecksumWithVersion> for CrateVersion {
12-
fn as_ref(&self) -> &ChecksumWithVersion {
13-
// Safety: this is safe because ChecksumWithVersion is just a repr[transparent] wrapper around CrateVersion
14-
unsafe { &*(self as *const CrateVersion as *const ChecksumWithVersion) }
15-
}
16-
}
17-
impl Hash for ChecksumWithVersion {
18-
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
19-
self.0.checksum.hash(state)
20-
}
21-
}
22-
23-
impl PartialEq for ChecksumWithVersion {
24-
fn eq(&self, other: &Self) -> bool {
25-
self.0.checksum == other.0.checksum
26-
}
27-
}
28-
impl Eq for ChecksumWithVersion {}
6+
use hashbrown::raw::RawTable;
297

308
#[derive(Default)]
319
pub(crate) struct Delegate {
3210
changes: Vec<Change>,
3311
err: Option<Error>,
34-
temporary_line_map: AHashSet<&'static [u8]>,
35-
temporary_version_map: AHashSet<ChecksumWithVersion>,
3612
}
3713

3814
impl Delegate {
@@ -85,32 +61,46 @@ impl Delegate {
8561
}
8662
Modification { .. } => {
8763
if let Some(diff) = change.event.diff().transpose()? {
64+
let mut old_lines = AHashSet::with_capacity(1024);
8865
let location = change.location;
8966
for line in diff.old.data.lines() {
9067
// Safety: We transform an &'_ [u8] to and &'static [u8] here
9168
// this is safe because we always drain the hashmap at the end of the function
9269
// the reason the HashMap has a static is that we want to reuse
9370
// the allocation for modifications
94-
self.temporary_line_map
95-
.insert(unsafe { &*(line as *const [u8]) });
71+
old_lines.insert(line);
9672
}
9773

74+
// A RawTable is used to represent a Checksum -> CrateVersion map
75+
// because the checksum is already stored in the CrateVersion
76+
// and we want to avoid storing the checksum twice for performance reasons
77+
let mut new_versions = RawTable::with_capacity(old_lines.len().min(1024));
78+
let hasher = RandomState::new();
79+
9880
for line in diff.new.data.lines() {
9981
// first quickly check if the exact same line is already present in this file in that case we don't need to do anything else
100-
if self.temporary_line_map.remove(line) {
82+
if old_lines.remove(line) {
10183
continue;
10284
}
85+
// no need to check if the checksum already exists in the hashmap
86+
// as each checksum appear only once
10387
let new_version = version_from_json_line(line, location)?;
104-
self.temporary_version_map
105-
.insert(ChecksumWithVersion(new_version));
88+
new_versions.insert(
89+
hasher.hash_one(new_version.checksum),
90+
new_version,
91+
|rehashed| hasher.hash_one(rehashed.checksum),
92+
);
10693
}
10794

10895
let mut deleted = Vec::new();
109-
for line in self.temporary_line_map.drain() {
96+
for line in old_lines.drain() {
11097
let old_version = version_from_json_line(line, location)?;
111-
let new_version = self.temporary_version_map.take(old_version.as_ref());
98+
let new_version = new_versions
99+
.remove_entry(hasher.hash_one(old_version.checksum), |version| {
100+
version.checksum == old_version.checksum
101+
});
112102
match new_version {
113-
Some(ChecksumWithVersion(new_version)) => {
103+
Some(new_version) => {
114104
let change = match (old_version.yanked, new_version.yanked) {
115105
(true, false) => Change::Unyanked(new_version),
116106
(false, true) => Change::Yanked(new_version),
@@ -127,7 +117,7 @@ impl Delegate {
127117
versions: deleted,
128118
})
129119
}
130-
for ChecksumWithVersion(version) in self.temporary_version_map.drain() {
120+
for version in new_versions.drain() {
131121
let change = if version.yanked {
132122
Change::AddedAndYanked(version)
133123
} else {

0 commit comments

Comments
 (0)