chore: Remove dep on derivative (#7133)

(This is part of #5711)

## Summary

@BurntSushi and I spotted that the `derivative` crate is only used for
one enum in the entire codebase — however, it's a proc macro, and we pay
for the cost of (re)compiling it in many different contexts.

This replaces it with a private `Inner` core which uses the regular std
derive macros — inlining and optimizations should make this equivalent
to the other implementation, and not too hard to maintain hopefully
(versus a manual impl of `PartialEq` and `Hash` which have to be kept in
sync.)

## Test Plan

Trust CI?
This commit is contained in:
Amos Wenger 2024-09-06 23:46:56 +02:00 committed by GitHub
parent 22c0be6664
commit 5e1b9b1964
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 117 additions and 31 deletions

12
Cargo.lock generated
View File

@ -968,17 +968,6 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b" checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b"
[[package]]
name = "derivative"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]] [[package]]
name = "diff" name = "diff"
version = "0.1.13" version = "0.1.13"
@ -5048,7 +5037,6 @@ dependencies = [
"cache-key", "cache-key",
"clap", "clap",
"dashmap", "dashmap",
"derivative",
"distribution-filename", "distribution-filename",
"distribution-types", "distribution-types",
"either", "either",

View File

@ -78,7 +78,6 @@ csv = { version = "1.3.0" }
ctrlc = { version = "3.4.4" } ctrlc = { version = "3.4.4" }
dashmap = { version = "6.0.0" } dashmap = { version = "6.0.0" }
data-encoding = { version = "2.5.0" } data-encoding = { version = "2.5.0" }
derivative = { version = "2.2.0" }
directories = { version = "5.0.1" } directories = { version = "5.0.1" }
dirs-sys = { version = "0.4.1" } dirs-sys = { version = "0.4.1" }
dunce = { version = "1.0.4" } dunce = { version = "1.0.4" }

View File

@ -38,7 +38,6 @@ uv-workspace = { workspace = true }
anyhow = { workspace = true } anyhow = { workspace = true }
clap = { workspace = true, features = ["derive"], optional = true } clap = { workspace = true, features = ["derive"], optional = true }
dashmap = { workspace = true } dashmap = { workspace = true }
derivative = { workspace = true }
either = { workspace = true } either = { workspace = true }
futures = { workspace = true } futures = { workspace = true }
indexmap = { workspace = true } indexmap = { workspace = true }

View File

@ -3,7 +3,6 @@ use std::cmp::Ordering;
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
use std::ops::Bound; use std::ops::Bound;
use derivative::Derivative;
use indexmap::IndexSet; use indexmap::IndexSet;
use owo_colors::OwoColorize; use owo_colors::OwoColorize;
use pubgrub::{DerivationTree, Derived, External, Map, Range, ReportFormatter, Term}; use pubgrub::{DerivationTree, Derived, External, Map, Range, ReportFormatter, Term};
@ -719,22 +718,21 @@ impl PubGrubReportFormatter<'_> {
} }
} }
#[derive(Derivative, Debug, Clone)] #[derive(Debug, Clone)]
#[derivative(Hash, PartialEq, Eq)]
pub(crate) enum PubGrubHint { pub(crate) enum PubGrubHint {
/// There are pre-release versions available for a package, but pre-releases weren't enabled /// There are pre-release versions available for a package, but pre-releases weren't enabled
/// for that package. /// for that package.
/// ///
PrereleaseAvailable { PrereleaseAvailable {
package: PubGrubPackage, package: PubGrubPackage,
#[derivative(PartialEq = "ignore", Hash = "ignore")] // excluded from `PartialEq` and `Hash`
version: Version, version: Version,
}, },
/// A requirement included a pre-release marker, but pre-releases weren't enabled for that /// A requirement included a pre-release marker, but pre-releases weren't enabled for that
/// package. /// package.
PrereleaseRequested { PrereleaseRequested {
package: PubGrubPackage, package: PubGrubPackage,
#[derivative(PartialEq = "ignore", Hash = "ignore")] // excluded from `PartialEq` and `Hash`
range: Range<Version>, range: Range<Version>,
}, },
/// Requirements were unavailable due to lookups in the index being disabled and no extra /// Requirements were unavailable due to lookups in the index being disabled and no extra
@ -747,59 +745,161 @@ pub(crate) enum PubGrubHint {
/// Metadata for a package could not be parsed. /// Metadata for a package could not be parsed.
InvalidPackageMetadata { InvalidPackageMetadata {
package: PubGrubPackage, package: PubGrubPackage,
#[derivative(PartialEq = "ignore", Hash = "ignore")] // excluded from `PartialEq` and `Hash`
reason: String, reason: String,
}, },
/// The structure of a package was invalid (e.g., multiple `.dist-info` directories). /// The structure of a package was invalid (e.g., multiple `.dist-info` directories).
InvalidPackageStructure { InvalidPackageStructure {
package: PubGrubPackage, package: PubGrubPackage,
#[derivative(PartialEq = "ignore", Hash = "ignore")] // excluded from `PartialEq` and `Hash`
reason: String, reason: String,
}, },
/// Metadata for a package version could not be found. /// Metadata for a package version could not be found.
MissingVersionMetadata { MissingVersionMetadata {
package: PubGrubPackage, package: PubGrubPackage,
#[derivative(PartialEq = "ignore", Hash = "ignore")] // excluded from `PartialEq` and `Hash`
version: Version, version: Version,
}, },
/// Metadata for a package version could not be parsed. /// Metadata for a package version could not be parsed.
InvalidVersionMetadata { InvalidVersionMetadata {
package: PubGrubPackage, package: PubGrubPackage,
#[derivative(PartialEq = "ignore", Hash = "ignore")] // excluded from `PartialEq` and `Hash`
version: Version, version: Version,
#[derivative(PartialEq = "ignore", Hash = "ignore")] // excluded from `PartialEq` and `Hash`
reason: String, reason: String,
}, },
/// Metadata for a package version was inconsistent (e.g., the package name did not match that /// Metadata for a package version was inconsistent (e.g., the package name did not match that
/// of the file). /// of the file).
InconsistentVersionMetadata { InconsistentVersionMetadata {
package: PubGrubPackage, package: PubGrubPackage,
#[derivative(PartialEq = "ignore", Hash = "ignore")] // excluded from `PartialEq` and `Hash`
version: Version, version: Version,
#[derivative(PartialEq = "ignore", Hash = "ignore")] // excluded from `PartialEq` and `Hash`
reason: String, reason: String,
}, },
/// The structure of a package version was invalid (e.g., multiple `.dist-info` directories). /// The structure of a package version was invalid (e.g., multiple `.dist-info` directories).
InvalidVersionStructure { InvalidVersionStructure {
package: PubGrubPackage, package: PubGrubPackage,
#[derivative(PartialEq = "ignore", Hash = "ignore")] // excluded from `PartialEq` and `Hash`
version: Version, version: Version,
#[derivative(PartialEq = "ignore", Hash = "ignore")] // excluded from `PartialEq` and `Hash`
reason: String, reason: String,
}, },
/// The `Requires-Python` requirement was not satisfied. /// The `Requires-Python` requirement was not satisfied.
RequiresPython { RequiresPython {
source: PythonRequirementSource, source: PythonRequirementSource,
requires_python: RequiresPython, requires_python: RequiresPython,
#[derivative(PartialEq = "ignore", Hash = "ignore")] // excluded from `PartialEq` and `Hash`
package: PubGrubPackage, package: PubGrubPackage,
#[derivative(PartialEq = "ignore", Hash = "ignore")] // excluded from `PartialEq` and `Hash`
package_set: Range<Version>, package_set: Range<Version>,
#[derivative(PartialEq = "ignore", Hash = "ignore")] // excluded from `PartialEq` and `Hash`
package_requires_python: Range<Version>, package_requires_python: Range<Version>,
}, },
} }
/// This private enum mirrors [`PubGrubHint`] but only includes fields that should be
/// used for `Eq` and `Hash` implementations. It is used to derive `PartialEq` and
/// `Hash` implementations for [`PubGrubHint`].
#[derive(PartialEq, Eq, Hash)]
enum PubGrubHintCore {
PrereleaseAvailable {
package: PubGrubPackage,
},
PrereleaseRequested {
package: PubGrubPackage,
},
NoIndex,
Offline,
MissingPackageMetadata {
package: PubGrubPackage,
},
InvalidPackageMetadata {
package: PubGrubPackage,
},
InvalidPackageStructure {
package: PubGrubPackage,
},
MissingVersionMetadata {
package: PubGrubPackage,
},
InvalidVersionMetadata {
package: PubGrubPackage,
},
InconsistentVersionMetadata {
package: PubGrubPackage,
},
InvalidVersionStructure {
package: PubGrubPackage,
},
RequiresPython {
source: PythonRequirementSource,
requires_python: RequiresPython,
},
}
impl From<PubGrubHint> for PubGrubHintCore {
#[inline]
fn from(hint: PubGrubHint) -> Self {
match hint {
PubGrubHint::PrereleaseAvailable { package, .. } => {
Self::PrereleaseAvailable { package }
}
PubGrubHint::PrereleaseRequested { package, .. } => {
Self::PrereleaseRequested { package }
}
PubGrubHint::NoIndex => Self::NoIndex,
PubGrubHint::Offline => Self::Offline,
PubGrubHint::MissingPackageMetadata { package, .. } => {
Self::MissingPackageMetadata { package }
}
PubGrubHint::InvalidPackageMetadata { package, .. } => {
Self::InvalidPackageMetadata { package }
}
PubGrubHint::InvalidPackageStructure { package, .. } => {
Self::InvalidPackageStructure { package }
}
PubGrubHint::MissingVersionMetadata { package, .. } => {
Self::MissingVersionMetadata { package }
}
PubGrubHint::InvalidVersionMetadata { package, .. } => {
Self::InvalidVersionMetadata { package }
}
PubGrubHint::InconsistentVersionMetadata { package, .. } => {
Self::InconsistentVersionMetadata { package }
}
PubGrubHint::InvalidVersionStructure { package, .. } => {
Self::InvalidVersionStructure { package }
}
PubGrubHint::RequiresPython {
source,
requires_python,
..
} => Self::RequiresPython {
source,
requires_python,
},
}
}
}
impl std::hash::Hash for PubGrubHint {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let core = PubGrubHintCore::from(self.clone());
core.hash(state);
}
}
impl PartialEq for PubGrubHint {
fn eq(&self, other: &Self) -> bool {
let core = PubGrubHintCore::from(self.clone());
let other_core = PubGrubHintCore::from(other.clone());
core == other_core
}
}
impl Eq for PubGrubHint {}
impl std::fmt::Display for PubGrubHint { impl std::fmt::Display for PubGrubHint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {