@@ -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///
@@ -1446,6 +1447,54 @@ pub macro PartialOrd($item:item) {
14461447 /* compiler built-in */
14471448}
14481449
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+
14491498/// Compares and returns the minimum of two values.
14501499///
14511500/// Returns the first argument if the comparison determines them to be equal.
@@ -1741,6 +1790,7 @@ where
17411790mod impls {
17421791 use crate :: cmp:: Ordering :: { self , Equal , Greater , Less } ;
17431792 use crate :: hint:: unreachable_unchecked;
1793+ use crate :: ops:: ControlFlow :: { self , Break , Continue } ;
17441794
17451795 macro_rules! partial_eq_impl {
17461796 ( $( $t: ty) * ) => ( $(
@@ -1779,6 +1829,36 @@ mod impls {
17791829
17801830 eq_impl ! { ( ) bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
17811831
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+
17821862 macro_rules! partial_ord_impl {
17831863 ( $( $t: ty) * ) => ( $(
17841864 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
@@ -1801,6 +1881,8 @@ mod impls {
18011881 #[ inline( always) ]
18021882 fn gt( & self , other: & $t) -> bool { ( * self ) > ( * other) }
18031883 }
1884+
1885+ chaining_impl!( $t) ;
18041886 ) * )
18051887 }
18061888
@@ -1840,6 +1922,8 @@ mod impls {
18401922 fn gt( & self , other: & $t) -> bool { ( * self ) > ( * other) }
18411923 }
18421924
1925+ chaining_impl!( $t) ;
1926+
18431927 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
18441928 impl Ord for $t {
18451929 #[ inline]
0 commit comments