Skip to content

Commit 90672e9

Browse files
committed
Incorporate [max] local version into VersionSmall (#8843)
## Summary See discussion in #8797.
1 parent a491503 commit 90672e9

File tree

4 files changed

+100
-56
lines changed

4 files changed

+100
-56
lines changed

crates/uv-cache/src/lib.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -773,16 +773,18 @@ pub enum CacheBucket {
773773
impl CacheBucket {
774774
fn to_str(self) -> &'static str {
775775
match self {
776-
Self::SourceDistributions => "sdists-v5",
777-
Self::FlatIndex => "flat-index-v1",
776+
// Note that when bumping this, you'll also need to bump it
777+
// in crates/uv/tests/cache_prune.rs.
778+
Self::SourceDistributions => "sdists-v6",
779+
Self::FlatIndex => "flat-index-v2",
778780
Self::Git => "git-v0",
779-
Self::Interpreter => "interpreter-v2",
781+
Self::Interpreter => "interpreter-v3",
780782
// Note that when bumping this, you'll also need to bump it
781783
// in crates/uv/tests/cache_clean.rs.
782-
Self::Simple => "simple-v13",
784+
Self::Simple => "simple-v14",
783785
// Note that when bumping this, you'll also need to bump it
784786
// in crates/uv/tests/cache_prune.rs.
785-
Self::Wheels => "wheels-v2",
787+
Self::Wheels => "wheels-v3",
786788
Self::Archive => "archive-v0",
787789
Self::Builds => "builds-v0",
788790
Self::Environments => "environments-v1",

crates/uv-pep440/src/version.rs

Lines changed: 89 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ impl Version {
390390
#[inline]
391391
pub fn local(&self) -> LocalVersionSlice {
392392
match *self.inner {
393-
VersionInner::Small { ref small } => small.local(),
393+
VersionInner::Small { ref small } => small.local_slice(),
394394
VersionInner::Full { ref full } => full.local.as_slice(),
395395
}
396396
}
@@ -546,6 +546,11 @@ impl Version {
546546
match value {
547547
LocalVersion::Segments(segments) => self.with_local_segments(segments),
548548
LocalVersion::Max => {
549+
if let VersionInner::Small { ref mut small } = Arc::make_mut(&mut self.inner) {
550+
if small.set_local(LocalVersion::Max) {
551+
return self;
552+
}
553+
}
549554
self.make_full().local = value;
550555
self
551556
}
@@ -559,12 +564,12 @@ impl Version {
559564
#[inline]
560565
#[must_use]
561566
pub fn without_local(mut self) -> Self {
562-
// A "small" version is already guaranteed not to have a local
563-
// component, so we only need to do anything if we have a "full"
564-
// version.
565-
if let VersionInner::Full { ref mut full } = Arc::make_mut(&mut self.inner) {
566-
full.local.clear();
567+
if let VersionInner::Small { ref mut small } = Arc::make_mut(&mut self.inner) {
568+
if small.set_local(LocalVersion::empty()) {
569+
return self;
570+
}
567571
}
572+
self.make_full().local = LocalVersion::empty();
568573
self
569574
}
570575

@@ -628,7 +633,7 @@ impl Version {
628633
pre: small.pre(),
629634
post: small.post(),
630635
dev: small.dev(),
631-
local: LocalVersion::Segments(vec![]),
636+
local: small.local(),
632637
};
633638
*self = Self {
634639
inner: Arc::new(VersionInner::Full { full }),
@@ -846,16 +851,16 @@ impl FromStr for Version {
846851
/// * Bytes 5, 4 and 3 correspond to the second, third and fourth release
847852
/// segments, respectively.
848853
/// * Bytes 2, 1 and 0 represent *one* of the following:
849-
/// `min, .devN, aN, bN, rcN, <no suffix>, .postN, max`.
854+
/// `min, .devN, aN, bN, rcN, <no suffix>, local, .postN, max`.
850855
/// Its representation is thus:
851-
/// * The most significant 3 bits of Byte 2 corresponds to a value in
852-
/// the range 0-7 inclusive, corresponding to min, dev, pre-a, pre-b,
856+
/// * The most significant 4 bits of Byte 2 corresponds to a value in
857+
/// the range 0-8 inclusive, corresponding to min, dev, pre-a, pre-b,
853858
/// pre-rc, no-suffix, post or max releases, respectively. `min` is a
854859
/// special version that does not exist in PEP 440, but is used here to
855860
/// represent the smallest possible version, preceding any `dev`, `pre`,
856861
/// `post` or releases. `max` is an analogous concept for the largest
857862
/// possible version, following any `post` or local releases.
858-
/// * The low 5 bits combined with the bits in bytes 1 and 0 correspond
863+
/// * The low 4 bits combined with the bits in bytes 1 and 0 correspond
859864
/// to the release number of the suffix, if one exists. If there is no
860865
/// suffix, then these bits are always 0.
861866
///
@@ -933,8 +938,9 @@ impl VersionSmall {
933938
const SUFFIX_PRE_BETA: u64 = 3;
934939
const SUFFIX_PRE_RC: u64 = 4;
935940
const SUFFIX_NONE: u64 = 5;
936-
const SUFFIX_POST: u64 = 6;
937-
const SUFFIX_MAX: u64 = 7;
941+
const SUFFIX_LOCAL: u64 = 6;
942+
const SUFFIX_POST: u64 = 7;
943+
const SUFFIX_MAX: u64 = 8;
938944

939945
// The mask to get only the release segment bits.
940946
//
@@ -943,16 +949,16 @@ impl VersionSmall {
943949
// `Parser::parse_fast`.
944950
const SUFFIX_RELEASE_MASK: u64 = 0xFFFF_FFFF_FF00_0000;
945951
// The mask to get the version suffix.
946-
const SUFFIX_VERSION_MASK: u64 = 0x001F_FFFF;
952+
const SUFFIX_VERSION_MASK: u64 = 0x000F_FFFF;
947953
// The number of bits used by the version suffix. Shifting the `repr`
948954
// right by this number of bits should put the suffix kind in the least
949955
// significant bits.
950-
const SUFFIX_VERSION_BIT_LEN: u64 = 21;
956+
const SUFFIX_VERSION_BIT_LEN: u64 = 20;
951957
// The mask to get only the suffix kind, after shifting right by the
952958
// version bits. If you need to add a bit here, then you'll probably need
953959
// to take a bit from the suffix version. (Which requires a change to both
954960
// the mask and the bit length above.)
955-
const SUFFIX_KIND_MASK: u64 = 0b111;
961+
const SUFFIX_KIND_MASK: u64 = 0b1111;
956962

957963
#[inline]
958964
fn new() -> Self {
@@ -1026,11 +1032,8 @@ impl VersionSmall {
10261032

10271033
#[inline]
10281034
fn set_post(&mut self, value: Option<u64>) -> bool {
1029-
if self.min().is_some()
1030-
|| self.pre().is_some()
1031-
|| self.dev().is_some()
1032-
|| self.max().is_some()
1033-
{
1035+
let suffix_kind = self.suffix_kind();
1036+
if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_POST) {
10341037
return value.is_none();
10351038
}
10361039
match value {
@@ -1073,10 +1076,11 @@ impl VersionSmall {
10731076

10741077
#[inline]
10751078
fn set_pre(&mut self, value: Option<Prerelease>) -> bool {
1076-
if self.min().is_some()
1077-
|| self.dev().is_some()
1078-
|| self.post().is_some()
1079-
|| self.max().is_some()
1079+
let suffix_kind = self.suffix_kind();
1080+
if !(suffix_kind == Self::SUFFIX_NONE
1081+
|| suffix_kind == Self::SUFFIX_PRE_ALPHA
1082+
|| suffix_kind == Self::SUFFIX_PRE_BETA
1083+
|| suffix_kind == Self::SUFFIX_PRE_RC)
10801084
{
10811085
return value.is_none();
10821086
}
@@ -1116,11 +1120,8 @@ impl VersionSmall {
11161120

11171121
#[inline]
11181122
fn set_dev(&mut self, value: Option<u64>) -> bool {
1119-
if self.min().is_some()
1120-
|| self.pre().is_some()
1121-
|| self.post().is_some()
1122-
|| self.max().is_some()
1123-
{
1123+
let suffix_kind = self.suffix_kind();
1124+
if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_DEV) {
11241125
return value.is_none();
11251126
}
11261127
match value {
@@ -1149,11 +1150,8 @@ impl VersionSmall {
11491150

11501151
#[inline]
11511152
fn set_min(&mut self, value: Option<u64>) -> bool {
1152-
if self.dev().is_some()
1153-
|| self.pre().is_some()
1154-
|| self.post().is_some()
1155-
|| self.max().is_some()
1156-
{
1153+
let suffix_kind = self.suffix_kind();
1154+
if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_MIN) {
11571155
return value.is_none();
11581156
}
11591157
match value {
@@ -1182,11 +1180,8 @@ impl VersionSmall {
11821180

11831181
#[inline]
11841182
fn set_max(&mut self, value: Option<u64>) -> bool {
1185-
if self.dev().is_some()
1186-
|| self.pre().is_some()
1187-
|| self.post().is_some()
1188-
|| self.min().is_some()
1189-
{
1183+
let suffix_kind = self.suffix_kind();
1184+
if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_MAX) {
11901185
return value.is_none();
11911186
}
11921187
match value {
@@ -1205,11 +1200,40 @@ impl VersionSmall {
12051200
}
12061201

12071202
#[inline]
1208-
#[allow(clippy::unused_self)]
1209-
fn local(&self) -> LocalVersionSlice {
1210-
// A "small" version is never used if the version has a non-zero number
1211-
// of local segments.
1212-
LocalVersionSlice::Segments(&[])
1203+
fn local(&self) -> LocalVersion {
1204+
if self.suffix_kind() == Self::SUFFIX_LOCAL {
1205+
LocalVersion::Max
1206+
} else {
1207+
LocalVersion::empty()
1208+
}
1209+
}
1210+
1211+
#[inline]
1212+
fn local_slice(&self) -> LocalVersionSlice {
1213+
if self.suffix_kind() == Self::SUFFIX_LOCAL {
1214+
LocalVersionSlice::Max
1215+
} else {
1216+
LocalVersionSlice::empty()
1217+
}
1218+
}
1219+
1220+
#[inline]
1221+
fn set_local(&mut self, value: LocalVersion) -> bool {
1222+
let suffix_kind = self.suffix_kind();
1223+
if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_LOCAL) {
1224+
return value.is_empty();
1225+
}
1226+
match value {
1227+
LocalVersion::Max => {
1228+
self.set_suffix_kind(Self::SUFFIX_LOCAL);
1229+
true
1230+
}
1231+
LocalVersion::Segments(segments) if segments.is_empty() => {
1232+
self.set_suffix_kind(Self::SUFFIX_NONE);
1233+
true
1234+
}
1235+
LocalVersion::Segments(_) => false,
1236+
}
12131237
}
12141238

12151239
#[inline]
@@ -1224,7 +1248,7 @@ impl VersionSmall {
12241248
debug_assert!(kind <= Self::SUFFIX_MAX);
12251249
self.repr &= !(Self::SUFFIX_KIND_MASK << Self::SUFFIX_VERSION_BIT_LEN);
12261250
self.repr |= kind << Self::SUFFIX_VERSION_BIT_LEN;
1227-
if kind == Self::SUFFIX_NONE {
1251+
if kind == Self::SUFFIX_NONE || kind == Self::SUFFIX_LOCAL {
12281252
self.set_suffix_version(0);
12291253
}
12301254
}
@@ -1450,6 +1474,19 @@ pub enum LocalVersionSlice<'a> {
14501474
}
14511475

14521476
impl LocalVersion {
1477+
/// Return an empty local version.
1478+
pub fn empty() -> Self {
1479+
Self::Segments(Vec::new())
1480+
}
1481+
1482+
/// Returns `true` if the local version is empty.
1483+
pub fn is_empty(&self) -> bool {
1484+
match self {
1485+
Self::Segments(segments) => segments.is_empty(),
1486+
Self::Max => false,
1487+
}
1488+
}
1489+
14531490
/// Convert the local version segments into a slice.
14541491
pub fn as_slice(&self) -> LocalVersionSlice<'_> {
14551492
match self {
@@ -1506,7 +1543,12 @@ impl Ord for LocalVersionSlice<'_> {
15061543
}
15071544

15081545
impl LocalVersionSlice<'_> {
1509-
/// Whether the local version is absent
1546+
/// Return an empty local version.
1547+
pub const fn empty() -> Self {
1548+
Self::Segments(&[])
1549+
}
1550+
1551+
/// Returns `true` if the local version is empty.
15101552
pub fn is_empty(&self) -> bool {
15111553
matches!(self, Self::Segments(&[]))
15121554
}

crates/uv/tests/it/cache_clean.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ fn clean_package_pypi() -> Result<()> {
5151
// Assert that the `.rkyv` file is created for `iniconfig`.
5252
let rkyv = context
5353
.cache_dir
54-
.child("simple-v13")
54+
.child("simple-v14")
5555
.child("pypi")
5656
.child("iniconfig.rkyv");
5757
assert!(
@@ -123,7 +123,7 @@ fn clean_package_index() -> Result<()> {
123123
// Assert that the `.rkyv` file is created for `iniconfig`.
124124
let rkyv = context
125125
.cache_dir
126-
.child("simple-v13")
126+
.child("simple-v14")
127127
.child("index")
128128
.child("e8208120cae3ba69")
129129
.child("iniconfig.rkyv");

crates/uv/tests/it/cache_prune.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ fn prune_stale_symlink() -> Result<()> {
140140
.success();
141141

142142
// Remove the wheels directory, causing the symlink to become stale.
143-
let wheels = context.cache_dir.child("wheels-v2");
143+
let wheels = context.cache_dir.child("wheels-v3");
144144
fs_err::remove_dir_all(wheels)?;
145145

146146
let filters: Vec<_> = context
@@ -328,7 +328,7 @@ fn prune_stale_revision() -> Result<()> {
328328
----- stderr -----
329329
DEBUG uv [VERSION] ([COMMIT] DATE)
330330
Pruning cache at: [CACHE_DIR]/
331-
DEBUG Removing dangling source revision: [CACHE_DIR]/sdists-v5/[ENTRY]
331+
DEBUG Removing dangling source revision: [CACHE_DIR]/sdists-v6/[ENTRY]
332332
DEBUG Removing dangling cache archive: [CACHE_DIR]/archive-v0/[ENTRY]
333333
Removed 8 files ([SIZE])
334334
"###);

0 commit comments

Comments
 (0)