@@ -29,6 +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
33
33
34
/// Trait for comparisons using the equality operator.
34
35
///
@@ -1446,6 +1447,54 @@ pub macro PartialOrd($item:item) {
1446
1447
/* compiler built-in */
1447
1448
}
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
+
1467
+ impl < T : PartialOrd < U > , U > SpecChainingPartialOrd < U > for T {
1468
+ #[ 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
+ }
1474
+ }
1475
+ #[ 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
+ }
1481
+ }
1482
+ #[ 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
+ }
1488
+ }
1489
+ #[ 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
+ }
1495
+ }
1496
+ }
1497
+
1449
1498
/// Compares and returns the minimum of two values.
1450
1499
///
1451
1500
/// Returns the first argument if the comparison determines them to be equal.
@@ -1741,6 +1790,7 @@ where
1741
1790
mod impls {
1742
1791
use crate :: cmp:: Ordering :: { self , Equal , Greater , Less } ;
1743
1792
use crate :: hint:: unreachable_unchecked;
1793
+ use crate :: ops:: ControlFlow :: { self , Break , Continue } ;
1744
1794
1745
1795
macro_rules! partial_eq_impl {
1746
1796
( $( $t: ty) * ) => ( $(
@@ -1779,6 +1829,36 @@ mod impls {
1779
1829
1780
1830
eq_impl ! { ( ) bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
1781
1831
1832
+ macro_rules! chaining_impl {
1833
+ ( $t: ty) => {
1834
+ // These implementations are the same for `Ord` or `PartialOrd` types
1835
+ // because if either is NAN the `==` test will fail so we end up in
1836
+ // 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
+ }
1858
+ }
1859
+ } ;
1860
+ }
1861
+
1782
1862
macro_rules! partial_ord_impl {
1783
1863
( $( $t: ty) * ) => ( $(
1784
1864
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
@@ -1801,6 +1881,8 @@ mod impls {
1801
1881
#[ inline( always) ]
1802
1882
fn gt( & self , other: & $t) -> bool { ( * self ) > ( * other) }
1803
1883
}
1884
+
1885
+ chaining_impl!( $t) ;
1804
1886
) * )
1805
1887
}
1806
1888
@@ -1840,6 +1922,8 @@ mod impls {
1840
1922
fn gt( & self , other: & $t) -> bool { ( * self ) > ( * other) }
1841
1923
}
1842
1924
1925
+ chaining_impl!( $t) ;
1926
+
1843
1927
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
1844
1928
impl Ord for $t {
1845
1929
#[ inline]
0 commit comments