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
{
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<'_> {
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! {
pub struct PhantomCovariantLifetime<'a>(PhantomCovariant<&'a ()>);
pub struct PhantomContravariantLifetime<'a>(PhantomContravariant<&'a ()>);
pub struct PhantomInvariantLifetime<'a>(PhantomInvariant<&'a ()>);
}
phantom_type! {
pub struct PhantomCovariant<T>(PhantomData<fn() -> T>);
pub struct PhantomContravariant<T>(PhantomData<fn(T)>);
pub struct PhantomInvariant<T>(PhantomData<fn(T) -> T>);
}
mod sealed {
pub trait Sealed {
const VALUE: Self;
}
}
pub trait Variance: sealed::Sealed + Default {}
pub const fn variance<T>() -> T
where
T: Variance,
{
T::VALUE
}