@@ -29,7 +29,7 @@ mod bytewise;
29
29
pub ( crate ) use bytewise:: BytewiseEq ;
30
30
31
31
use self :: Ordering :: * ;
32
- use crate :: ops:: ControlFlow :: { self , Break , Continue } ;
32
+ use crate :: ops:: ControlFlow ;
33
33
34
34
/// Trait for comparisons using the equality operator.
35
35
///
@@ -1436,65 +1436,78 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
1436
1436
fn ge ( & self , other : & Rhs ) -> bool {
1437
1437
self . partial_cmp ( other) . is_some_and ( Ordering :: is_ge)
1438
1438
}
1439
- }
1440
-
1441
- /// Derive macro generating an impl of the trait [`PartialOrd`].
1442
- /// The behavior of this macro is described in detail [here](PartialOrd#derivable).
1443
- #[ rustc_builtin_macro]
1444
- #[ stable( feature = "builtin_macro_prelude" , since = "1.38.0" ) ]
1445
- #[ allow_internal_unstable( core_intrinsics) ]
1446
- pub macro PartialOrd ( $item: item) {
1447
- /* compiler built-in */
1448
- }
1449
-
1450
- /// Helpers for chaining together field PartialOrds into the full type's ordering.
1451
- ///
1452
- /// If the two values are equal, returns `ControlFlow::Continue`.
1453
- /// If the two values are not equal, returns `ControlFlow::Break(self OP other)`.
1454
- ///
1455
- /// This allows simple types like `i32` and `f64` to just emit two comparisons
1456
- /// directly, instead of needing to optimize the 3-way comparison.
1457
- ///
1458
- /// Currently this is done using specialization, but it doesn't need that:
1459
- /// it could be provided methods on `PartialOrd` instead and work fine.
1460
- pub ( crate ) trait SpecChainingPartialOrd < Rhs > : PartialOrd < Rhs > {
1461
- fn spec_chain_lt ( & self , other : & Rhs ) -> ControlFlow < bool > ;
1462
- fn spec_chain_le ( & self , other : & Rhs ) -> ControlFlow < bool > ;
1463
- fn spec_chain_gt ( & self , other : & Rhs ) -> ControlFlow < bool > ;
1464
- fn spec_chain_ge ( & self , other : & Rhs ) -> ControlFlow < bool > ;
1465
- }
1466
1439
1467
- impl < T : PartialOrd < U > , U > SpecChainingPartialOrd < U > for T {
1440
+ /// If `self == other`, returns `ControlFlow::Continue(())`.
1441
+ /// Otherwise, returns `ControlFlow::Break(self < other)`.
1442
+ ///
1443
+ /// This is useful for chaining together calls when implementing a lexical
1444
+ /// `PartialOrd::lt`, as it allows types (like primitives) which can cheaply
1445
+ /// check `==` and `<` separately to do rather than needing to calculate
1446
+ /// (then optimize out) the three-way `Ordering` result.
1468
1447
#[ inline]
1469
- default fn spec_chain_lt ( & self , other : & U ) -> ControlFlow < bool > {
1470
- match PartialOrd :: partial_cmp ( self , other) {
1471
- Some ( Equal ) => Continue ( ( ) ) ,
1472
- c => Break ( c. is_some_and ( Ordering :: is_lt) ) ,
1473
- }
1448
+ #[ must_use]
1449
+ // Added to improve the behaviour of tuples; not necessarily stabilization-track.
1450
+ #[ unstable( feature = "partial_ord_chaining_methods" , issue = "none" ) ]
1451
+ #[ doc( hidden) ]
1452
+ fn __chaining_lt ( & self , other : & Rhs ) -> ControlFlow < bool > {
1453
+ default_chaining_impl ( self , other, Ordering :: is_lt)
1474
1454
}
1455
+
1456
+ /// Same as `__chaining_lt`, but for `<=` instead of `<`.
1475
1457
#[ inline]
1476
- default fn spec_chain_le ( & self , other : & U ) -> ControlFlow < bool > {
1477
- match PartialOrd :: partial_cmp ( self , other ) {
1478
- Some ( Equal ) => Continue ( ( ) ) ,
1479
- c => Break ( c . is_some_and ( Ordering :: is_le ) ) ,
1480
- }
1458
+ # [ must_use ]
1459
+ # [ unstable ( feature = "partial_ord_chaining_methods" , issue = "none" ) ]
1460
+ # [ doc ( hidden ) ]
1461
+ fn __chaining_le ( & self , other : & Rhs ) -> ControlFlow < bool > {
1462
+ default_chaining_impl ( self , other , Ordering :: is_le )
1481
1463
}
1464
+
1465
+ /// Same as `__chaining_lt`, but for `>` instead of `<`.
1482
1466
#[ inline]
1483
- default fn spec_chain_gt ( & self , other : & U ) -> ControlFlow < bool > {
1484
- match PartialOrd :: partial_cmp ( self , other ) {
1485
- Some ( Equal ) => Continue ( ( ) ) ,
1486
- c => Break ( c . is_some_and ( Ordering :: is_gt ) ) ,
1487
- }
1467
+ # [ must_use ]
1468
+ # [ unstable ( feature = "partial_ord_chaining_methods" , issue = "none" ) ]
1469
+ # [ doc ( hidden ) ]
1470
+ fn __chaining_gt ( & self , other : & Rhs ) -> ControlFlow < bool > {
1471
+ default_chaining_impl ( self , other , Ordering :: is_gt )
1488
1472
}
1473
+
1474
+ /// Same as `__chaining_lt`, but for `>=` instead of `<`.
1489
1475
#[ inline]
1490
- default fn spec_chain_ge ( & self , other : & U ) -> ControlFlow < bool > {
1491
- match PartialOrd :: partial_cmp ( self , other ) {
1492
- Some ( Equal ) => Continue ( ( ) ) ,
1493
- c => Break ( c . is_some_and ( Ordering :: is_ge ) ) ,
1494
- }
1476
+ # [ must_use ]
1477
+ # [ unstable ( feature = "partial_ord_chaining_methods" , issue = "none" ) ]
1478
+ # [ doc ( hidden ) ]
1479
+ fn __chaining_ge ( & self , other : & Rhs ) -> ControlFlow < bool > {
1480
+ default_chaining_impl ( self , other , Ordering :: is_ge )
1495
1481
}
1496
1482
}
1497
1483
1484
+ fn default_chaining_impl < T : ?Sized , U : ?Sized > (
1485
+ lhs : & T ,
1486
+ rhs : & U ,
1487
+ p : impl FnOnce ( Ordering ) -> bool ,
1488
+ ) -> ControlFlow < bool >
1489
+ where
1490
+ T : PartialOrd < U > ,
1491
+ {
1492
+ // It's important that this only call `partial_cmp` once, not call `eq` then
1493
+ // one of the relational operators. We don't want to `bcmp`-then-`memcp` a
1494
+ // `String`, for example, or similarly for other data structures (#108157).
1495
+ match <T as PartialOrd < U > >:: partial_cmp ( lhs, rhs) {
1496
+ Some ( Equal ) => ControlFlow :: Continue ( ( ) ) ,
1497
+ Some ( c) => ControlFlow :: Break ( p ( c) ) ,
1498
+ None => ControlFlow :: Break ( false ) ,
1499
+ }
1500
+ }
1501
+
1502
+ /// Derive macro generating an impl of the trait [`PartialOrd`].
1503
+ /// The behavior of this macro is described in detail [here](PartialOrd#derivable).
1504
+ #[ rustc_builtin_macro]
1505
+ #[ stable( feature = "builtin_macro_prelude" , since = "1.38.0" ) ]
1506
+ #[ allow_internal_unstable( core_intrinsics) ]
1507
+ pub macro PartialOrd ( $item: item) {
1508
+ /* compiler built-in */
1509
+ }
1510
+
1498
1511
/// Compares and returns the minimum of two values.
1499
1512
///
1500
1513
/// Returns the first argument if the comparison determines them to be equal.
@@ -1829,32 +1842,31 @@ mod impls {
1829
1842
1830
1843
eq_impl ! { ( ) bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
1831
1844
1832
- macro_rules! chaining_impl {
1845
+ macro_rules! chaining_methods_impl {
1833
1846
( $t: ty) => {
1834
1847
// These implementations are the same for `Ord` or `PartialOrd` types
1835
1848
// because if either is NAN the `==` test will fail so we end up in
1836
1849
// the `Break` case and the comparison will correctly return `false`.
1837
- impl super :: SpecChainingPartialOrd <$t> for $t {
1838
- #[ inline]
1839
- fn spec_chain_lt( & self , other: & Self ) -> ControlFlow <bool > {
1840
- let ( lhs, rhs) = ( * self , * other) ;
1841
- if lhs == rhs { Continue ( ( ) ) } else { Break ( lhs < rhs) }
1842
- }
1843
- #[ inline]
1844
- fn spec_chain_le( & self , other: & Self ) -> ControlFlow <bool > {
1845
- let ( lhs, rhs) = ( * self , * other) ;
1846
- if lhs == rhs { Continue ( ( ) ) } else { Break ( lhs <= rhs) }
1847
- }
1848
- #[ inline]
1849
- fn spec_chain_gt( & self , other: & Self ) -> ControlFlow <bool > {
1850
- let ( lhs, rhs) = ( * self , * other) ;
1851
- if lhs == rhs { Continue ( ( ) ) } else { Break ( lhs > rhs) }
1852
- }
1853
- #[ inline]
1854
- fn spec_chain_ge( & self , other: & Self ) -> ControlFlow <bool > {
1855
- let ( lhs, rhs) = ( * self , * other) ;
1856
- if lhs == rhs { Continue ( ( ) ) } else { Break ( lhs >= rhs) }
1857
- }
1850
+
1851
+ #[ inline]
1852
+ fn __chaining_lt( & self , other: & Self ) -> ControlFlow <bool > {
1853
+ let ( lhs, rhs) = ( * self , * other) ;
1854
+ if lhs == rhs { Continue ( ( ) ) } else { Break ( lhs < rhs) }
1855
+ }
1856
+ #[ inline]
1857
+ fn __chaining_le( & self , other: & Self ) -> ControlFlow <bool > {
1858
+ let ( lhs, rhs) = ( * self , * other) ;
1859
+ if lhs == rhs { Continue ( ( ) ) } else { Break ( lhs <= rhs) }
1860
+ }
1861
+ #[ inline]
1862
+ fn __chaining_gt( & self , other: & Self ) -> ControlFlow <bool > {
1863
+ let ( lhs, rhs) = ( * self , * other) ;
1864
+ if lhs == rhs { Continue ( ( ) ) } else { Break ( lhs > rhs) }
1865
+ }
1866
+ #[ inline]
1867
+ fn __chaining_ge( & self , other: & Self ) -> ControlFlow <bool > {
1868
+ let ( lhs, rhs) = ( * self , * other) ;
1869
+ if lhs == rhs { Continue ( ( ) ) } else { Break ( lhs >= rhs) }
1858
1870
}
1859
1871
} ;
1860
1872
}
@@ -1880,9 +1892,9 @@ mod impls {
1880
1892
fn ge( & self , other: & $t) -> bool { ( * self ) >= ( * other) }
1881
1893
#[ inline( always) ]
1882
1894
fn gt( & self , other: & $t) -> bool { ( * self ) > ( * other) }
1883
- }
1884
1895
1885
- chaining_impl!( $t) ;
1896
+ chaining_methods_impl!( $t) ;
1897
+ }
1886
1898
) * )
1887
1899
}
1888
1900
@@ -1920,9 +1932,9 @@ mod impls {
1920
1932
fn ge( & self , other: & $t) -> bool { ( * self ) >= ( * other) }
1921
1933
#[ inline( always) ]
1922
1934
fn gt( & self , other: & $t) -> bool { ( * self ) > ( * other) }
1923
- }
1924
1935
1925
- chaining_impl!( $t) ;
1936
+ chaining_methods_impl!( $t) ;
1937
+ }
1926
1938
1927
1939
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
1928
1940
impl Ord for $t {
0 commit comments