1// See core/src/primitive_docs.rs for documentation.
2
3use crate::cmp::Ordering::{self, *};
4use crate::marker::ConstParamTy;
5use crate::marker::StructuralPartialEq;
6
7// Recursive macro for implementing n-ary tuple functions and operations
8//
9// Also provides implementations for tuples with lesser arity. For example, tuple_impls!(A B C)
10// will implement everything for (A, B, C), (A, B) and (A,).
11macro_rules! tuple_impls {
12 // Stopping criteria (1-ary tuple)
13 ($T:ident) => {
14 tuple_impls!(@impl $T);
15 };
16 // Running criteria (n-ary tuple, with n >= 2)
17 ($T:ident $( $U:ident )+) => {
18 tuple_impls!($( $U )+);
19 tuple_impls!(@impl $T $( $U )+);
20 };
21 // "Private" internal implementation
22 (@impl $( $T:ident )+) => {
23 maybe_tuple_doc! {
24 $($T)+ @
25 #[stable(feature = "rust1", since = "1.0.0")]
26 impl<$($T: PartialEq),+> PartialEq for ($($T,)+)
27 where
28 last_type!($($T,)+): ?Sized
29 {
30 #[inline]
31 fn eq(&self, other: &($($T,)+)) -> bool {
32 $( ${ignore($T)} self.${index()} == other.${index()} )&&+
33 }
34 #[inline]
35 fn ne(&self, other: &($($T,)+)) -> bool {
36 $( ${ignore($T)} self.${index()} != other.${index()} )||+
37 }
38 }
39 }
40
41 maybe_tuple_doc! {
42 $($T)+ @
43 #[stable(feature = "rust1", since = "1.0.0")]
44 impl<$($T: Eq),+> Eq for ($($T,)+)
45 where
46 last_type!($($T,)+): ?Sized
47 {}
48 }
49
50 maybe_tuple_doc! {
51 $($T)+ @
52 #[unstable(feature = "structural_match", issue = "31434")]
53 impl<$($T: ConstParamTy),+> ConstParamTy for ($($T,)+)
54 {}
55 }
56
57 maybe_tuple_doc! {
58 $($T)+ @
59 #[unstable(feature = "structural_match", issue = "31434")]
60 impl<$($T),+> StructuralPartialEq for ($($T,)+)
61 {}
62 }
63
64 maybe_tuple_doc! {
65 $($T)+ @
66 #[unstable(feature = "structural_match", issue = "31434")]
67 #[cfg(bootstrap)]
68 impl<$($T),+> crate::marker::StructuralEq for ($($T,)+)
69 {}
70 }
71
72 maybe_tuple_doc! {
73 $($T)+ @
74 #[stable(feature = "rust1", since = "1.0.0")]
75 impl<$($T: PartialOrd),+> PartialOrd for ($($T,)+)
76 where
77 last_type!($($T,)+): ?Sized
78 {
79 #[inline]
80 fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> {
81 lexical_partial_cmp!($( ${ignore($T)} self.${index()}, other.${index()} ),+)
82 }
83 #[inline]
84 fn lt(&self, other: &($($T,)+)) -> bool {
85 lexical_ord!(lt, Less, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
86 }
87 #[inline]
88 fn le(&self, other: &($($T,)+)) -> bool {
89 lexical_ord!(le, Less, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
90 }
91 #[inline]
92 fn ge(&self, other: &($($T,)+)) -> bool {
93 lexical_ord!(ge, Greater, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
94 }
95 #[inline]
96 fn gt(&self, other: &($($T,)+)) -> bool {
97 lexical_ord!(gt, Greater, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
98 }
99 }
100 }
101
102 maybe_tuple_doc! {
103 $($T)+ @
104 #[stable(feature = "rust1", since = "1.0.0")]
105 impl<$($T: Ord),+> Ord for ($($T,)+)
106 where
107 last_type!($($T,)+): ?Sized
108 {
109 #[inline]
110 fn cmp(&self, other: &($($T,)+)) -> Ordering {
111 lexical_cmp!($( ${ignore($T)} self.${index()}, other.${index()} ),+)
112 }
113 }
114 }
115
116 maybe_tuple_doc! {
117 $($T)+ @
118 #[stable(feature = "rust1", since = "1.0.0")]
119 impl<$($T: Default),+> Default for ($($T,)+) {
120 #[inline]
121 fn default() -> ($($T,)+) {
122 ($({ let x: $T = Default::default(); x},)+)
123 }
124 }
125 }
126
127 #[stable(feature = "array_tuple_conv", since = "1.71.0")]
128 impl<T> From<[T; ${count($T)}]> for ($(${ignore($T)} T,)+) {
129 #[inline]
130 #[allow(non_snake_case)]
131 fn from(array: [T; ${count($T)}]) -> Self {
132 let [$($T,)+] = array;
133 ($($T,)+)
134 }
135 }
136
137 #[stable(feature = "array_tuple_conv", since = "1.71.0")]
138 impl<T> From<($(${ignore($T)} T,)+)> for [T; ${count($T)}] {
139 #[inline]
140 #[allow(non_snake_case)]
141 fn from(tuple: ($(${ignore($T)} T,)+)) -> Self {
142 let ($($T,)+) = tuple;
143 [$($T,)+]
144 }
145 }
146 }
147}
148
149// If this is a unary tuple, it adds a doc comment.
150// Otherwise, it hides the docs entirely.
151macro_rules! maybe_tuple_doc {
152 ($a:ident @ #[$meta:meta] $item:item) => {
153 #[doc(fake_variadic)]
154 #[doc = "This trait is implemented for tuples up to twelve items long."]
155 #[$meta]
156 $item
157 };
158 ($a:ident $($rest_a:ident)+ @ #[$meta:meta] $item:item) => {
159 #[doc(hidden)]
160 #[$meta]
161 $item
162 };
163}
164
165#[inline]
166const fn ordering_is_some(c: Option<Ordering>, x: Ordering) -> bool {
167 // FIXME: Just use `==` once that's const-stable on `Option`s.
168 // This is mapping `None` to 2 and then doing the comparison afterwards
169 // because it optimizes better (`None::<Ordering>` is represented as 2).
170 x as i8
171 == match c {
172 Some(c: Ordering) => c as i8,
173 None => 2,
174 }
175}
176
177// Constructs an expression that performs a lexical ordering using method `$rel`.
178// The values are interleaved, so the macro invocation for
179// `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_ord!(lt, opt_is_lt, a1, b1,
180// a2, b2, a3, b3)` (and similarly for `lexical_cmp`)
181//
182// `$ne_rel` is only used to determine the result after checking that they're
183// not equal, so `lt` and `le` can both just use `Less`.
184macro_rules! lexical_ord {
185 ($rel: ident, $ne_rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {{
186 let c = PartialOrd::partial_cmp(&$a, &$b);
187 if !ordering_is_some(c, Equal) { ordering_is_some(c, $ne_rel) }
188 else { lexical_ord!($rel, $ne_rel, $($rest_a, $rest_b),+) }
189 }};
190 ($rel: ident, $ne_rel: ident, $a:expr, $b:expr) => {
191 // Use the specific method for the last element
192 PartialOrd::$rel(&$a, &$b)
193 };
194}
195
196macro_rules! lexical_partial_cmp {
197 ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
198 match ($a).partial_cmp(&$b) {
199 Some(Equal) => lexical_partial_cmp!($($rest_a, $rest_b),+),
200 ordering => ordering
201 }
202 };
203 ($a:expr, $b:expr) => { ($a).partial_cmp(&$b) };
204}
205
206macro_rules! lexical_cmp {
207 ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
208 match ($a).cmp(&$b) {
209 Equal => lexical_cmp!($($rest_a, $rest_b),+),
210 ordering => ordering
211 }
212 };
213 ($a:expr, $b:expr) => { ($a).cmp(&$b) };
214}
215
216macro_rules! last_type {
217 ($a:ident,) => { $a };
218 ($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) };
219}
220
221tuple_impls!(E D C B A Z Y X W V U T);
222