@@ -29,6 +29,7 @@ mod bytewise;
2929pub ( crate ) use bytewise:: BytewiseEq ;
3030
3131use self :: Ordering :: * ;
32+ use crate :: ops:: ControlFlow ;
3233
3334/// Trait for comparisons using the equality operator.
3435///
@@ -1435,6 +1436,67 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
14351436 fn ge ( & self , other : & Rhs ) -> bool {
14361437 self . partial_cmp ( other) . is_some_and ( Ordering :: is_ge)
14371438 }
1439+
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.
1447+ #[ inline]
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)
1454+ }
1455+
1456+ /// Same as `__chaining_lt`, but for `<=` instead of `<`.
1457+ #[ inline]
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)
1463+ }
1464+
1465+ /// Same as `__chaining_lt`, but for `>` instead of `<`.
1466+ #[ inline]
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)
1472+ }
1473+
1474+ /// Same as `__chaining_lt`, but for `>=` instead of `<`.
1475+ #[ inline]
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)
1481+ }
1482+ }
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+ }
14381500}
14391501
14401502/// Derive macro generating an impl of the trait [`PartialOrd`].
@@ -1741,6 +1803,7 @@ where
17411803mod impls {
17421804 use crate :: cmp:: Ordering :: { self , Equal , Greater , Less } ;
17431805 use crate :: hint:: unreachable_unchecked;
1806+ use crate :: ops:: ControlFlow :: { self , Break , Continue } ;
17441807
17451808 macro_rules! partial_eq_impl {
17461809 ( $( $t: ty) * ) => ( $(
@@ -1779,6 +1842,35 @@ mod impls {
17791842
17801843 eq_impl ! { ( ) bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
17811844
1845+ macro_rules! chaining_methods_impl {
1846+ ( $t: ty) => {
1847+ // These implementations are the same for `Ord` or `PartialOrd` types
1848+ // because if either is NAN the `==` test will fail so we end up in
1849+ // the `Break` case and the comparison will correctly return `false`.
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) }
1870+ }
1871+ } ;
1872+ }
1873+
17821874 macro_rules! partial_ord_impl {
17831875 ( $( $t: ty) * ) => ( $(
17841876 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
@@ -1800,6 +1892,8 @@ mod impls {
18001892 fn ge( & self , other: & $t) -> bool { ( * self ) >= ( * other) }
18011893 #[ inline( always) ]
18021894 fn gt( & self , other: & $t) -> bool { ( * self ) > ( * other) }
1895+
1896+ chaining_methods_impl!( $t) ;
18031897 }
18041898 ) * )
18051899 }
@@ -1838,6 +1932,8 @@ mod impls {
18381932 fn ge( & self , other: & $t) -> bool { ( * self ) >= ( * other) }
18391933 #[ inline( always) ]
18401934 fn gt( & self , other: & $t) -> bool { ( * self ) > ( * other) }
1935+
1936+ chaining_methods_impl!( $t) ;
18411937 }
18421938
18431939 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
0 commit comments