//! This is a copy of [`std::marker::variance`]. use std::any::type_name; use std::cmp::Ordering; use std::fmt; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; macro_rules! first_token { ($first:tt $($rest:tt)*) => { $first }; } macro_rules! phantom_type { ($( $(#[$attr:meta])* pub struct $name:ident <$t:ident> ($($inner:tt)*); )*) => {$( $(#[$attr])* pub struct $name<$t>($($inner)*) where T: ?Sized; impl $name where T: ?Sized { /// Constructs a new instance of the variance marker. pub const fn new() -> Self { Self(PhantomData) } } impl self::sealed::Sealed for $name where T: ?Sized { const VALUE: Self = Self::new(); } impl Variance for $name where T: ?Sized {} impl Default for $name where T: ?Sized { fn default() -> Self { Self(PhantomData) } } impl fmt::Debug for $name where T: ?Sized { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}<{}>", stringify!($name), type_name::()) } } impl Clone for $name where T: ?Sized { fn clone(&self) -> Self { *self } } impl Copy for $name where T: ?Sized {} impl PartialEq for $name where T: ?Sized { fn eq(&self, _: &Self) -> bool { true } } impl Eq for $name where T: ?Sized {} #[allow(clippy::non_canonical_partial_ord_impl)] impl PartialOrd for $name where T: ?Sized { fn partial_cmp(&self, _: &Self) -> Option { Some(Ordering::Equal) } } impl Ord for $name where T: ?Sized { fn cmp(&self, _: &Self) -> Ordering { Ordering::Equal } } impl Hash for $name where T: ?Sized { fn hash(&self, _: &mut H) {} } )*}; } macro_rules! phantom_lifetime { ($( $(#[$attr:meta])* pub struct $name:ident <$lt:lifetime> ($($inner:tt)*); )*) => {$( $(#[$attr])* #[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct $name<$lt>($($inner)*); impl $name<'_> { /// Constructs a new instance of the variance marker. pub const fn new() -> Self { Self(first_token!($($inner)*)(PhantomData)) } } impl self::sealed::Sealed for $name<'_> { const VALUE: Self = Self::new(); } impl Variance for $name<'_> {} impl fmt::Debug for $name<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", stringify!($name)) } } )*}; } phantom_lifetime! { /// Zero-sized type used to mark a lifetime as covariant. /// /// Covariant lifetimes must live at least as long as declared. See [the reference][1] for more /// information. /// /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance /// /// ## Layout /// /// For all `'a`, the following are guaranteed: /// * `size_of::>() == 0` /// * `align_of::>() == 1` pub struct PhantomCovariantLifetime<'a>(PhantomCovariant<&'a ()>); /// Zero-sized type used to mark a lifetime as contravariant. /// /// Contravariant lifetimes must live at most as long as declared. See [the reference][1] for /// more information. /// /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance /// /// ## Layout /// /// For all `'a`, the following are guaranteed: /// * `size_of::>() == 0` /// * `align_of::>() == 1` pub struct PhantomContravariantLifetime<'a>(PhantomContravariant<&'a ()>); /// Zero-sized type used to mark a lifetime as invariant. /// /// Invariant lifetimes must be live for the exact length declared, neither shorter nor longer. /// See [the reference][1] for more information. /// /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance /// /// ## Layout /// /// For all `'a`, the following are guaranteed: /// * `size_of::>() == 0` /// * `align_of::>() == 1` pub struct PhantomInvariantLifetime<'a>(PhantomInvariant<&'a ()>); } phantom_type! { /// Zero-sized type used to mark a type parameter as covariant. /// /// Types used as part of the return value from a function are covariant. If the type is _also_ /// passed as a parameter then it is [invariant][PhantomInvariant]. See [the reference][1] for /// more information. /// /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance /// /// ## Layout /// /// For all `T`, the following are guaranteed: /// * `size_of::>() == 0` /// * `align_of::>() == 1` pub struct PhantomCovariant(PhantomData T>); /// Zero-sized type used to mark a type parameter as contravariant. /// /// Types passed as arguments to a function are contravariant. If the type is _also_ part of the /// return value from a function then it is [invariant][PhantomInvariant]. See [the /// reference][1] for more information. /// /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance /// /// ## Layout /// /// For all `T`, the following are guaranteed: /// * `size_of::>() == 0` /// * `align_of::>() == 1` pub struct PhantomContravariant(PhantomData); /// Zero-sized type used to mark a type parameter as invariant. /// /// Types that are both passed as an argument _and_ used as part of the return value from a /// function are invariant. See [the reference][1] for more information. /// /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance /// /// ## Layout /// /// For all `T`, the following are guaranteed: /// * `size_of::>() == 0` /// * `align_of::>() == 1` pub struct PhantomInvariant(PhantomData T>); } mod sealed { pub trait Sealed { const VALUE: Self; } } /// A marker trait for phantom variance types. pub trait Variance: sealed::Sealed + Default {} /// Construct a variance marker; equivalent to [`Default::default`]. /// /// This type can be any of the following. You generally should not need to explicitly name the /// type, however. /// /// - [`PhantomCovariant`] /// - [`PhantomContravariant`] /// - [`PhantomInvariant`] /// - [`PhantomCovariantLifetime`] /// - [`PhantomContravariantLifetime`] /// - [`PhantomInvariantLifetime`] /// /// # Example /// /// ```rust /// #![feature(phantom_variance_markers)] /// /// use core::marker::{PhantomCovariant, variance}; /// /// struct BoundFn /// where /// F: Fn(P) -> R, /// { /// function: F, /// parameter: P, /// return_value: PhantomCovariant, /// } /// /// let bound_fn = BoundFn { /// function: core::convert::identity, /// parameter: 5u8, /// return_value: variance(), /// }; /// ``` pub const fn variance() -> T where T: Variance, { T::VALUE }