@@ -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 :: Segments ( 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 :: Segments ( 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 :: Segments ( vec ! [ ] ) ,
619
632
} ;
620
633
* self = Self {
621
634
inner : Arc :: new ( VersionInner :: Full { full } ) ,
@@ -712,14 +725,12 @@ impl std::fmt::Display for Version {
712
725
let local = if self . local ( ) . is_empty ( ) {
713
726
String :: new ( )
714
727
} else {
715
- format ! (
716
- "+{}" ,
717
- self . local( )
718
- . iter( )
719
- . map( ToString :: to_string)
720
- . collect:: <Vec <String >>( )
721
- . join( "." )
722
- )
728
+ match self . local ( ) {
729
+ LocalVersionSlice :: Segments ( _) => {
730
+ format ! ( "+{}" , self . local( ) )
731
+ }
732
+ LocalVersionSlice :: Max => String :: new ( ) ,
733
+ }
723
734
} ;
724
735
write ! ( f, "{epoch}{release}{pre}{post}{dev}{local}" )
725
736
}
@@ -1195,10 +1206,10 @@ impl VersionSmall {
1195
1206
1196
1207
#[ inline]
1197
1208
#[ allow( clippy:: unused_self) ]
1198
- fn local ( & self ) -> & [ LocalSegment ] {
1209
+ fn local ( & self ) -> LocalVersionSlice {
1199
1210
// A "small" version is never used if the version has a non-zero number
1200
1211
// of local segments.
1201
- & [ ]
1212
+ LocalVersionSlice :: Segments ( & [ ] )
1202
1213
}
1203
1214
1204
1215
#[ inline]
@@ -1283,7 +1294,7 @@ struct VersionFull {
1283
1294
///
1284
1295
/// Local versions allow multiple segments separated by periods, such as `deadbeef.1.2.3`, see
1285
1296
/// [`LocalSegment`] for details on the semantics.
1286
- local : Vec < LocalSegment > ,
1297
+ local : LocalVersion ,
1287
1298
/// An internal-only segment that does not exist in PEP 440, used to
1288
1299
/// represent the smallest possible version of a release, preceding any
1289
1300
/// `dev`, `pre`, `post` or releases.
@@ -1414,6 +1425,93 @@ impl std::fmt::Display for Prerelease {
1414
1425
}
1415
1426
}
1416
1427
1428
+ /// Either a sequence of local segments or [`LocalVersion::Sentinel`], an internal-only value that
1429
+ /// compares greater than all other local versions.
1430
+ #[ derive( Eq , PartialEq , Debug , Clone , Hash ) ]
1431
+ #[ cfg_attr(
1432
+ feature = "rkyv" ,
1433
+ derive( rkyv:: Archive , rkyv:: Deserialize , rkyv:: Serialize )
1434
+ ) ]
1435
+ #[ cfg_attr( feature = "rkyv" , rkyv( derive( Debug , Eq , PartialEq , PartialOrd , Ord ) ) ) ]
1436
+ pub enum LocalVersion {
1437
+ /// A sequence of local segments.
1438
+ Segments ( Vec < LocalSegment > ) ,
1439
+ /// An internal-only value that compares greater to all other local versions.
1440
+ Max ,
1441
+ }
1442
+
1443
+ /// Like [`LocalVersion`], but using a slice
1444
+ #[ derive( Eq , PartialEq , Debug , Clone , Hash ) ]
1445
+ pub enum LocalVersionSlice < ' a > {
1446
+ /// Like [`LocalVersion::Segments`]
1447
+ Segments ( & ' a [ LocalSegment ] ) ,
1448
+ /// Like [`LocalVersion::Sentinel`]
1449
+ Max ,
1450
+ }
1451
+
1452
+ impl LocalVersion {
1453
+ /// Convert the local version segments into a slice.
1454
+ pub fn as_slice ( & self ) -> LocalVersionSlice < ' _ > {
1455
+ match self {
1456
+ LocalVersion :: Segments ( segments) => LocalVersionSlice :: Segments ( segments) ,
1457
+ LocalVersion :: Max => LocalVersionSlice :: Max ,
1458
+ }
1459
+ }
1460
+
1461
+ /// Clear the local version segments, if they exist.
1462
+ pub fn clear ( & mut self ) {
1463
+ match self {
1464
+ Self :: Segments ( segments) => segments. clear ( ) ,
1465
+ Self :: Max => * self = Self :: Segments ( Vec :: new ( ) ) ,
1466
+ }
1467
+ }
1468
+ }
1469
+
1470
+ /// Output the local version identifier string.
1471
+ ///
1472
+ /// [`LocalVersionSlice::Max`] maps to `"[max]"` which is otherwise an illegal local
1473
+ /// version because `[` and `]` are not allowed.
1474
+ impl std:: fmt:: Display for LocalVersionSlice < ' _ > {
1475
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
1476
+ match self {
1477
+ LocalVersionSlice :: Segments ( segments) => {
1478
+ for ( i, segment) in segments. iter ( ) . enumerate ( ) {
1479
+ if i > 0 {
1480
+ write ! ( f, "." ) ?;
1481
+ }
1482
+ write ! ( f, "{segment}" ) ?;
1483
+ }
1484
+ Ok ( ( ) )
1485
+ }
1486
+ LocalVersionSlice :: Max => write ! ( f, "[max]" ) ,
1487
+ }
1488
+ }
1489
+ }
1490
+
1491
+ impl PartialOrd for LocalVersionSlice < ' _ > {
1492
+ fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
1493
+ Some ( self . cmp ( other) )
1494
+ }
1495
+ }
1496
+
1497
+ impl Ord for LocalVersionSlice < ' _ > {
1498
+ fn cmp ( & self , other : & Self ) -> Ordering {
1499
+ match ( self , other) {
1500
+ ( LocalVersionSlice :: Segments ( lv1) , LocalVersionSlice :: Segments ( lv2) ) => lv1. cmp ( lv2) ,
1501
+ ( LocalVersionSlice :: Segments ( _) , LocalVersionSlice :: Max ) => Ordering :: Less ,
1502
+ ( LocalVersionSlice :: Max , LocalVersionSlice :: Segments ( _) ) => Ordering :: Greater ,
1503
+ ( LocalVersionSlice :: Max , LocalVersionSlice :: Max ) => Ordering :: Equal ,
1504
+ }
1505
+ }
1506
+ }
1507
+
1508
+ impl LocalVersionSlice < ' _ > {
1509
+ /// Whether the local version is absent
1510
+ pub fn is_empty ( & self ) -> bool {
1511
+ matches ! ( self , Self :: Segments ( & [ ] ) )
1512
+ }
1513
+ }
1514
+
1417
1515
/// A part of the [local version identifier](<https://peps.python.org/pep-0440/#local-version-identifiers>)
1418
1516
///
1419
1517
/// Local versions are a mess:
@@ -1855,7 +1953,7 @@ impl<'a> Parser<'a> {
1855
1953
. with_pre ( self . pre )
1856
1954
. with_post ( self . post )
1857
1955
. with_dev ( self . dev )
1858
- . with_local ( self . local ) ;
1956
+ . with_local ( LocalVersion :: Segments ( self . local ) ) ;
1859
1957
VersionPattern {
1860
1958
version,
1861
1959
wildcard : self . wildcard ,
@@ -2326,7 +2424,7 @@ pub(crate) fn compare_release(this: &[u64], other: &[u64]) -> Ordering {
2326
2424
/// implementation
2327
2425
///
2328
2426
/// [pep440-suffix-ordering]: https://peps.python.org/pep-0440/#summary-of-permitted-suffixes-and-relative-ordering
2329
- fn sortable_tuple ( version : & Version ) -> ( u64 , u64 , Option < u64 > , u64 , & [ LocalSegment ] ) {
2427
+ fn sortable_tuple ( version : & Version ) -> ( u64 , u64 , Option < u64 > , u64 , LocalVersionSlice ) {
2330
2428
// If the version is a "max" version, use a post version larger than any possible post version.
2331
2429
let post = if version. max ( ) . is_some ( ) {
2332
2430
Some ( u64:: MAX )
0 commit comments