1 | #![unstable (feature = "phantom_variance_markers" , issue = "135806" )] |
2 | |
3 | use super::PhantomData; |
4 | use crate::any::type_name; |
5 | use crate::cmp::Ordering; |
6 | use crate::fmt; |
7 | use crate::hash::{Hash, Hasher}; |
8 | |
9 | macro_rules! first_token { |
10 | ($first:tt $($rest:tt)*) => { |
11 | $first |
12 | }; |
13 | } |
14 | |
15 | macro_rules! phantom_type { |
16 | ($( |
17 | $(#[$attr:meta])* |
18 | pub struct $name:ident <$t:ident> ($($inner:tt)*); |
19 | )*) => {$( |
20 | $(#[$attr])* |
21 | pub struct $name<$t>($($inner)*) where T: ?Sized; |
22 | |
23 | impl<T> $name<T> |
24 | where T: ?Sized |
25 | { |
26 | /// Constructs a new instance of the variance marker. |
27 | pub const fn new() -> Self { |
28 | Self(PhantomData) |
29 | } |
30 | } |
31 | |
32 | impl<T> self::sealed::Sealed for $name<T> where T: ?Sized { |
33 | const VALUE: Self = Self::new(); |
34 | } |
35 | impl<T> Variance for $name<T> where T: ?Sized {} |
36 | |
37 | impl<T> Default for $name<T> |
38 | where T: ?Sized |
39 | { |
40 | fn default() -> Self { |
41 | Self(PhantomData) |
42 | } |
43 | } |
44 | |
45 | impl<T> fmt::Debug for $name<T> |
46 | where T: ?Sized |
47 | { |
48 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
49 | write!(f, "{}<{}>" , stringify!($name), type_name::<T>()) |
50 | } |
51 | } |
52 | |
53 | impl<T> Clone for $name<T> |
54 | where T: ?Sized |
55 | { |
56 | fn clone(&self) -> Self { |
57 | *self |
58 | } |
59 | } |
60 | |
61 | impl<T> Copy for $name<T> where T: ?Sized {} |
62 | |
63 | impl<T> PartialEq for $name<T> |
64 | where T: ?Sized |
65 | { |
66 | fn eq(&self, _: &Self) -> bool { |
67 | true |
68 | } |
69 | } |
70 | |
71 | impl<T> Eq for $name<T> where T: ?Sized {} |
72 | |
73 | impl<T> PartialOrd for $name<T> |
74 | where T: ?Sized |
75 | { |
76 | fn partial_cmp(&self, _: &Self) -> Option<Ordering> { |
77 | Some(Ordering::Equal) |
78 | } |
79 | } |
80 | |
81 | impl<T> Ord for $name<T> |
82 | where T: ?Sized |
83 | { |
84 | fn cmp(&self, _: &Self) -> Ordering { |
85 | Ordering::Equal |
86 | } |
87 | } |
88 | |
89 | impl<T> Hash for $name<T> |
90 | where T: ?Sized |
91 | { |
92 | fn hash<H: Hasher>(&self, _: &mut H) {} |
93 | } |
94 | )*}; |
95 | } |
96 | |
97 | macro_rules! phantom_lifetime { |
98 | ($( |
99 | $(#[$attr:meta])* |
100 | pub struct $name:ident <$lt:lifetime> ($($inner:tt)*); |
101 | )*) => {$( |
102 | $(#[$attr])* |
103 | #[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
104 | pub struct $name<$lt>($($inner)*); |
105 | |
106 | impl $name<'_> { |
107 | /// Constructs a new instance of the variance marker. |
108 | pub const fn new() -> Self { |
109 | Self(first_token!($($inner)*)(PhantomData)) |
110 | } |
111 | } |
112 | |
113 | impl self::sealed::Sealed for $name<'_> { |
114 | const VALUE: Self = Self::new(); |
115 | } |
116 | impl Variance for $name<'_> {} |
117 | |
118 | impl fmt::Debug for $name<'_> { |
119 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
120 | write!(f, "{}" , stringify!($name)) |
121 | } |
122 | } |
123 | )*}; |
124 | } |
125 | |
126 | phantom_lifetime! { |
127 | /// Zero-sized type used to mark a lifetime as covariant. |
128 | /// |
129 | /// Covariant lifetimes must live at least as long as declared. See [the reference][1] for more |
130 | /// information. |
131 | /// |
132 | /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance |
133 | /// |
134 | /// ## Layout |
135 | /// |
136 | /// For all `'a`, the following are guaranteed: |
137 | /// * `size_of::<PhantomCovariantLifetime<'a>>() == 0` |
138 | /// * `align_of::<PhantomCovariantLifetime<'a>>() == 1` |
139 | #[rustc_pub_transparent] |
140 | #[repr (transparent)] |
141 | pub struct PhantomCovariantLifetime<'a>(PhantomCovariant<&'a ()>); |
142 | /// Zero-sized type used to mark a lifetime as contravariant. |
143 | /// |
144 | /// Contravariant lifetimes must live at most as long as declared. See [the reference][1] for |
145 | /// more information. |
146 | /// |
147 | /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance |
148 | /// |
149 | /// ## Layout |
150 | /// |
151 | /// For all `'a`, the following are guaranteed: |
152 | /// * `size_of::<PhantomContravariantLifetime<'a>>() == 0` |
153 | /// * `align_of::<PhantomContravariantLifetime<'a>>() == 1` |
154 | #[rustc_pub_transparent] |
155 | #[repr (transparent)] |
156 | pub struct PhantomContravariantLifetime<'a>(PhantomContravariant<&'a ()>); |
157 | /// Zero-sized type used to mark a lifetime as invariant. |
158 | /// |
159 | /// Invariant lifetimes must be live for the exact length declared, neither shorter nor longer. |
160 | /// See [the reference][1] for more information. |
161 | /// |
162 | /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance |
163 | /// |
164 | /// ## Layout |
165 | /// |
166 | /// For all `'a`, the following are guaranteed: |
167 | /// * `size_of::<PhantomInvariantLifetime<'a>>() == 0` |
168 | /// * `align_of::<PhantomInvariantLifetime<'a>>() == 1` |
169 | #[rustc_pub_transparent] |
170 | #[repr (transparent)] |
171 | pub struct PhantomInvariantLifetime<'a>(PhantomInvariant<&'a ()>); |
172 | } |
173 | |
174 | phantom_type! { |
175 | /// Zero-sized type used to mark a type parameter as covariant. |
176 | /// |
177 | /// Types used as part of the return value from a function are covariant. If the type is _also_ |
178 | /// passed as a parameter then it is [invariant][PhantomInvariant]. See [the reference][1] for |
179 | /// more information. |
180 | /// |
181 | /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance |
182 | /// |
183 | /// ## Layout |
184 | /// |
185 | /// For all `T`, the following are guaranteed: |
186 | /// * `size_of::<PhantomCovariant<T>>() == 0` |
187 | /// * `align_of::<PhantomCovariant<T>>() == 1` |
188 | #[rustc_pub_transparent] |
189 | #[repr (transparent)] |
190 | pub struct PhantomCovariant<T>(PhantomData<fn() -> T>); |
191 | /// Zero-sized type used to mark a type parameter as contravariant. |
192 | /// |
193 | /// Types passed as arguments to a function are contravariant. If the type is _also_ part of the |
194 | /// return value from a function then it is [invariant][PhantomInvariant]. See [the |
195 | /// reference][1] for more information. |
196 | /// |
197 | /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance |
198 | /// |
199 | /// ## Layout |
200 | /// |
201 | /// For all `T`, the following are guaranteed: |
202 | /// * `size_of::<PhantomContravariant<T>>() == 0` |
203 | /// * `align_of::<PhantomContravariant<T>>() == 1` |
204 | #[rustc_pub_transparent] |
205 | #[repr (transparent)] |
206 | pub struct PhantomContravariant<T>(PhantomData<fn(T)>); |
207 | /// Zero-sized type used to mark a type parameter as invariant. |
208 | /// |
209 | /// Types that are both passed as an argument _and_ used as part of the return value from a |
210 | /// function are invariant. See [the reference][1] for more information. |
211 | /// |
212 | /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance |
213 | /// |
214 | /// ## Layout |
215 | /// |
216 | /// For all `T`, the following are guaranteed: |
217 | /// * `size_of::<PhantomInvariant<T>>() == 0` |
218 | /// * `align_of::<PhantomInvariant<T>>() == 1` |
219 | #[rustc_pub_transparent] |
220 | #[repr (transparent)] |
221 | pub struct PhantomInvariant<T>(PhantomData<fn(T) -> T>); |
222 | } |
223 | |
224 | mod sealed { |
225 | pub trait Sealed { |
226 | const VALUE: Self; |
227 | } |
228 | } |
229 | |
230 | /// A marker trait for phantom variance types. |
231 | pub trait Variance: sealed::Sealed + Default {} |
232 | |
233 | /// Construct a variance marker; equivalent to [`Default::default`]. |
234 | /// |
235 | /// This type can be any of the following. You generally should not need to explicitly name the |
236 | /// type, however. |
237 | /// |
238 | /// - [`PhantomCovariant`] |
239 | /// - [`PhantomContravariant`] |
240 | /// - [`PhantomInvariant`] |
241 | /// - [`PhantomCovariantLifetime`] |
242 | /// - [`PhantomContravariantLifetime`] |
243 | /// - [`PhantomInvariantLifetime`] |
244 | /// |
245 | /// # Example |
246 | /// |
247 | /// ```rust |
248 | /// #![feature(phantom_variance_markers)] |
249 | /// |
250 | /// use core::marker::{PhantomCovariant, variance}; |
251 | /// |
252 | /// struct BoundFn<F, P, R> |
253 | /// where |
254 | /// F: Fn(P) -> R, |
255 | /// { |
256 | /// function: F, |
257 | /// parameter: P, |
258 | /// return_value: PhantomCovariant<R>, |
259 | /// } |
260 | /// |
261 | /// let bound_fn = BoundFn { |
262 | /// function: core::convert::identity, |
263 | /// parameter: 5u8, |
264 | /// return_value: variance(), |
265 | /// }; |
266 | /// ``` |
267 | pub const fn variance<T>() -> T |
268 | where |
269 | T: Variance, |
270 | { |
271 | T::VALUE |
272 | } |
273 | |