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 | /// Note: If `'a` is otherwise contravariant or invariant, the resulting type is invariant. |
135 | /// |
136 | /// ## Layout |
137 | /// |
138 | /// For all `'a`, the following are guaranteed: |
139 | /// * `size_of::<PhantomCovariantLifetime<'a>>() == 0` |
140 | /// * `align_of::<PhantomCovariantLifetime<'a>>() == 1` |
141 | #[rustc_pub_transparent] |
142 | #[repr (transparent)] |
143 | pub struct PhantomCovariantLifetime<'a>(PhantomCovariant<&'a ()>); |
144 | /// Zero-sized type used to mark a lifetime as contravariant. |
145 | /// |
146 | /// Contravariant lifetimes must live at most as long as declared. See [the reference][1] for |
147 | /// more information. |
148 | /// |
149 | /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance |
150 | /// |
151 | /// Note: If `'a` is otherwise covariant or invariant, the resulting type is invariant. |
152 | /// |
153 | /// ## Layout |
154 | /// |
155 | /// For all `'a`, the following are guaranteed: |
156 | /// * `size_of::<PhantomContravariantLifetime<'a>>() == 0` |
157 | /// * `align_of::<PhantomContravariantLifetime<'a>>() == 1` |
158 | #[rustc_pub_transparent] |
159 | #[repr (transparent)] |
160 | pub struct PhantomContravariantLifetime<'a>(PhantomContravariant<&'a ()>); |
161 | /// Zero-sized type used to mark a lifetime as invariant. |
162 | /// |
163 | /// Invariant lifetimes must be live for the exact length declared, neither shorter nor longer. |
164 | /// See [the reference][1] for more information. |
165 | /// |
166 | /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance |
167 | /// |
168 | /// ## Layout |
169 | /// |
170 | /// For all `'a`, the following are guaranteed: |
171 | /// * `size_of::<PhantomInvariantLifetime<'a>>() == 0` |
172 | /// * `align_of::<PhantomInvariantLifetime<'a>>() == 1` |
173 | #[rustc_pub_transparent] |
174 | #[repr (transparent)] |
175 | pub struct PhantomInvariantLifetime<'a>(PhantomInvariant<&'a ()>); |
176 | } |
177 | |
178 | phantom_type! { |
179 | /// Zero-sized type used to mark a type parameter as covariant. |
180 | /// |
181 | /// Types used as part of the return value from a function are covariant. If the type is _also_ |
182 | /// passed as a parameter then it is [invariant][PhantomInvariant]. See [the reference][1] for |
183 | /// more information. |
184 | /// |
185 | /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance |
186 | /// |
187 | /// Note: If `T` is otherwise contravariant or invariant, the resulting type is invariant. |
188 | /// |
189 | /// ## Layout |
190 | /// |
191 | /// For all `T`, the following are guaranteed: |
192 | /// * `size_of::<PhantomCovariant<T>>() == 0` |
193 | /// * `align_of::<PhantomCovariant<T>>() == 1` |
194 | #[rustc_pub_transparent] |
195 | #[repr (transparent)] |
196 | pub struct PhantomCovariant<T>(PhantomData<fn() -> T>); |
197 | /// Zero-sized type used to mark a type parameter as contravariant. |
198 | /// |
199 | /// Types passed as arguments to a function are contravariant. If the type is _also_ part of the |
200 | /// return value from a function then it is [invariant][PhantomInvariant]. See [the |
201 | /// reference][1] for more information. |
202 | /// |
203 | /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance |
204 | /// |
205 | /// Note: If `T` is otherwise covariant or invariant, the resulting type is invariant. |
206 | /// |
207 | /// ## Layout |
208 | /// |
209 | /// For all `T`, the following are guaranteed: |
210 | /// * `size_of::<PhantomContravariant<T>>() == 0` |
211 | /// * `align_of::<PhantomContravariant<T>>() == 1` |
212 | #[rustc_pub_transparent] |
213 | #[repr (transparent)] |
214 | pub struct PhantomContravariant<T>(PhantomData<fn(T)>); |
215 | /// Zero-sized type used to mark a type parameter as invariant. |
216 | /// |
217 | /// Types that are both passed as an argument _and_ used as part of the return value from a |
218 | /// function are invariant. See [the reference][1] for more information. |
219 | /// |
220 | /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance |
221 | /// |
222 | /// ## Layout |
223 | /// |
224 | /// For all `T`, the following are guaranteed: |
225 | /// * `size_of::<PhantomInvariant<T>>() == 0` |
226 | /// * `align_of::<PhantomInvariant<T>>() == 1` |
227 | #[rustc_pub_transparent] |
228 | #[repr (transparent)] |
229 | pub struct PhantomInvariant<T>(PhantomData<fn(T) -> T>); |
230 | } |
231 | |
232 | mod sealed { |
233 | pub trait Sealed { |
234 | const VALUE: Self; |
235 | } |
236 | } |
237 | |
238 | /// A marker trait for phantom variance types. |
239 | pub trait Variance: sealed::Sealed + Default {} |
240 | |
241 | /// Construct a variance marker; equivalent to [`Default::default`]. |
242 | /// |
243 | /// This type can be any of the following. You generally should not need to explicitly name the |
244 | /// type, however. |
245 | /// |
246 | /// - [`PhantomCovariant`] |
247 | /// - [`PhantomContravariant`] |
248 | /// - [`PhantomInvariant`] |
249 | /// - [`PhantomCovariantLifetime`] |
250 | /// - [`PhantomContravariantLifetime`] |
251 | /// - [`PhantomInvariantLifetime`] |
252 | /// |
253 | /// # Example |
254 | /// |
255 | /// ```rust |
256 | /// #![feature(phantom_variance_markers)] |
257 | /// |
258 | /// use core::marker::{PhantomCovariant, variance}; |
259 | /// |
260 | /// struct BoundFn<F, P, R> |
261 | /// where |
262 | /// F: Fn(P) -> R, |
263 | /// { |
264 | /// function: F, |
265 | /// parameter: P, |
266 | /// return_value: PhantomCovariant<R>, |
267 | /// } |
268 | /// |
269 | /// let bound_fn = BoundFn { |
270 | /// function: core::convert::identity, |
271 | /// parameter: 5u8, |
272 | /// return_value: variance(), |
273 | /// }; |
274 | /// ``` |
275 | pub const fn variance<T>() -> T |
276 | where |
277 | T: Variance, |
278 | { |
279 | T::VALUE |
280 | } |
281 | |