use std::sync::Arc;
use rustc_hash::{FxHashMap, FxHashSet};
use uv_distribution_types::{RequirementSource, ResolutionRecorder};
use uv_normalize::PackageName;
use uv_pep440::Version;
use crate::{DependencyMode, Manifest, ResolverEnvironment};
#[derive(Debug, Default, Clone)]
pub struct AllowedYanks {
versions: Arc<FxHashMap<PackageName, FxHashSet<Version>>>,
recorder: Option<ResolutionRecorder>,
}
impl AllowedYanks {
pub fn from_manifest(
manifest: &Manifest,
env: &ResolverEnvironment,
dependencies: DependencyMode,
) -> Self {
let mut allowed_yanks = FxHashMap::<PackageName, FxHashSet<Version>>::default();
for requirement in manifest.candidate_selection_requirements(env, dependencies) {
let RequirementSource::Registry { specifier, .. } = &requirement.source else {
continue;
};
let [specifier] = specifier.as_ref() else {
continue;
};
if matches!(
specifier.operator(),
uv_pep440::Operator::Equal | uv_pep440::Operator::ExactEqual
) {
allowed_yanks
.entry(requirement.name.clone())
.or_default()
.insert(specifier.version().clone());
}
}
for (name, preferences) in manifest.preferences.iter() {
allowed_yanks
.entry(name.clone())
.or_default()
.extend(preferences.map(|(.., version)| version.clone()));
}
Self {
versions: Arc::new(allowed_yanks),
recorder: manifest.recorder.clone(),
}
}
pub(crate) fn contains(&self, package_name: &PackageName, version: &Version) -> bool {
if let Some(recorder) = &self.recorder {
recorder.candidate_policy(package_name);
}
self.versions
.get(package_name)
.is_some_and(|versions| versions.contains(version))
}
}