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 caed822

Browse files
committedJan 21, 2025··
Implement phantom variance markers
1 parent b605c65 commit caed822

File tree

2 files changed

+235
-0
lines changed

2 files changed

+235
-0
lines changed
 

Diff for: ‎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 = "none")]
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;

Diff for: ‎library/core/src/marker/variance.rs

+228
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
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+
impl<T> Variance for $name<T> where T: ?Sized {}
34+
35+
impl<T> Default for $name<T>
36+
where T: ?Sized
37+
{
38+
fn default() -> Self {
39+
Self(PhantomData)
40+
}
41+
}
42+
43+
impl<T> fmt::Debug for $name<T>
44+
where T: ?Sized
45+
{
46+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47+
write!(f, "{}<{}>", stringify!($name), type_name::<T>())
48+
}
49+
}
50+
51+
impl<T> Clone for $name<T>
52+
where T: ?Sized
53+
{
54+
fn clone(&self) -> Self {
55+
*self
56+
}
57+
}
58+
59+
impl<T> Copy for $name<T> where T: ?Sized {}
60+
61+
impl<T> PartialEq for $name<T>
62+
where T: ?Sized
63+
{
64+
fn eq(&self, _: &Self) -> bool {
65+
true
66+
}
67+
}
68+
69+
impl<T> Eq for $name<T> where T: ?Sized {}
70+
71+
impl<T> PartialOrd for $name<T>
72+
where T: ?Sized
73+
{
74+
fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
75+
Some(Ordering::Equal)
76+
}
77+
}
78+
79+
impl<T> Ord for $name<T>
80+
where T: ?Sized
81+
{
82+
fn cmp(&self, _: &Self) -> Ordering {
83+
Ordering::Equal
84+
}
85+
}
86+
87+
impl<T> Hash for $name<T>
88+
where T: ?Sized
89+
{
90+
fn hash<H: Hasher>(&self, _: &mut H) {}
91+
}
92+
)*};
93+
}
94+
95+
macro_rules! phantom_lifetime {
96+
($(
97+
$(#[$attr:meta])*
98+
pub struct $name:ident <$lt:lifetime> ($($inner:tt)*);
99+
)*) => {$(
100+
$(#[$attr])*
101+
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
102+
pub struct $name<$lt>($($inner)*);
103+
104+
impl $name<'_> {
105+
/// Constructs a new instance of the variance marker.
106+
pub const fn new() -> Self {
107+
Self(first_token!($($inner)*)(PhantomData))
108+
}
109+
}
110+
111+
impl self::sealed::Sealed for $name<'_> {}
112+
impl Variance for $name<'_> {}
113+
114+
impl fmt::Debug for $name<'_> {
115+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116+
write!(f, "{}", stringify!($name))
117+
}
118+
}
119+
)*};
120+
}
121+
122+
phantom_lifetime! {
123+
/// Zero-sized type used to mark a lifetime as covariant.
124+
///
125+
/// Covariant lifetimes must live at least as long as declared. See [the reference][1] for more
126+
/// information.
127+
///
128+
/// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
129+
///
130+
/// ## Layout
131+
///
132+
/// For all `'a`, the following are guaranteed:
133+
/// * `size_of::<PhantomCovariantLifetime<'a>>() == 0`
134+
/// * `align_of::<PhantomCovariantLifetime<'a>>() == 1`
135+
pub struct PhantomCovariantLifetime<'a>(PhantomCovariant<&'a ()>);
136+
/// Zero-sized type used to mark a lifetime as contravariant.
137+
///
138+
/// Contravariant lifetimes must live at most as long as declared. See [the reference][1] for
139+
/// more information.
140+
///
141+
/// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
142+
///
143+
/// ## Layout
144+
///
145+
/// For all `'a`, the following are guaranteed:
146+
/// * `size_of::<PhantomContravariantLifetime<'a>>() == 0`
147+
/// * `align_of::<PhantomContravariantLifetime<'a>>() == 1`
148+
pub struct PhantomContravariantLifetime<'a>(PhantomContravariant<&'a ()>);
149+
/// Zero-sized type used to mark a lifetime as invariant.
150+
///
151+
/// Invariant lifetimes must be live for the exact length declared, neither shorter nor longer.
152+
/// See [the reference][1] for more information.
153+
///
154+
/// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
155+
///
156+
/// ## Layout
157+
///
158+
/// For all `'a`, the following are guaranteed:
159+
/// * `size_of::<PhantomInvariantLifetime<'a>>() == 0`
160+
/// * `align_of::<PhantomInvariantLifetime<'a>>() == 1`
161+
pub struct PhantomInvariantLifetime<'a>(PhantomInvariant<&'a ()>);
162+
}
163+
164+
phantom_type! {
165+
/// Zero-sized type used to mark a type parameter as covariant.
166+
///
167+
/// Types passed as arguments to functions are covariant. See [the reference][1] for more
168+
/// information.
169+
///
170+
/// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
171+
///
172+
/// ## Layout
173+
///
174+
/// For all `T`, the following are guaranteed:
175+
/// * `size_of::<PhantomCovariant<T>>() == 0`
176+
/// * `align_of::<PhantomCovariant<T>>() == 1`
177+
pub struct PhantomCovariant<T>(PhantomData<T>);
178+
/// Zero-sized type used to mark a type parameter as contravariant.
179+
///
180+
/// Types returned from functions are contravariant. See [the reference][1] for more
181+
/// information.
182+
///
183+
/// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
184+
///
185+
/// ## Layout
186+
///
187+
/// For all `T`, the following are guaranteed:
188+
/// * `size_of::<PhantomContravariant<T>>() == 0`
189+
/// * `align_of::<PhantomContravariant<T>>() == 1`
190+
pub struct PhantomContravariant<T>(PhantomData<fn(T)>);
191+
/// Zero-sized type used to mark a type parameter as invariant.
192+
///
193+
/// Types used as both arguments and return values. See [the reference][1] for more information.
194+
///
195+
/// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
196+
///
197+
/// ## Layout
198+
///
199+
/// For all `T`, the following are guaranteed:
200+
/// * `size_of::<PhantomInvariant<T>>() == 0`
201+
/// * `align_of::<PhantomInvariant<T>>() == 1`
202+
pub struct PhantomInvariant<T>(PhantomData<fn(T) -> T>);
203+
}
204+
205+
mod sealed {
206+
pub trait Sealed {}
207+
}
208+
209+
/// A marker trait for phantom variance types.
210+
pub trait Variance: sealed::Sealed + Default {}
211+
212+
/// Construct a variance marker; equivalent to [`Default::default`].
213+
///
214+
/// This type can be any of the following. You generally should not need to explicitly name the
215+
/// type, however.
216+
///
217+
/// - [`PhantomCovariant`]
218+
/// - [`PhantomContravariant`]
219+
/// - [`PhantomInvariant`]
220+
/// - [`PhantomCovariantLifetime`]
221+
/// - [`PhantomContravariantLifetime`]
222+
/// - [`PhantomInvariantLifetime`]
223+
pub fn variance<T>() -> T
224+
where
225+
T: Variance,
226+
{
227+
T::default()
228+
}

0 commit comments

Comments
 (0)