core/
tuple.rs

1// See core/src/primitive_docs.rs for documentation.
2
3#[cfg(not(feature = "ferrocene_certified"))]
4use crate::cell::CloneFromCell;
5#[cfg(not(feature = "ferrocene_certified"))]
6use crate::cmp::Ordering::{self, *};
7#[cfg(not(feature = "ferrocene_certified"))]
8use crate::marker::{ConstParamTy_, StructuralPartialEq};
9#[cfg(not(feature = "ferrocene_certified"))]
10use crate::ops::ControlFlow::{self, Break, Continue};
11
12// Recursive macro for implementing n-ary tuple functions and operations
13//
14// Also provides implementations for tuples with lesser arity. For example, tuple_impls!(A B C)
15// will implement everything for (A, B, C), (A, B) and (A,).
16macro_rules! tuple_impls {
17    // Stopping criteria (1-ary tuple)
18    ($T:ident) => {
19        tuple_impls!(@impl $T);
20    };
21    // Running criteria (n-ary tuple, with n >= 2)
22    ($T:ident $( $U:ident )+) => {
23        tuple_impls!($( $U )+);
24        tuple_impls!(@impl $T $( $U )+);
25    };
26    // "Private" internal implementation
27    (@impl $( $T:ident )+) => {
28        maybe_tuple_doc! {
29            $($T)+ @
30            #[stable(feature = "rust1", since = "1.0.0")]
31            #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
32            impl<$($T: [const] PartialEq),+> const PartialEq for ($($T,)+) {
33                #[inline]
34                fn eq(&self, other: &($($T,)+)) -> bool {
35                    $( ${ignore($T)} self.${index()} == other.${index()} )&&+
36                }
37                #[inline]
38                fn ne(&self, other: &($($T,)+)) -> bool {
39                    $( ${ignore($T)} self.${index()} != other.${index()} )||+
40                }
41            }
42        }
43
44        #[cfg(not(feature = "ferrocene_certified"))]
45        maybe_tuple_doc! {
46            $($T)+ @
47            #[stable(feature = "rust1", since = "1.0.0")]
48            #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
49            impl<$($T: [const] Eq),+> const Eq for ($($T,)+)
50            {}
51        }
52
53        #[cfg(not(feature = "ferrocene_certified"))]
54        maybe_tuple_doc! {
55            $($T)+ @
56            #[unstable(feature = "adt_const_params", issue = "95174")]
57            #[unstable_feature_bound(unsized_const_params)]
58            impl<$($T: ConstParamTy_),+> ConstParamTy_ for ($($T,)+)
59            {}
60        }
61
62        #[cfg(not(feature = "ferrocene_certified"))]
63        maybe_tuple_doc! {
64            $($T)+ @
65            #[unstable(feature = "structural_match", issue = "31434")]
66            impl<$($T),+> StructuralPartialEq for ($($T,)+)
67            {}
68        }
69
70        #[cfg(not(feature = "ferrocene_certified"))]
71        maybe_tuple_doc! {
72            $($T)+ @
73            #[stable(feature = "rust1", since = "1.0.0")]
74            #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
75            impl<$($T: [const] PartialOrd),+> const PartialOrd for ($($T,)+)
76            {
77                #[inline]
78                fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> {
79                    lexical_partial_cmp!($( ${ignore($T)} self.${index()}, other.${index()} ),+)
80                }
81                #[inline]
82                fn lt(&self, other: &($($T,)+)) -> bool {
83                    lexical_ord!(lt, __chaining_lt, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
84                }
85                #[inline]
86                fn le(&self, other: &($($T,)+)) -> bool {
87                    lexical_ord!(le, __chaining_le, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
88                }
89                #[inline]
90                fn ge(&self, other: &($($T,)+)) -> bool {
91                    lexical_ord!(ge, __chaining_ge, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
92                }
93                #[inline]
94                fn gt(&self, other: &($($T,)+)) -> bool {
95                    lexical_ord!(gt, __chaining_gt, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
96                }
97                #[inline]
98                fn __chaining_lt(&self, other: &($($T,)+)) -> ControlFlow<bool> {
99                    lexical_chain!(__chaining_lt, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
100                }
101                #[inline]
102                fn __chaining_le(&self, other: &($($T,)+)) -> ControlFlow<bool> {
103                    lexical_chain!(__chaining_le, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
104                }
105                #[inline]
106                fn __chaining_gt(&self, other: &($($T,)+)) -> ControlFlow<bool> {
107                    lexical_chain!(__chaining_gt, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
108                }
109                #[inline]
110                fn __chaining_ge(&self, other: &($($T,)+)) -> ControlFlow<bool> {
111                    lexical_chain!(__chaining_ge, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
112                }
113            }
114        }
115
116        #[cfg(not(feature = "ferrocene_certified"))]
117        maybe_tuple_doc! {
118            $($T)+ @
119            #[stable(feature = "rust1", since = "1.0.0")]
120            #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
121            impl<$($T: [const] Ord),+> const Ord for ($($T,)+)
122            {
123                #[inline]
124                fn cmp(&self, other: &($($T,)+)) -> Ordering {
125                    lexical_cmp!($( ${ignore($T)} self.${index()}, other.${index()} ),+)
126                }
127            }
128        }
129
130        #[cfg(not(feature = "ferrocene_certified"))]
131        maybe_tuple_doc! {
132            $($T)+ @
133            #[stable(feature = "rust1", since = "1.0.0")]
134            impl<$($T: Default),+> Default for ($($T,)+) {
135                #[inline]
136                fn default() -> ($($T,)+) {
137                    ($({ let x: $T = Default::default(); x},)+)
138                }
139            }
140        }
141
142        #[cfg(not(feature = "ferrocene_certified"))]
143        maybe_tuple_doc! {
144            $($T)+ @
145            #[stable(feature = "array_tuple_conv", since = "1.71.0")]
146            // can't do const From due to https://github.com/rust-lang/rust/issues/144280
147            impl<T> From<[T; ${count($T)}]> for ($(${ignore($T)} T,)+) {
148                #[inline]
149                #[allow(non_snake_case)]
150                fn from(array: [T; ${count($T)}]) -> Self {
151                    let [$($T,)+] = array;
152                    ($($T,)+)
153                }
154            }
155        }
156
157        #[cfg(not(feature = "ferrocene_certified"))]
158        maybe_tuple_doc! {
159            $($T)+ @
160            #[stable(feature = "array_tuple_conv", since = "1.71.0")]
161            // can't do const From due to https://github.com/rust-lang/rust/issues/144280
162            impl<T> From<($(${ignore($T)} T,)+)> for [T; ${count($T)}] {
163                #[inline]
164                #[allow(non_snake_case)]
165                fn from(tuple: ($(${ignore($T)} T,)+)) -> Self {
166                    let ($($T,)+) = tuple;
167                    [$($T,)+]
168                }
169            }
170        }
171
172        #[cfg(not(feature = "ferrocene_certified"))]
173        maybe_tuple_doc! {
174            $($T)+ @
175            // SAFETY: tuples introduce no additional indirection, so they can be copied whenever T
176            // can.
177            #[unstable(feature = "cell_get_cloned", issue = "145329")]
178            unsafe impl<$($T: CloneFromCell),+> CloneFromCell for ($($T,)+)
179            {}
180        }
181    }
182}
183
184// If this is a unary tuple, it adds a doc comment.
185// Otherwise, it hides the docs entirely.
186macro_rules! maybe_tuple_doc {
187    ($a:ident @ #[$meta:meta] $item:item) => {
188        #[doc(fake_variadic)]
189        #[doc = "This trait is implemented for tuples up to twelve items long."]
190        #[$meta]
191        $item
192    };
193    ($a:ident $($rest_a:ident)+ @ #[$meta:meta] $item:item) => {
194        #[doc(hidden)]
195        #[$meta]
196        $item
197    };
198}
199
200// Constructs an expression that performs a lexical ordering using method `$rel`.
201// The values are interleaved, so the macro invocation for
202// `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_ord!(lt, opt_is_lt, a1, b1,
203// a2, b2, a3, b3)` (and similarly for `lexical_cmp`)
204//
205// `$chain_rel` is the chaining method from `PartialOrd` to use for all but the
206// final value, to produce better results for simple primitives.
207#[cfg(not(feature = "ferrocene_certified"))]
208macro_rules! lexical_ord {
209    ($rel: ident, $chain_rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {{
210        match PartialOrd::$chain_rel(&$a, &$b) {
211            Break(val) => val,
212            Continue(()) => lexical_ord!($rel, $chain_rel, $($rest_a, $rest_b),+),
213        }
214    }};
215    ($rel: ident, $chain_rel: ident, $a:expr, $b:expr) => {
216        // Use the specific method for the last element
217        PartialOrd::$rel(&$a, &$b)
218    };
219}
220
221// Same parameter interleaving as `lexical_ord` above
222#[cfg(not(feature = "ferrocene_certified"))]
223macro_rules! lexical_chain {
224    ($chain_rel: ident, $a:expr, $b:expr $(,$rest_a:expr, $rest_b:expr)*) => {{
225        PartialOrd::$chain_rel(&$a, &$b)?;
226        lexical_chain!($chain_rel $(,$rest_a, $rest_b)*)
227    }};
228    ($chain_rel: ident) => {
229        Continue(())
230    };
231}
232
233#[cfg(not(feature = "ferrocene_certified"))]
234macro_rules! lexical_partial_cmp {
235    ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
236        match ($a).partial_cmp(&$b) {
237            Some(Equal) => lexical_partial_cmp!($($rest_a, $rest_b),+),
238            ordering => ordering
239        }
240    };
241    ($a:expr, $b:expr) => { ($a).partial_cmp(&$b) };
242}
243
244#[cfg(not(feature = "ferrocene_certified"))]
245macro_rules! lexical_cmp {
246    ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
247        match ($a).cmp(&$b) {
248            Equal => lexical_cmp!($($rest_a, $rest_b),+),
249            ordering => ordering
250        }
251    };
252    ($a:expr, $b:expr) => { ($a).cmp(&$b) };
253}
254
255tuple_impls!(E D C B A Z Y X W V U T);