Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/stdx/src/variance.rs')
-rw-r--r--crates/stdx/src/variance.rs270
1 files changed, 270 insertions, 0 deletions
diff --git a/crates/stdx/src/variance.rs b/crates/stdx/src/variance.rs
new file mode 100644
index 0000000000..8465d72bf3
--- /dev/null
+++ b/crates/stdx/src/variance.rs
@@ -0,0 +1,270 @@
+//! 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<T> $name<T>
+ where T: ?Sized
+ {
+ /// Constructs a new instance of the variance marker.
+ pub const fn new() -> Self {
+ Self(PhantomData)
+ }
+ }
+
+ impl<T> self::sealed::Sealed for $name<T> where T: ?Sized {
+ const VALUE: Self = Self::new();
+ }
+
+ impl<T> Variance for $name<T> where T: ?Sized {}
+
+ impl<T> Default for $name<T>
+ where T: ?Sized
+ {
+ fn default() -> Self {
+ Self(PhantomData)
+ }
+ }
+
+ impl<T> fmt::Debug for $name<T>
+ where T: ?Sized
+ {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}<{}>", stringify!($name), type_name::<T>())
+ }
+ }
+
+ impl<T> Clone for $name<T>
+ where T: ?Sized
+ {
+ fn clone(&self) -> Self {
+ *self
+ }
+ }
+
+ impl<T> Copy for $name<T> where T: ?Sized {}
+
+ impl<T> PartialEq for $name<T>
+ where T: ?Sized
+ {
+ fn eq(&self, _: &Self) -> bool {
+ true
+ }
+ }
+
+ impl<T> Eq for $name<T> where T: ?Sized {}
+
+ #[allow(clippy::non_canonical_partial_ord_impl)]
+ impl<T> PartialOrd for $name<T>
+ where T: ?Sized
+ {
+ fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
+ Some(Ordering::Equal)
+ }
+ }
+
+ impl<T> Ord for $name<T>
+ where T: ?Sized
+ {
+ fn cmp(&self, _: &Self) -> Ordering {
+ Ordering::Equal
+ }
+ }
+
+ impl<T> Hash for $name<T>
+ where T: ?Sized
+ {
+ fn hash<H: Hasher>(&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::<PhantomCovariantLifetime<'a>>() == 0`
+ /// * `align_of::<PhantomCovariantLifetime<'a>>() == 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::<PhantomContravariantLifetime<'a>>() == 0`
+ /// * `align_of::<PhantomContravariantLifetime<'a>>() == 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::<PhantomInvariantLifetime<'a>>() == 0`
+ /// * `align_of::<PhantomInvariantLifetime<'a>>() == 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::<PhantomCovariant<T>>() == 0`
+ /// * `align_of::<PhantomCovariant<T>>() == 1`
+
+ pub struct PhantomCovariant<T>(PhantomData<fn() -> 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::<PhantomContravariant<T>>() == 0`
+ /// * `align_of::<PhantomContravariant<T>>() == 1`
+
+ pub struct PhantomContravariant<T>(PhantomData<fn(T)>);
+ /// 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::<PhantomInvariant<T>>() == 0`
+ /// * `align_of::<PhantomInvariant<T>>() == 1`
+
+ pub struct PhantomInvariant<T>(PhantomData<fn(T) -> 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<F, P, R>
+/// where
+/// F: Fn(P) -> R,
+/// {
+/// function: F,
+/// parameter: P,
+/// return_value: PhantomCovariant<R>,
+/// }
+///
+/// let bound_fn = BoundFn {
+/// function: core::convert::identity,
+/// parameter: 5u8,
+/// return_value: variance(),
+/// };
+/// ```
+pub const fn variance<T>() -> T
+where
+ T: Variance,
+{
+ T::VALUE
+}