Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c558d94

Browse files
committedJan 22, 2025
Implement phantom variance markers
1 parent b605c65 commit c558d94

File tree

2 files changed

+241
-0
lines changed

2 files changed

+241
-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

+234
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
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 passed as arguments to functions are covariant. See [the reference][1] for more
172+
/// information.
173+
///
174+
/// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
175+
///
176+
/// ## Layout
177+
///
178+
/// For all `T`, the following are guaranteed:
179+
/// * `size_of::<PhantomCovariant<T>>() == 0`
180+
/// * `align_of::<PhantomCovariant<T>>() == 1`
181+
pub struct PhantomCovariant<T>(PhantomData<T>);
182+
/// Zero-sized type used to mark a type parameter as contravariant.
183+
///
184+
/// Types returned from functions are contravariant. See [the reference][1] for more
185+
/// information.
186+
///
187+
/// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
188+
///
189+
/// ## Layout
190+
///
191+
/// For all `T`, the following are guaranteed:
192+
/// * `size_of::<PhantomContravariant<T>>() == 0`
193+
/// * `align_of::<PhantomContravariant<T>>() == 1`
194+
pub struct PhantomContravariant<T>(PhantomData<fn(T)>);
195+
/// Zero-sized type used to mark a type parameter as invariant.
196+
///
197+
/// Types used as both arguments and return values. See [the reference][1] for more information.
198+
///
199+
/// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
200+
///
201+
/// ## Layout
202+
///
203+
/// For all `T`, the following are guaranteed:
204+
/// * `size_of::<PhantomInvariant<T>>() == 0`
205+
/// * `align_of::<PhantomInvariant<T>>() == 1`
206+
pub struct PhantomInvariant<T>(PhantomData<fn(T) -> T>);
207+
}
208+
209+
mod sealed {
210+
pub trait Sealed {
211+
const VALUE: Self;
212+
}
213+
}
214+
215+
/// A marker trait for phantom variance types.
216+
pub trait Variance: sealed::Sealed + Default {}
217+
218+
/// Construct a variance marker; equivalent to [`Default::default`].
219+
///
220+
/// This type can be any of the following. You generally should not need to explicitly name the
221+
/// type, however.
222+
///
223+
/// - [`PhantomCovariant`]
224+
/// - [`PhantomContravariant`]
225+
/// - [`PhantomInvariant`]
226+
/// - [`PhantomCovariantLifetime`]
227+
/// - [`PhantomContravariantLifetime`]
228+
/// - [`PhantomInvariantLifetime`]
229+
pub const fn variance<T>() -> T
230+
where
231+
T: Variance,
232+
{
233+
T::VALUE
234+
}

0 commit comments

Comments
 (0)