@@ -388,10 +388,10 @@ impl Version {
388
388
389
389
/// Returns the local segments in this version, if any exist.
390
390
#[ inline]
391
- pub fn local ( & self ) -> & [ LocalSegment ] {
391
+ pub fn local ( & self ) -> LocalVersionSlice {
392
392
match * self . inner {
393
393
VersionInner :: Small { ref small } => small. local ( ) ,
394
- VersionInner :: Full { ref full } => & full. local ,
394
+ VersionInner :: Full { ref full } => full. local . as_slice ( ) ,
395
395
}
396
396
}
397
397
@@ -530,15 +530,28 @@ impl Version {
530
530
/// Set the local segments and return the updated version.
531
531
#[ inline]
532
532
#[ must_use]
533
- pub fn with_local ( mut self , value : Vec < LocalSegment > ) -> Self {
533
+ pub fn with_local_segments ( mut self , value : Vec < LocalSegment > ) -> Self {
534
534
if value. is_empty ( ) {
535
535
self . without_local ( )
536
536
} else {
537
- self . make_full ( ) . local = value;
537
+ self . make_full ( ) . local = LocalVersion :: Actual ( value) ;
538
538
self
539
539
}
540
540
}
541
541
542
+ /// Set the local version and return the updated version.
543
+ #[ inline]
544
+ #[ must_use]
545
+ pub fn with_local ( mut self , value : LocalVersion ) -> Self {
546
+ match value {
547
+ LocalVersion :: Actual ( segments) => self . with_local_segments ( segments) ,
548
+ LocalVersion :: Max => {
549
+ self . make_full ( ) . local = value;
550
+ self
551
+ }
552
+ }
553
+ }
554
+
542
555
/// For PEP 440 specifier matching: "Except where specifically noted below,
543
556
/// local version identifiers MUST NOT be permitted in version specifiers,
544
557
/// and local version labels MUST be ignored entirely when checking if
@@ -615,7 +628,7 @@ impl Version {
615
628
pre : small. pre ( ) ,
616
629
post : small. post ( ) ,
617
630
dev : small. dev ( ) ,
618
- local : vec ! [ ] ,
631
+ local : LocalVersion :: Actual ( vec ! [ ] ) ,
619
632
} ;
620
633
* self = Self {
621
634
inner : Arc :: new ( VersionInner :: Full { full } ) ,
@@ -714,11 +727,14 @@ impl std::fmt::Display for Version {
714
727
} else {
715
728
format ! (
716
729
"+{}" ,
717
- self . local( )
718
- . iter( )
719
- . map( ToString :: to_string)
720
- . collect:: <Vec <String >>( )
721
- . join( "." )
730
+ match self . local( ) {
731
+ LocalVersionSlice :: Actual ( segments) => segments
732
+ . iter( )
733
+ . map( ToString :: to_string)
734
+ . collect:: <Vec <String >>( )
735
+ . join( "." ) ,
736
+ LocalVersionSlice :: Sentinel => String :: from( "<max-local-version>" ) ,
737
+ }
722
738
)
723
739
} ;
724
740
write ! ( f, "{epoch}{release}{pre}{post}{dev}{local}" )
@@ -1164,10 +1180,10 @@ impl VersionSmall {
1164
1180
1165
1181
#[ inline]
1166
1182
#[ allow( clippy:: unused_self) ]
1167
- fn local ( & self ) -> & [ LocalSegment ] {
1183
+ fn local ( & self ) -> LocalVersionSlice {
1168
1184
// A "small" version is never used if the version has a non-zero number
1169
1185
// of local segments.
1170
- & [ ]
1186
+ LocalVersionSlice :: Actual ( & [ ] )
1171
1187
}
1172
1188
1173
1189
#[ inline]
@@ -1252,7 +1268,7 @@ struct VersionFull {
1252
1268
///
1253
1269
/// Local versions allow multiple segments separated by periods, such as `deadbeef.1.2.3`, see
1254
1270
/// [`LocalSegment`] for details on the semantics.
1255
- local : Vec < LocalSegment > ,
1271
+ local : LocalVersion ,
1256
1272
/// An internal-only segment that does not exist in PEP 440, used to
1257
1273
/// represent the smallest possible version of a release, preceding any
1258
1274
/// `dev`, `pre`, `post` or releases.
@@ -1383,6 +1399,84 @@ impl std::fmt::Display for Prerelease {
1383
1399
}
1384
1400
}
1385
1401
1402
+ /// Either a sequence of local segments or [`LocalVersion::Sentinel``], an internal-only value that compares greater than all other local versions.
1403
+ #[ derive( Eq , PartialEq , Debug , Clone , Hash ) ]
1404
+ #[ cfg_attr(
1405
+ feature = "rkyv" ,
1406
+ derive( rkyv:: Archive , rkyv:: Deserialize , rkyv:: Serialize )
1407
+ ) ]
1408
+ #[ cfg_attr( feature = "rkyv" , rkyv( derive( Debug , Eq , PartialEq , PartialOrd , Ord ) ) ) ]
1409
+ pub enum LocalVersion {
1410
+ /// A sequence of local segments
1411
+ Actual ( Vec < LocalSegment > ) ,
1412
+ /// An internal-only value that compares greater to all other local versions
1413
+ Max ,
1414
+ }
1415
+
1416
+ /// Like [`LocalVersion`], but using a slice
1417
+ #[ derive( Eq , PartialEq , Debug , Clone , Hash ) ]
1418
+ pub enum LocalVersionSlice < ' a > {
1419
+ /// Like [`LocalVersion::Actual`]
1420
+ Actual ( & ' a [ LocalSegment ] ) ,
1421
+ /// Like [`LocalVersion::Sentintel`]
1422
+ Sentinel ,
1423
+ }
1424
+
1425
+ impl LocalVersion {
1426
+ /// convert into a local version slice
1427
+ pub fn as_slice < ' a > ( & ' a self ) -> LocalVersionSlice < ' a > {
1428
+ match self {
1429
+ LocalVersion :: Actual ( segments) => LocalVersionSlice :: Actual ( segments) ,
1430
+ LocalVersion :: Max => LocalVersionSlice :: Sentinel ,
1431
+ }
1432
+ }
1433
+
1434
+ /// clear the local version segments, if they exist
1435
+ pub fn clear ( & mut self ) {
1436
+ if let Self :: Actual ( segments) = self {
1437
+ segments. clear ( ) ;
1438
+ }
1439
+ }
1440
+ }
1441
+
1442
+ impl LocalVersionSlice < ' _ > {
1443
+ /// output the local version identifier string. [`LocalVersionSlice::Sentinel`] maps to `"<max-local-version>"` which is otherwise an illegal local version because `<` and `>` are not allowed
1444
+ pub fn local_identifier_string ( & self ) -> String {
1445
+ match self {
1446
+ LocalVersionSlice :: Actual ( segments) => segments
1447
+ . iter ( )
1448
+ . map ( ToString :: to_string)
1449
+ . collect :: < Vec < String > > ( )
1450
+ . join ( "." ) ,
1451
+ LocalVersionSlice :: Sentinel => String :: from ( "<max-local-version>" ) ,
1452
+ }
1453
+ }
1454
+ }
1455
+
1456
+ impl PartialOrd for LocalVersionSlice < ' _ > {
1457
+ fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
1458
+ Some ( self . cmp ( other) )
1459
+ }
1460
+ }
1461
+
1462
+ impl Ord for LocalVersionSlice < ' _ > {
1463
+ fn cmp ( & self , other : & Self ) -> Ordering {
1464
+ match ( self , other) {
1465
+ ( LocalVersionSlice :: Actual ( lv1) , LocalVersionSlice :: Actual ( lv2) ) => lv1. cmp ( lv2) ,
1466
+ ( LocalVersionSlice :: Actual ( _) , LocalVersionSlice :: Sentinel ) => Ordering :: Less ,
1467
+ ( LocalVersionSlice :: Sentinel , LocalVersionSlice :: Actual ( _) ) => Ordering :: Greater ,
1468
+ ( LocalVersionSlice :: Sentinel , LocalVersionSlice :: Sentinel ) => Ordering :: Equal ,
1469
+ }
1470
+ }
1471
+ }
1472
+
1473
+ impl LocalVersionSlice < ' _ > {
1474
+ /// Whether the local version is absent
1475
+ pub fn is_empty ( & self ) -> bool {
1476
+ matches ! ( self , Self :: Actual ( & [ ] ) )
1477
+ }
1478
+ }
1479
+
1386
1480
/// A part of the [local version identifier](<https://peps.python.org/pep-0440/#local-version-identifiers>)
1387
1481
///
1388
1482
/// Local versions are a mess:
@@ -1830,7 +1924,7 @@ impl<'a> Parser<'a> {
1830
1924
. with_pre ( self . pre )
1831
1925
. with_post ( self . post )
1832
1926
. with_dev ( self . dev )
1833
- . with_local ( self . local ) ;
1927
+ . with_local ( LocalVersion :: Actual ( self . local ) ) ;
1834
1928
VersionPattern {
1835
1929
version,
1836
1930
wildcard : self . wildcard ,
@@ -2301,7 +2395,7 @@ pub(crate) fn compare_release(this: &[u64], other: &[u64]) -> Ordering {
2301
2395
/// implementation
2302
2396
///
2303
2397
/// [pep440-suffix-ordering]: https://peps.python.org/pep-0440/#summary-of-permitted-suffixes-and-relative-ordering
2304
- fn sortable_tuple ( version : & Version ) -> ( u64 , u64 , Option < u64 > , u64 , & [ LocalSegment ] ) {
2398
+ fn sortable_tuple ( version : & Version ) -> ( u64 , u64 , Option < u64 > , u64 , LocalVersionSlice ) {
2305
2399
// If the version is a "max" version, use a post version larger than any possible post version.
2306
2400
let post = if version. max ( ) . is_some ( ) {
2307
2401
Some ( u64:: MAX )
0 commit comments