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 #[stable(feature = "rust1", since = "1.0.0")]
67 impl<$($T: PartialOrd),+> PartialOrd for ($($T,)+)
68 where
69 last_type!($($T,)+): ?Sized
70 {
71 #[inline]
72 fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> {
73 lexical_partial_cmp!($( ${ignore($T)} self.${index()}, other.${index()} ),+)
74 }
75 #[inline]
76 fn lt(&self, other: &($($T,)+)) -> bool {
77 lexical_ord!(lt, Less, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
78 }
79 #[inline]
80 fn le(&self, other: &($($T,)+)) -> bool {
81 lexical_ord!(le, Less, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
82 }
83 #[inline]
84 fn ge(&self, other: &($($T,)+)) -> bool {
85 lexical_ord!(ge, Greater, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
86 }
87 #[inline]
88 fn gt(&self, other: &($($T,)+)) -> bool {
89 lexical_ord!(gt, Greater, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
90 }
91 }
92 }
93
94 maybe_tuple_doc! {
95 $($T)+ @
96 #[stable(feature = "rust1", since = "1.0.0")]
97 impl<$($T: Ord),+> Ord for ($($T,)+)
98 where
99 last_type!($($T,)+): ?Sized
100 {
101 #[inline]
102 fn cmp(&self, other: &($($T,)+)) -> Ordering {
103 lexical_cmp!($( ${ignore($T)} self.${index()}, other.${index()} ),+)
104 }
105 }
106 }
107
108 maybe_tuple_doc! {
109 $($T)+ @
110 #[stable(feature = "rust1", since = "1.0.0")]
111 impl<$($T: Default),+> Default for ($($T,)+) {
112 #[inline]
113 fn default() -> ($($T,)+) {
114 ($({ let x: $T = Default::default(); x},)+)
115 }
116 }
117 }
118
119 #[stable(feature = "array_tuple_conv", since = "1.71.0")]
120 impl<T> From<[T; ${count($T)}]> for ($(${ignore($T)} T,)+) {
121 #[inline]
122 #[allow(non_snake_case)]
123 fn from(array: [T; ${count($T)}]) -> Self {
124 let [$($T,)+] = array;
125 ($($T,)+)
126 }
127 }
128
129 #[stable(feature = "array_tuple_conv", since = "1.71.0")]
130 impl<T> From<($(${ignore($T)} T,)+)> for [T; ${count($T)}] {
131 #[inline]
132 #[allow(non_snake_case)]
133 fn from(tuple: ($(${ignore($T)} T,)+)) -> Self {
134 let ($($T,)+) = tuple;
135 [$($T,)+]
136 }
137 }
138 }
139}
140
141// If this is a unary tuple, it adds a doc comment.
142// Otherwise, it hides the docs entirely.
143macro_rules! maybe_tuple_doc {
144 ($a:ident @ #[$meta:meta] $item:item) => {
145 #[doc(fake_variadic)]
146 #[doc = "This trait is implemented for tuples up to twelve items long."]
147 #[$meta]
148 $item
149 };
150 ($a:ident $($rest_a:ident)+ @ #[$meta:meta] $item:item) => {
151 #[doc(hidden)]
152 #[$meta]
153 $item
154 };
155}
156
157// Constructs an expression that performs a lexical ordering using method `$rel`.
158// The values are interleaved, so the macro invocation for
159// `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_ord!(lt, opt_is_lt, a1, b1,
160// a2, b2, a3, b3)` (and similarly for `lexical_cmp`)
161//
162// `$ne_rel` is only used to determine the result after checking that they're
163// not equal, so `lt` and `le` can both just use `Less`.
164macro_rules! lexical_ord {
165 ($rel: ident, $ne_rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {{
166 let c = PartialOrd::partial_cmp(&$a, &$b);
167 if c != Some(Equal) { c == Some($ne_rel) }
168 else { lexical_ord!($rel, $ne_rel, $($rest_a, $rest_b),+) }
169 }};
170 ($rel: ident, $ne_rel: ident, $a:expr, $b:expr) => {
171 // Use the specific method for the last element
172 PartialOrd::$rel(&$a, &$b)
173 };
174}
175
176macro_rules! lexical_partial_cmp {
177 ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
178 match ($a).partial_cmp(&$b) {
179 Some(Equal) => lexical_partial_cmp!($($rest_a, $rest_b),+),
180 ordering => ordering
181 }
182 };
183 ($a:expr, $b:expr) => { ($a).partial_cmp(&$b) };
184}
185
186macro_rules! lexical_cmp {
187 ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
188 match ($a).cmp(&$b) {
189 Equal => lexical_cmp!($($rest_a, $rest_b),+),
190 ordering => ordering
191 }
192 };
193 ($a:expr, $b:expr) => { ($a).cmp(&$b) };
194}
195
196macro_rules! last_type {
197 ($a:ident,) => { $a };
198 ($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) };
199}
200
201tuple_impls!(E D C B A Z Y X W V U T);
202