Skip to content

Commit b3a5d0a

Browse files
committed
Implement phantom variance markers
1 parent b605c65 commit b3a5d0a

File tree

2 files changed

+267
-0
lines changed

2 files changed

+267
-0
lines changed

library/core/src/marker.rs

+7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66
77
#![stable(feature = "rust1", since = "1.0.0")]
88

9+
mod variance;
10+
11+
#[unstable(feature = "phantom_variance_markers", issue = "135806")]
12+
pub use self::variance::{
13+
PhantomContravariant, PhantomContravariantLifetime, PhantomCovariant, PhantomCovariantLifetime,
14+
PhantomInvariant, PhantomInvariantLifetime, Variance, variance,
15+
};
916
use crate::cell::UnsafeCell;
1017
use crate::cmp;
1118
use crate::fmt::Debug;

library/core/src/marker/variance.rs

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

0 commit comments

Comments
 (0)