@@ -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
///
@@ -1436,6 +1437,54 @@ pub macro PartialOrd($item:item) {
1436
1437
/* compiler built-in */
1437
1438
}
1438
1439
1440
+ /// Helpers for chaining together field PartialOrds into the full type's ordering.
1441
+ ///
1442
+ /// If the two values are equal, returns `ControlFlow::Continue`.
1443
+ /// If the two values are not equal, returns `ControlFlow::Break(self OP other)`.
1444
+ ///
1445
+ /// This allows simple types like `i32` and `f64` to just emit two comparisons
1446
+ /// directly, instead of needing to optimize the 3-way comparison.
1447
+ ///
1448
+ /// Currently this is done using specialization, but it doesn't need that:
1449
+ /// it could be provided methods on `PartialOrd` instead and work fine.
1450
+ pub ( crate ) trait SpecChainingPartialOrd < Rhs > : PartialOrd < Rhs > {
1451
+ fn spec_chain_lt ( & self , other : & Rhs ) -> ControlFlow < bool > ;
1452
+ fn spec_chain_le ( & self , other : & Rhs ) -> ControlFlow < bool > ;
1453
+ fn spec_chain_gt ( & self , other : & Rhs ) -> ControlFlow < bool > ;
1454
+ fn spec_chain_ge ( & self , other : & Rhs ) -> ControlFlow < bool > ;
1455
+ }
1456
+
1457
+ impl < T : PartialOrd < U > , U > SpecChainingPartialOrd < U > for T {
1458
+ #[ inline]
1459
+ default fn spec_chain_lt ( & self , other : & U ) -> ControlFlow < bool > {
1460
+ match PartialOrd :: partial_cmp ( self , other) {
1461
+ Some ( Equal ) => Continue ( ( ) ) ,
1462
+ c => Break ( c. is_some_and ( Ordering :: is_lt) ) ,
1463
+ }
1464
+ }
1465
+ #[ inline]
1466
+ default fn spec_chain_le ( & self , other : & U ) -> ControlFlow < bool > {
1467
+ match PartialOrd :: partial_cmp ( self , other) {
1468
+ Some ( Equal ) => Continue ( ( ) ) ,
1469
+ c => Break ( c. is_some_and ( Ordering :: is_le) ) ,
1470
+ }
1471
+ }
1472
+ #[ inline]
1473
+ default fn spec_chain_gt ( & self , other : & U ) -> ControlFlow < bool > {
1474
+ match PartialOrd :: partial_cmp ( self , other) {
1475
+ Some ( Equal ) => Continue ( ( ) ) ,
1476
+ c => Break ( c. is_some_and ( Ordering :: is_gt) ) ,
1477
+ }
1478
+ }
1479
+ #[ inline]
1480
+ default fn spec_chain_ge ( & self , other : & U ) -> ControlFlow < bool > {
1481
+ match PartialOrd :: partial_cmp ( self , other) {
1482
+ Some ( Equal ) => Continue ( ( ) ) ,
1483
+ c => Break ( c. is_some_and ( Ordering :: is_ge) ) ,
1484
+ }
1485
+ }
1486
+ }
1487
+
1439
1488
/// Compares and returns the minimum of two values.
1440
1489
///
1441
1490
/// Returns the first argument if the comparison determines them to be equal.
@@ -1731,6 +1780,7 @@ where
1731
1780
mod impls {
1732
1781
use crate :: cmp:: Ordering :: { self , Equal , Greater , Less } ;
1733
1782
use crate :: hint:: unreachable_unchecked;
1783
+ use crate :: ops:: ControlFlow :: { self , Break , Continue } ;
1734
1784
1735
1785
macro_rules! partial_eq_impl {
1736
1786
( $( $t: ty) * ) => ( $(
@@ -1769,6 +1819,40 @@ mod impls {
1769
1819
1770
1820
eq_impl ! { ( ) bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
1771
1821
1822
+ macro_rules! chaining_impl {
1823
+ ( $t: ty) => {
1824
+ // These implementations are the same for `Ord` or `PartialOrd` types
1825
+ // because if either is NAN the `==` test will fail so we end up in
1826
+ // the `Break` case and the comparison will correctly return `false`.
1827
+ impl super :: SpecChainingPartialOrd <$t> for $t {
1828
+ #[ inline]
1829
+ fn spec_chain_lt( & self , other: & Self ) -> ControlFlow <bool > {
1830
+ let ( lhs, rhs) = ( * self , * other) ;
1831
+ if lhs == rhs { Continue ( ( ) ) }
1832
+ else { Break ( lhs < rhs) }
1833
+ }
1834
+ #[ inline]
1835
+ fn spec_chain_le( & self , other: & Self ) -> ControlFlow <bool > {
1836
+ let ( lhs, rhs) = ( * self , * other) ;
1837
+ if lhs == rhs { Continue ( ( ) ) }
1838
+ else { Break ( lhs <= rhs) }
1839
+ }
1840
+ #[ inline]
1841
+ fn spec_chain_gt( & self , other: & Self ) -> ControlFlow <bool > {
1842
+ let ( lhs, rhs) = ( * self , * other) ;
1843
+ if lhs == rhs { Continue ( ( ) ) }
1844
+ else { Break ( lhs > rhs) }
1845
+ }
1846
+ #[ inline]
1847
+ fn spec_chain_ge( & self , other: & Self ) -> ControlFlow <bool > {
1848
+ let ( lhs, rhs) = ( * self , * other) ;
1849
+ if lhs == rhs { Continue ( ( ) ) }
1850
+ else { Break ( lhs >= rhs) }
1851
+ }
1852
+ }
1853
+ } ;
1854
+ }
1855
+
1772
1856
macro_rules! partial_ord_impl {
1773
1857
( $( $t: ty) * ) => ( $(
1774
1858
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
@@ -1791,6 +1875,8 @@ mod impls {
1791
1875
#[ inline( always) ]
1792
1876
fn gt( & self , other: & $t) -> bool { ( * self ) > ( * other) }
1793
1877
}
1878
+
1879
+ chaining_impl!( $t) ;
1794
1880
) * )
1795
1881
}
1796
1882
@@ -1830,6 +1916,8 @@ mod impls {
1830
1916
fn gt( & self , other: & $t) -> bool { ( * self ) > ( * other) }
1831
1917
}
1832
1918
1919
+ chaining_impl!( $t) ;
1920
+
1833
1921
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
1834
1922
impl Ord for $t {
1835
1923
#[ inline]
0 commit comments