use std::collections::hash_map::Entry;
use rustc_hash::FxHashMap;
use uv_distribution_types::{CompatibleDist, DistributionId, Identifier, ResolvedDist};
use uv_normalize::PackageName;
use uv_pep440::Version;
use crate::ResolveError;
use crate::candidate_selector::Candidate;
use crate::resolver::RegisteredMetadata;
#[derive(Clone, Debug)]
enum FilePin<'index> {
Registry {
dist: ResolvedDist,
metadata: PinMetadata<'index>,
},
Url(RegisteredMetadata<'index>),
}
#[derive(Clone, Debug)]
enum PinMetadata<'index> {
Unrequested(DistributionId),
Registered(RegisteredMetadata<'index>),
}
#[derive(Clone, Debug, Default)]
pub(crate) struct FilePins<'index>(FxHashMap<(PackageName, Version), FilePin<'index>>);
impl<'index> FilePins<'index> {
pub(crate) fn insert(
&mut self,
candidate: &Candidate,
dist: &CompatibleDist,
request: Option<impl FnOnce() -> Result<RegisteredMetadata<'index>, ResolveError>>,
) -> Result<(), ResolveError> {
match self
.0
.entry((candidate.name().clone(), candidate.version().clone()))
{
Entry::Occupied(mut entry) => {
if let Some(request) = request
&& let FilePin::Registry {
metadata: metadata @ PinMetadata::Unrequested(_),
..
} = entry.get_mut()
{
*metadata = PinMetadata::Registered(request()?);
}
}
Entry::Vacant(entry) => {
let metadata = if let Some(request) = request {
PinMetadata::Registered(request()?)
} else {
PinMetadata::Unrequested(dist.for_resolution().distribution_id())
};
entry.insert(FilePin::Registry {
dist: dist.for_installation().to_owned(),
metadata,
});
}
}
Ok(())
}
pub(crate) fn insert_url(
&mut self,
name: &PackageName,
version: &Version,
metadata: RegisteredMetadata<'index>,
) {
self.0
.entry((name.clone(), version.clone()))
.or_insert(FilePin::Url(metadata));
}
pub(crate) fn get(&self, name: &PackageName, version: &Version) -> Option<&ResolvedDist> {
match self.0.get(&(name.clone(), version.clone()))? {
FilePin::Registry { dist, .. } => Some(dist),
FilePin::Url(_) => None,
}
}
pub(crate) fn metadata(
&self,
name: &PackageName,
version: &Version,
) -> Option<&RegisteredMetadata<'index>> {
match self.0.get(&(name.clone(), version.clone()))? {
FilePin::Registry {
metadata: PinMetadata::Registered(metadata),
..
}
| FilePin::Url(metadata) => Some(metadata),
FilePin::Registry {
metadata: PinMetadata::Unrequested(_),
..
} => None,
}
}
pub(crate) fn dist_and_id(
&self,
name: &PackageName,
version: &Version,
) -> Option<(&ResolvedDist, &DistributionId)> {
match self.0.get(&(name.clone(), version.clone()))? {
FilePin::Registry { dist, metadata } => Some((
dist,
match metadata {
PinMetadata::Unrequested(id) => id,
PinMetadata::Registered(metadata) => metadata.id(),
},
)),
FilePin::Url(_) => None,
}
}
}