| // See core/src/primitive_docs.rs for documentation. |
| |
| use crate::cmp::Ordering::{self, *}; |
| use crate::marker::ConstParamTy; |
| use crate::marker::StructuralPartialEq; |
| |
| // Recursive macro for implementing n-ary tuple functions and operations |
| // |
| // Also provides implementations for tuples with lesser arity. For example, tuple_impls!(A B C) |
| // will implement everything for (A, B, C), (A, B) and (A,). |
| macro_rules! tuple_impls { |
| // Stopping criteria (1-ary tuple) |
| ($T:ident) => { |
| tuple_impls!(@impl $T); |
| }; |
| // Running criteria (n-ary tuple, with n >= 2) |
| ($T:ident $( $U:ident )+) => { |
| tuple_impls!($( $U )+); |
| tuple_impls!(@impl $T $( $U )+); |
| }; |
| // "Private" internal implementation |
| (@impl $( $T:ident )+) => { |
| maybe_tuple_doc! { |
| $($T)+ @ |
| #[stable(feature = "rust1", since = "1.0.0")] |
| impl<$($T: PartialEq),+> PartialEq for ($($T,)+) |
| where |
| last_type!($($T,)+): ?Sized |
| { |
| #[inline] |
| fn eq(&self, other: &($($T,)+)) -> bool { |
| $( ${ignore($T)} self.${index()} == other.${index()} )&&+ |
| } |
| #[inline] |
| fn ne(&self, other: &($($T,)+)) -> bool { |
| $( ${ignore($T)} self.${index()} != other.${index()} )||+ |
| } |
| } |
| } |
| |
| maybe_tuple_doc! { |
| $($T)+ @ |
| #[stable(feature = "rust1", since = "1.0.0")] |
| impl<$($T: Eq),+> Eq for ($($T,)+) |
| where |
| last_type!($($T,)+): ?Sized |
| {} |
| } |
| |
| maybe_tuple_doc! { |
| $($T)+ @ |
| #[unstable(feature = "structural_match", issue = "31434")] |
| impl<$($T: ConstParamTy),+> ConstParamTy for ($($T,)+) |
| {} |
| } |
| |
| maybe_tuple_doc! { |
| $($T)+ @ |
| #[unstable(feature = "structural_match", issue = "31434")] |
| impl<$($T),+> StructuralPartialEq for ($($T,)+) |
| {} |
| } |
| |
| maybe_tuple_doc! { |
| $($T)+ @ |
| #[unstable(feature = "structural_match", issue = "31434")] |
| #[cfg(bootstrap)] |
| impl<$($T),+> crate::marker::StructuralEq for ($($T,)+) |
| {} |
| } |
| |
| maybe_tuple_doc! { |
| $($T)+ @ |
| #[stable(feature = "rust1", since = "1.0.0")] |
| impl<$($T: PartialOrd),+> PartialOrd for ($($T,)+) |
| where |
| last_type!($($T,)+): ?Sized |
| { |
| #[inline] |
| fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> { |
| lexical_partial_cmp!($( ${ignore($T)} self.${index()}, other.${index()} ),+) |
| } |
| #[inline] |
| fn lt(&self, other: &($($T,)+)) -> bool { |
| lexical_ord!(lt, Less, $( ${ignore($T)} self.${index()}, other.${index()} ),+) |
| } |
| #[inline] |
| fn le(&self, other: &($($T,)+)) -> bool { |
| lexical_ord!(le, Less, $( ${ignore($T)} self.${index()}, other.${index()} ),+) |
| } |
| #[inline] |
| fn ge(&self, other: &($($T,)+)) -> bool { |
| lexical_ord!(ge, Greater, $( ${ignore($T)} self.${index()}, other.${index()} ),+) |
| } |
| #[inline] |
| fn gt(&self, other: &($($T,)+)) -> bool { |
| lexical_ord!(gt, Greater, $( ${ignore($T)} self.${index()}, other.${index()} ),+) |
| } |
| } |
| } |
| |
| maybe_tuple_doc! { |
| $($T)+ @ |
| #[stable(feature = "rust1", since = "1.0.0")] |
| impl<$($T: Ord),+> Ord for ($($T,)+) |
| where |
| last_type!($($T,)+): ?Sized |
| { |
| #[inline] |
| fn cmp(&self, other: &($($T,)+)) -> Ordering { |
| lexical_cmp!($( ${ignore($T)} self.${index()}, other.${index()} ),+) |
| } |
| } |
| } |
| |
| maybe_tuple_doc! { |
| $($T)+ @ |
| #[stable(feature = "rust1", since = "1.0.0")] |
| impl<$($T: Default),+> Default for ($($T,)+) { |
| #[inline] |
| fn default() -> ($($T,)+) { |
| ($({ let x: $T = Default::default(); x},)+) |
| } |
| } |
| } |
| |
| #[stable(feature = "array_tuple_conv", since = "1.71.0")] |
| impl<T> From<[T; ${count($T)}]> for ($(${ignore($T)} T,)+) { |
| #[inline] |
| #[allow(non_snake_case)] |
| fn from(array: [T; ${count($T)}]) -> Self { |
| let [$($T,)+] = array; |
| ($($T,)+) |
| } |
| } |
| |
| #[stable(feature = "array_tuple_conv", since = "1.71.0")] |
| impl<T> From<($(${ignore($T)} T,)+)> for [T; ${count($T)}] { |
| #[inline] |
| #[allow(non_snake_case)] |
| fn from(tuple: ($(${ignore($T)} T,)+)) -> Self { |
| let ($($T,)+) = tuple; |
| [$($T,)+] |
| } |
| } |
| } |
| } |
| |
| // If this is a unary tuple, it adds a doc comment. |
| // Otherwise, it hides the docs entirely. |
| macro_rules! maybe_tuple_doc { |
| ($a:ident @ #[$meta:meta] $item:item) => { |
| #[doc(fake_variadic)] |
| #[doc = "This trait is implemented for tuples up to twelve items long."] |
| #[$meta] |
| $item |
| }; |
| ($a:ident $($rest_a:ident)+ @ #[$meta:meta] $item:item) => { |
| #[doc(hidden)] |
| #[$meta] |
| $item |
| }; |
| } |
| |
| #[inline] |
| const fn ordering_is_some(c: Option<Ordering>, x: Ordering) -> bool { |
| // FIXME: Just use `==` once that's const-stable on `Option`s. |
| // This is mapping `None` to 2 and then doing the comparison afterwards |
| // because it optimizes better (`None::<Ordering>` is represented as 2). |
| x as i8 |
| == match c { |
| Some(c) => c as i8, |
| None => 2, |
| } |
| } |
| |
| // Constructs an expression that performs a lexical ordering using method `$rel`. |
| // The values are interleaved, so the macro invocation for |
| // `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_ord!(lt, opt_is_lt, a1, b1, |
| // a2, b2, a3, b3)` (and similarly for `lexical_cmp`) |
| // |
| // `$ne_rel` is only used to determine the result after checking that they're |
| // not equal, so `lt` and `le` can both just use `Less`. |
| macro_rules! lexical_ord { |
| ($rel: ident, $ne_rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {{ |
| let c = PartialOrd::partial_cmp(&$a, &$b); |
| if !ordering_is_some(c, Equal) { ordering_is_some(c, $ne_rel) } |
| else { lexical_ord!($rel, $ne_rel, $($rest_a, $rest_b),+) } |
| }}; |
| ($rel: ident, $ne_rel: ident, $a:expr, $b:expr) => { |
| // Use the specific method for the last element |
| PartialOrd::$rel(&$a, &$b) |
| }; |
| } |
| |
| macro_rules! lexical_partial_cmp { |
| ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => { |
| match ($a).partial_cmp(&$b) { |
| Some(Equal) => lexical_partial_cmp!($($rest_a, $rest_b),+), |
| ordering => ordering |
| } |
| }; |
| ($a:expr, $b:expr) => { ($a).partial_cmp(&$b) }; |
| } |
| |
| macro_rules! lexical_cmp { |
| ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => { |
| match ($a).cmp(&$b) { |
| Equal => lexical_cmp!($($rest_a, $rest_b),+), |
| ordering => ordering |
| } |
| }; |
| ($a:expr, $b:expr) => { ($a).cmp(&$b) }; |
| } |
| |
| macro_rules! last_type { |
| ($a:ident,) => { $a }; |
| ($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) }; |
| } |
| |
| tuple_impls!(E D C B A Z Y X W V U T); |