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,
{
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);