1 | // See core/src/primitive_docs.rs for documentation. |
2 | |
3 | use crate::cmp::Ordering::{self, *}; |
4 | use crate::marker::ConstParamTy; |
5 | use 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,). |
11 | macro_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. |
151 | macro_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 ] |
166 | const 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`. |
184 | macro_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 | |
196 | macro_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 | |
206 | macro_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 | |
216 | macro_rules! last_type { |
217 | ($a:ident,) => { $a }; |
218 | ($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) }; |
219 | } |
220 | |
221 | tuple_impls!(E D C B A Z Y X W V U T); |
222 | |