mirror of
https://github.com/astral-sh/uv.git
synced 2025-11-03 21:23:54 +00:00
puffin-resolver: make VersionMap::iter even lazier
This rollbacks the optimization in the previous commit to be more general. That is, instead of specializing the case of a range for a singleton version, we make iteration over the distributions in a `VersionMap` more explicitly lazy. Iteration now provides a `Version` (like it did previously) and a _handle_ to a distribution that can be turned into a `ResolvableDist`. Doing things this way permits callers to iterate over the versions and only materialize a distribution if they actually need one. In cases like candidate selection, one can often rule out use of a distribution through its version alone, and thus skip construction of that distribution entirely.
This commit is contained in:
parent
ed000d0dd5
commit
94437175c7
2 changed files with 73 additions and 28 deletions
|
|
@ -126,15 +126,27 @@ impl VersionMap {
|
|||
}
|
||||
|
||||
/// Return an iterator over the versions and distributions.
|
||||
pub(crate) fn iter(&self) -> impl DoubleEndedIterator<Item = (&Version, ResolvableDist)> {
|
||||
///
|
||||
/// Note that the value returned in this iterator is a [`VersionMapDist`],
|
||||
/// which can be used to lazily request a [`ResolvableDist`]. This is
|
||||
/// useful in cases where one can skip materializing a full distribution
|
||||
/// for each version.
|
||||
pub(crate) fn iter(&self) -> impl DoubleEndedIterator<Item = (&Version, VersionMapDistHandle)> {
|
||||
match self.inner {
|
||||
VersionMapInner::Eager { ref map } => either::Either::Left(
|
||||
map.iter()
|
||||
.filter_map(|(version, dist)| Some((version, dist.get()?))),
|
||||
),
|
||||
VersionMapInner::Eager(ref map) => {
|
||||
either::Either::Left(map.iter().map(|(version, dist)| {
|
||||
let version_map_dist = VersionMapDistHandle {
|
||||
inner: VersionMapDistHandleInner::Eager(dist),
|
||||
};
|
||||
(version, version_map_dist)
|
||||
}))
|
||||
}
|
||||
VersionMapInner::Lazy(ref lazy) => {
|
||||
either::Either::Right(lazy.map.iter().filter_map(|(version, lazy_dist)| {
|
||||
Some((version, lazy.get_lazy(lazy_dist)?.get()?))
|
||||
either::Either::Right(lazy.map.iter().map(|(version, dist)| {
|
||||
let version_map_dist = VersionMapDistHandle {
|
||||
inner: VersionMapDistHandleInner::Lazy { lazy, dist },
|
||||
};
|
||||
(version, version_map_dist)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
@ -155,6 +167,9 @@ impl VersionMap {
|
|||
}
|
||||
|
||||
/// Returns the total number of distinct versions in this map.
|
||||
///
|
||||
/// Note that this may include versions of distributions that are not
|
||||
/// usable in the current environment.
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
match self.inner {
|
||||
VersionMapInner::Eager(ref map) => map.len(),
|
||||
|
|
@ -171,6 +186,40 @@ impl From<FlatDistributions> for VersionMap {
|
|||
}
|
||||
}
|
||||
|
||||
/// A lazily initialized distribution.
|
||||
///
|
||||
/// This permits access to a handle that can be turned into a resolvable
|
||||
/// distribution when desired. This is coupled with a `Version` in
|
||||
/// [`VersionMap::iter`] to permit iteration over all items in a map without
|
||||
/// necessarily constructing a distribution for every version if it isn't
|
||||
/// needed.
|
||||
///
|
||||
/// Note that because of laziness, not all such items can be turned into
|
||||
/// a valid distribution. For example, if in the process of building a
|
||||
/// distribution no compatible wheel or source distribution could be found,
|
||||
/// then building a `ResolvableDist` will fail.
|
||||
pub(crate) struct VersionMapDistHandle<'a> {
|
||||
inner: VersionMapDistHandleInner<'a>,
|
||||
}
|
||||
|
||||
enum VersionMapDistHandleInner<'a> {
|
||||
Eager(&'a PrioritizedDistribution),
|
||||
Lazy {
|
||||
lazy: &'a VersionMapLazy,
|
||||
dist: &'a LazyPrioritizedDistribution,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> VersionMapDistHandle<'a> {
|
||||
/// Returns a resolvable distribution from this handle.
|
||||
pub(crate) fn resolvable_dist(&self) -> Option<ResolvableDist<'a>> {
|
||||
match self.inner {
|
||||
VersionMapDistHandleInner::Eager(dist) => dist.get(),
|
||||
VersionMapDistHandleInner::Lazy { lazy, dist } => Some(lazy.get_lazy(dist)?.get()?),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The kind of internal version map we have.
|
||||
#[derive(Debug)]
|
||||
enum VersionMapInner {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue