id_sys 0.1.0

Provides data structures which can be marked such that they only work with similarly marked integer data types.
Documentation
use crate::{internal::fmt_marker_name, I32Id, U32Id, UsizeId};
use std::{
    cmp::Ordering,
    fmt::{
        self, Binary, Debug, Display, Formatter, LowerExp, LowerHex, Octal, UpperExp, UpperHex,
        Write,
    },
    hash::{Hash, Hasher},
    marker::PhantomData,
    mem::transmute,
    str::FromStr,
};

pub struct IsizeId<TMarker: ?Sized> {
    phantom: PhantomData<TMarker>,
    repr: isize,
}

impl<TMarker: ?Sized> IsizeId<TMarker> {
    fn fmt_helper(
        self,
        fmt_repr: impl FnOnce(&isize, &mut Formatter) -> fmt::Result,
        f: &mut Formatter,
    ) -> fmt::Result {
        fmt_marker_name::<TMarker>(f)?;
        f.write_char('(')?;
        fmt_repr(&self.to_isize(), f)?;
        f.write_char(')')
    }

    pub const fn from_isize(isize: isize) -> IsizeId<TMarker> {
        Self {
            phantom: PhantomData,
            repr: isize,
        }
    }

    pub const fn offset(self, value: isize) -> IsizeId<TMarker> {
        IsizeId::from_isize(self.to_isize() + value)
    }

    pub const fn to_i32_id(self) -> I32Id<TMarker> {
        I32Id::from_i32(self.to_isize() as i32)
    }

    pub const fn to_isize(self) -> isize {
        self.repr
    }

    pub const fn to_u32_id(self) -> U32Id<TMarker> {
        U32Id::from_u32(self.to_isize() as u32)
    }

    pub const fn to_usize_id(self) -> UsizeId<TMarker> {
        UsizeId::from_usize(self.to_isize() as usize)
    }
}

impl<TMarker: ?Sized> Binary for IsizeId<TMarker> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.fmt_helper(Binary::fmt, f)
    }
}

impl<TMarker: ?Sized> Clone for IsizeId<TMarker> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<TMarker: ?Sized> Copy for IsizeId<TMarker> {}

impl<TMarker: ?Sized> Debug for IsizeId<TMarker> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.fmt_helper(Debug::fmt, f)
    }
}

impl<TMarker: ?Sized> Display for IsizeId<TMarker> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.fmt_helper(Display::fmt, f)
    }
}

impl<TMarker: ?Sized> Eq for IsizeId<TMarker> {}

impl<TMarker: ?Sized> From<isize> for IsizeId<TMarker> {
    fn from(val: isize) -> Self {
        Self::from_isize(val)
    }
}

impl<TMarker: ?Sized> FromStr for IsizeId<TMarker> {
    type Err = <isize as FromStr>::Err;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(IsizeId::from_isize(isize::from_str(s)?))
    }
}

impl<TMarker: ?Sized> Hash for IsizeId<TMarker> {
    fn hash<H>(&self, state: &mut H)
    where
        H: Hasher,
    {
        self.to_isize().hash(state)
    }

    fn hash_slice<H>(data: &[Self], state: &mut H)
    where
        H: Hasher,
    {
        let data = unsafe { transmute(data) };
        isize::hash_slice(data, state)
    }
}

impl<TMarker: ?Sized> LowerExp for IsizeId<TMarker> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.fmt_helper(LowerExp::fmt, f)
    }
}

impl<TMarker: ?Sized> LowerHex for IsizeId<TMarker> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.fmt_helper(LowerHex::fmt, f)
    }
}

impl<TMarker: ?Sized> Octal for IsizeId<TMarker> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.fmt_helper(Octal::fmt, f)
    }
}

impl<TMarker: ?Sized> Ord for IsizeId<TMarker> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.to_isize().cmp(&other.to_isize())
    }

    fn max(self, other: Self) -> Self
    where
        Self: Sized,
    {
        Self::from_isize(self.to_isize().max(other.to_isize()))
    }

    fn min(self, other: Self) -> Self
    where
        Self: Sized,
    {
        Self::from_isize(self.to_isize().min(other.to_isize()))
    }

    fn clamp(self, min: Self, max: Self) -> Self
    where
        Self: Sized,
        Self: PartialOrd,
    {
        Self::from_isize(self.to_isize().clamp(min.to_isize(), max.to_isize()))
    }
}

impl<TMarker: ?Sized> PartialEq for IsizeId<TMarker> {
    fn eq(&self, other: &Self) -> bool {
        self.to_isize().eq(&other.to_isize())
    }

    #[allow(clippy::partialeq_ne_impl)]
    fn ne(&self, other: &Self) -> bool {
        self.to_isize().ne(&other.to_isize())
    }
}

#[allow(clippy::non_canonical_partial_ord_impl)]
impl<TMarker: ?Sized> PartialOrd for IsizeId<TMarker> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.to_isize().partial_cmp(&other.to_isize())
    }

    fn lt(&self, other: &Self) -> bool {
        self.to_isize().lt(&other.to_isize())
    }

    fn le(&self, other: &Self) -> bool {
        self.to_isize().le(&other.to_isize())
    }

    fn gt(&self, other: &Self) -> bool {
        self.to_isize().gt(&other.to_isize())
    }

    fn ge(&self, other: &Self) -> bool {
        self.to_isize().ge(&other.to_isize())
    }
}

impl<TMarker: ?Sized> UpperExp for IsizeId<TMarker> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.fmt_helper(UpperExp::fmt, f)
    }
}

impl<TMarker: ?Sized> UpperHex for IsizeId<TMarker> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.fmt_helper(UpperHex::fmt, f)
    }
}