as-is 0.0.4-alpha

An abstraction over ownership
Documentation
use crate::{AsIs, AsIsMut, Is, IsCow, IsMut, Owned, ToOwned};
use core::borrow::{Borrow, BorrowMut};
use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::ops::{
    Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Deref,
    DerefMut, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr,
    ShrAssign, Sub, SubAssign,
};

impl<T: ?Sized> AsIs for IsMut<'_, T>
where
    T: ToOwned,
    T::Owned: Clone + AsIs<Is = T::Owned>,
{
    type Is = T;

    fn as_is<'a>(self) -> Is<'a, T>
    where
        Self: 'a,
    {
        match self {
            Self::Owned(x) => Is::Owned(x),
            Self::MutBorrowed(x) => Is::MutBorrowed(x),
        }
    }

    fn borrow_or_clone<B: ?Sized>(&self) -> IsCow<'_, B>
    where
        T: Borrow<B>,
        T::Owned: Borrow<B>,
        B: ToOwned<Owned = T::Owned>,
    {
        match self {
            Self::Owned(x) => x.borrow_or_clone(),
            Self::MutBorrowed(x) => x.borrow_or_clone(),
        }
    }
}

impl<T: ?Sized> AsIsMut for IsMut<'_, T>
where
    T: ToOwned,
    T::Owned: Clone + AsIs<Is = T::Owned> + BorrowMut<T>,
{
}

impl<T: ?Sized> Deref for IsMut<'_, T>
where
    T: ToOwned,
{
    type Target = T;

    fn deref(&self) -> &Self::Target {
        match self {
            Self::Owned(x) => x.borrow(),
            Self::MutBorrowed(x) => x,
        }
    }
}

impl<T: ?Sized> DerefMut for IsMut<'_, T>
where
    T: ToOwned,
    T::Owned: BorrowMut<T>,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        match self {
            Self::Owned(x) => x.borrow_mut(),
            Self::MutBorrowed(x) => x,
        }
    }
}

impl<T: ?Sized> Borrow<T> for IsMut<'_, T>
where
    T: ToOwned,
{
    fn borrow(&self) -> &T {
        self
    }
}

impl<T: ?Sized> BorrowMut<T> for IsMut<'_, T>
where
    T: ToOwned,
    T::Owned: BorrowMut<T>,
{
    fn borrow_mut(&mut self) -> &mut T {
        self
    }
}

impl<T: ?Sized, U: ?Sized> PartialEq<U> for IsMut<'_, T>
where
    for<'a> T: ToOwned + PartialEq<<&'a U as AsIs>::Is>,
    for<'a> &'a U: AsIs,
{
    fn eq(&self, other: &U) -> bool {
        **self == *other.as_is()
    }
}

impl<T: ?Sized> Eq for IsMut<'_, T>
where
    Self: PartialEq,
    T: ToOwned + Eq,
{
}

impl<T: ?Sized, U: ?Sized> PartialOrd<U> for IsMut<'_, T>
where
    for<'a> T: ToOwned + PartialOrd<<&'a U as AsIs>::Is>,
    for<'a> &'a U: AsIs,
{
    fn partial_cmp(&self, other: &U) -> Option<Ordering> {
        (**self).partial_cmp(&*other.as_is())
    }
}

impl<T: ?Sized> Ord for IsMut<'_, T>
where
    Self: PartialOrd,
    T: ToOwned + Ord,
{
    fn cmp(&self, other: &Self) -> Ordering {
        (**self).cmp(&**other)
    }
}

impl<T: ?Sized> Hash for IsMut<'_, T>
where
    T: ToOwned + Hash,
{
    fn hash<H: Hasher>(&self, state: &mut H) {
        (**self).hash(state);
    }
}

impl<T: ?Sized> Default for IsMut<'_, T>
where
    T: ToOwned,
    T::Owned: Default,
{
    /// Creates an owned `IsMut<'a, T>` with the default value for `T::Owned`.
    fn default() -> Self {
        Self::Owned(T::Owned::default())
    }
}

impl<T: ?Sized, U: ?Sized> AsRef<U> for IsMut<'_, T>
where
    T: ToOwned + AsRef<U>,
{
    fn as_ref(&self) -> &U {
        (**self).as_ref()
    }
}

impl<T: ?Sized, U: ?Sized> AsMut<U> for IsMut<'_, T>
where
    T: ToOwned + AsMut<U>,
    T::Owned: BorrowMut<T>,
{
    fn as_mut(&mut self) -> &mut U {
        (**self).as_mut()
    }
}

macro_rules! impl_fmt {
    ($($Trait:ident),*$(,)?) => {
        $(
        impl<T: ?Sized> fmt::$Trait for IsMut<'_, T>
        where
            T: ToOwned + fmt::$Trait,
        {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                (**self).fmt(f)
            }
        }
        )*
    };
}

impl_fmt!(Binary, Display, LowerExp, LowerHex, Octal, UpperExp, UpperHex);

macro_rules! impl_unop {
    ($Op:ident, $op:ident) => {
        impl<T: ?Sized, O> $Op for IsMut<'_, T>
        where
            T: ToOwned,
            T::Owned: $Op<Output = O>,
            for<'a> &'a T: $Op<Output = O>,
        {
            type Output = O;

            fn $op(self) -> Self::Output {
                match self {
                    Self::Owned(x) => x.$op(),
                    Self::MutBorrowed(x) => x.$op(),
                }
            }
        }
    };
}

impl_unop!(Neg, neg);
impl_unop!(Not, not);

macro_rules! impl_binop {
    ($Op:ident, $op:ident, $OpAssign:ident, $op_assign:ident) => {
        impl<T: ?Sized, U, O> $Op<U> for IsMut<'_, T>
        where
            T: ToOwned,
            U: AsIs,
            for<'a> T::Owned: $Op<Owned<U>, Output = O> + $Op<&'a U::Is, Output = O>,
            for<'a, 'b> &'a T: $Op<Owned<U>, Output = O> + $Op<&'b U::Is, Output = O>,
        {
            type Output = O;

            fn $op(self, rhs: U) -> Self::Output {
                match self {
                    Self::Owned(x) => match rhs.as_is() {
                        Is::Owned(y) => x.$op(y),
                        Is::Borrowed(y) => x.$op(y),
                        Is::MutBorrowed(y) => x.$op(&*y),
                    },
                    Self::MutBorrowed(x) => match rhs.as_is() {
                        Is::Owned(y) => x.$op(y),
                        Is::Borrowed(y) => x.$op(y),
                        Is::MutBorrowed(y) => x.$op(&*y),
                    },
                }
            }
        }

        impl<T: ?Sized, U> $OpAssign<U> for IsMut<'_, T>
        where
            T: ToOwned,
            U: AsIs,
            for<'a> T: $OpAssign<Owned<U>> + $OpAssign<&'a U::Is>,
            for<'a> T::Owned: $OpAssign<Owned<U>> + $OpAssign<&'a U::Is>,
        {
            fn $op_assign(&mut self, rhs: U) {
                match self {
                    Self::Owned(x) => match rhs.as_is() {
                        Is::Owned(y) => x.$op_assign(y),
                        Is::Borrowed(y) => x.$op_assign(y),
                        Is::MutBorrowed(y) => x.$op_assign(&*y),
                    },
                    Self::MutBorrowed(x) => match rhs.as_is() {
                        Is::Owned(y) => x.$op_assign(y),
                        Is::Borrowed(y) => x.$op_assign(y),
                        Is::MutBorrowed(y) => x.$op_assign(&*y),
                    },
                }
            }
        }
    };
}

impl_binop!(Add, add, AddAssign, add_assign);
impl_binop!(Sub, sub, SubAssign, sub_assign);
impl_binop!(Mul, mul, MulAssign, mul_assign);
impl_binop!(Div, div, DivAssign, div_assign);
impl_binop!(Rem, rem, RemAssign, rem_assign);
impl_binop!(Shl, shl, ShlAssign, shl_assign);
impl_binop!(Shr, shr, ShrAssign, shr_assign);
impl_binop!(BitAnd, bitand, BitAndAssign, bitand_assign);
impl_binop!(BitOr, bitor, BitOrAssign, bitor_assign);
impl_binop!(BitXor, bitxor, BitXorAssign, bitxor_assign);