@@ -29,6 +29,7 @@ mod bytewise;
2929pub ( crate ) use bytewise:: BytewiseEq ;
3030
3131use self :: Ordering :: * ;
32+ use crate :: ops:: ControlFlow :: { self , Break , Continue } ;
3233
3334/// Trait for comparisons using the equality operator.
3435///
@@ -1436,6 +1437,54 @@ pub macro PartialOrd($item:item) {
14361437 /* compiler built-in */
14371438}
14381439
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+
14391488/// Compares and returns the minimum of two values.
14401489///
14411490/// Returns the first argument if the comparison determines them to be equal.
@@ -1731,6 +1780,7 @@ where
17311780mod impls {
17321781 use crate :: cmp:: Ordering :: { self , Equal , Greater , Less } ;
17331782 use crate :: hint:: unreachable_unchecked;
1783+ use crate :: ops:: ControlFlow :: { self , Break , Continue } ;
17341784
17351785 macro_rules! partial_eq_impl {
17361786 ( $( $t: ty) * ) => ( $(
@@ -1769,6 +1819,36 @@ mod impls {
17691819
17701820 eq_impl ! { ( ) bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
17711821
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 ( ( ) ) } else { Break ( lhs < rhs) }
1832+ }
1833+ #[ inline]
1834+ fn spec_chain_le( & self , other: & Self ) -> ControlFlow <bool > {
1835+ let ( lhs, rhs) = ( * self , * other) ;
1836+ if lhs == rhs { Continue ( ( ) ) } else { Break ( lhs <= rhs) }
1837+ }
1838+ #[ inline]
1839+ fn spec_chain_gt( & 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_ge( & self , other: & Self ) -> ControlFlow <bool > {
1845+ let ( lhs, rhs) = ( * self , * other) ;
1846+ if lhs == rhs { Continue ( ( ) ) } else { Break ( lhs >= rhs) }
1847+ }
1848+ }
1849+ } ;
1850+ }
1851+
17721852 macro_rules! partial_ord_impl {
17731853 ( $( $t: ty) * ) => ( $(
17741854 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
@@ -1791,6 +1871,8 @@ mod impls {
17911871 #[ inline( always) ]
17921872 fn gt( & self , other: & $t) -> bool { ( * self ) > ( * other) }
17931873 }
1874+
1875+ chaining_impl!( $t) ;
17941876 ) * )
17951877 }
17961878
@@ -1830,6 +1912,8 @@ mod impls {
18301912 fn gt( & self , other: & $t) -> bool { ( * self ) > ( * other) }
18311913 }
18321914
1915+ chaining_impl!( $t) ;
1916+
18331917 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
18341918 impl Ord for $t {
18351919 #[ inline]
0 commit comments