Skip to content

Commit c103add

Browse files
committed
a faster hash for ActivationsKey
1 parent 2f74b54 commit c103add

File tree

2 files changed

+54
-35
lines changed

2 files changed

+54
-35
lines changed

src/cargo/core/resolver/context.rs

Lines changed: 4 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
use super::dep_cache::RegistryQueryer;
22
use super::errors::ActivateResult;
3-
use super::types::{ConflictMap, ConflictReason, FeaturesSet, ResolveOpts};
3+
use super::types::{ActivationsKey, ConflictMap, ConflictReason, FeaturesSet, ResolveOpts};
44
use super::RequestedFeatures;
5-
use crate::core::{Dependency, PackageId, SourceId, Summary};
5+
use crate::core::{Dependency, PackageId, Summary};
66
use crate::util::interning::InternedString;
77
use crate::util::Graph;
88
use anyhow::format_err;
99
use std::collections::HashMap;
10-
use std::num::NonZeroU64;
1110
use tracing::debug;
1211

1312
// A `Context` is basically a bunch of local resolution information which is
@@ -39,39 +38,9 @@ pub type ContextAge = usize;
3938
/// By storing this in a hash map we ensure that there is only one
4039
/// semver compatible version of each crate.
4140
/// This all so stores the `ContextAge`.
42-
pub type ActivationsKey = (InternedString, SourceId, SemverCompatibility);
43-
4441
pub type Activations =
4542
im_rc::HashMap<ActivationsKey, (Summary, ContextAge), rustc_hash::FxBuildHasher>;
4643

47-
/// A type that represents when cargo treats two Versions as compatible.
48-
/// Versions `a` and `b` are compatible if their left-most nonzero digit is the
49-
/// same.
50-
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, PartialOrd, Ord)]
51-
pub enum SemverCompatibility {
52-
Major(NonZeroU64),
53-
Minor(NonZeroU64),
54-
Patch(u64),
55-
}
56-
57-
impl From<&semver::Version> for SemverCompatibility {
58-
fn from(ver: &semver::Version) -> Self {
59-
if let Some(m) = NonZeroU64::new(ver.major) {
60-
return SemverCompatibility::Major(m);
61-
}
62-
if let Some(m) = NonZeroU64::new(ver.minor) {
63-
return SemverCompatibility::Minor(m);
64-
}
65-
SemverCompatibility::Patch(ver.patch)
66-
}
67-
}
68-
69-
impl PackageId {
70-
pub fn as_activations_key(self) -> ActivationsKey {
71-
(self.name(), self.source_id(), self.version().into())
72-
}
73-
}
74-
7544
impl ResolverContext {
7645
pub fn new() -> ResolverContext {
7746
ResolverContext {
@@ -137,7 +106,8 @@ impl ResolverContext {
137106
// versions came from a `[patch]` source.
138107
if let Some((_, dep)) = parent {
139108
if dep.source_id() != id.source_id() {
140-
let key = (id.name(), dep.source_id(), id.version().into());
109+
let key =
110+
ActivationsKey::new(id.name(), id.version().into(), dep.source_id());
141111
let prev = self.activations.insert(key, (summary.clone(), age));
142112
if let Some((previous_summary, _)) = prev {
143113
return Err(

src/cargo/core/resolver/types.rs

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use super::features::{CliFeatures, RequestedFeatures};
2-
use crate::core::{Dependency, PackageId, Summary};
2+
use crate::core::{Dependency, PackageId, SourceId, Summary};
33
use crate::util::errors::CargoResult;
44
use crate::util::interning::InternedString;
55
use crate::util::GlobalContext;
66
use std::cmp::Ordering;
77
use std::collections::{BTreeMap, BTreeSet};
8+
use std::num::NonZeroU64;
89
use std::rc::Rc;
910
use std::time::{Duration, Instant};
1011

@@ -163,6 +164,54 @@ impl ResolveOpts {
163164
}
164165
}
165166

167+
/// A key that when stord in a hash map ensures that there is only one
168+
/// semver compatible version of each crate.
169+
/// Find the activated version of a crate based on the name, source, and semver compatibility.
170+
#[derive(Clone, PartialEq, Eq, Debug, Ord, PartialOrd)]
171+
pub struct ActivationsKey(InternedString, SemverCompatibility, SourceId);
172+
173+
impl ActivationsKey {
174+
pub fn new(name: InternedString, ver: SemverCompatibility, source_id: SourceId) -> ActivationsKey {
175+
ActivationsKey(name, ver, source_id)
176+
}
177+
}
178+
179+
impl std::hash::Hash for ActivationsKey {
180+
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
181+
std::ptr::NonNull::from(self.0.as_str()).hash(state);
182+
self.1.hash(state);
183+
// self.2.hash(state); // Packages that only differ by SourceId are rare enough to not be worth hashing
184+
}
185+
}
186+
187+
/// A type that represents when cargo treats two Versions as compatible.
188+
/// Versions `a` and `b` are compatible if their left-most nonzero digit is the
189+
/// same.
190+
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, PartialOrd, Ord)]
191+
pub enum SemverCompatibility {
192+
Major(NonZeroU64),
193+
Minor(NonZeroU64),
194+
Patch(u64),
195+
}
196+
197+
impl From<&semver::Version> for SemverCompatibility {
198+
fn from(ver: &semver::Version) -> Self {
199+
if let Some(m) = NonZeroU64::new(ver.major) {
200+
return SemverCompatibility::Major(m);
201+
}
202+
if let Some(m) = NonZeroU64::new(ver.minor) {
203+
return SemverCompatibility::Minor(m);
204+
}
205+
SemverCompatibility::Patch(ver.patch)
206+
}
207+
}
208+
209+
impl PackageId {
210+
pub fn as_activations_key(self) -> ActivationsKey {
211+
ActivationsKey(self.name(), self.version().into(), self.source_id())
212+
}
213+
}
214+
166215
#[derive(Clone)]
167216
pub struct DepsFrame {
168217
pub parent: Summary,

0 commit comments

Comments
 (0)