core/marker/variance.rs
1#![unstable(feature = "phantom_variance_markers", issue = "135806")]
2
3use super::PhantomData;
4use crate::any::type_name;
5use crate::cmp::Ordering;
6use crate::fmt;
7use crate::hash::{Hash, Hasher};
8
9macro_rules! first_token {
10 ($first:tt $($rest:tt)*) => {
11 $first
12 };
13}
14
15macro_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
97macro_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
126phantom_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
178phantom_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
232mod sealed {
233 pub trait Sealed {
234 const VALUE: Self;
235 }
236}
237
238/// A marker trait for phantom variance types.
239pub 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/// ```
275pub const fn variance<T>() -> T
276where
277 T: Variance,
278{
279 T::VALUE
280}