use crate::{AsIs, BorrowAsIs, Is, IsCow, Owned, ToOwned, ToOwnedMut};
use core::borrow::{Borrow, BorrowMut};
use core::cmp::Ordering;
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,
};
use ref_ops::{
RefAdd, RefBitAnd, RefBitOr, RefBitXor, RefDiv, RefMul, RefMutAdd, RefMutBitAnd, RefMutBitOr,
RefMutBitXor, RefMutDiv, RefMutMul, RefMutNeg, RefMutNot, RefMutRem, RefMutShl, RefMutShr,
RefMutSub, RefNeg, RefNot, RefRem, RefShl, RefShr, RefSub,
};
#[derive(Debug)]
pub enum IsMut<'a, T>
where
T: ?Sized + ToOwned,
{
Owned(T::Owned),
MutBorrowed(&'a mut T),
}
impl<T> Default for IsMut<'_, T>
where
T: ?Sized + ToOwned,
T::Owned: Default,
{
fn default() -> Self {
IsMut::Owned(T::Owned::default())
}
}
impl<T> Deref for IsMut<'_, T>
where
T: ?Sized + ToOwned,
{
type Target = T;
fn deref(&self) -> &T {
match self {
IsMut::Owned(x) => x.borrow(),
IsMut::MutBorrowed(x) => x,
}
}
}
impl<T> DerefMut for IsMut<'_, T>
where
T: ?Sized + ToOwnedMut,
{
fn deref_mut(&mut self) -> &mut T {
match self {
IsMut::Owned(x) => x.borrow_mut(),
IsMut::MutBorrowed(x) => x,
}
}
}
impl<T> Borrow<T> for IsMut<'_, T>
where
T: ?Sized + ToOwned,
{
fn borrow(&self) -> &T {
self
}
}
impl<T> Borrow<T> for &IsMut<'_, T>
where
T: ?Sized + ToOwned,
{
fn borrow(&self) -> &T {
self
}
}
impl<T> Borrow<T> for &mut IsMut<'_, T>
where
T: ?Sized + ToOwned,
{
fn borrow(&self) -> &T {
self
}
}
impl<T> BorrowMut<T> for IsMut<'_, T>
where
T: ?Sized + ToOwnedMut,
{
fn borrow_mut(&mut self) -> &mut T {
self
}
}
impl<T> BorrowMut<T> for &mut IsMut<'_, T>
where
T: ?Sized + ToOwnedMut,
{
fn borrow_mut(&mut self) -> &mut T {
self
}
}
impl<T, U> PartialEq<Is<'_, U>> for IsMut<'_, T>
where
T: ?Sized + ToOwned + PartialEq<U>,
U: ?Sized + ToOwned,
{
fn eq(&self, other: &Is<'_, U>) -> bool {
**self == **other
}
}
impl<T, U> PartialEq<IsCow<'_, U>> for IsMut<'_, T>
where
T: ?Sized + ToOwned + PartialEq<U>,
U: ?Sized + ToOwned,
{
fn eq(&self, other: &IsCow<'_, U>) -> bool {
**self == **other
}
}
impl<T, U> PartialEq<IsMut<'_, U>> for IsMut<'_, T>
where
T: ?Sized + ToOwned + PartialEq<U>,
U: ?Sized + ToOwned,
{
fn eq(&self, other: &IsMut<'_, U>) -> bool {
**self == **other
}
}
impl<T> Eq for IsMut<'_, T> where T: ?Sized + ToOwned + Eq {}
impl<T, U> PartialOrd<Is<'_, U>> for IsMut<'_, T>
where
T: ?Sized + ToOwned + PartialOrd<U>,
U: ?Sized + ToOwned,
{
fn partial_cmp(&self, other: &Is<'_, U>) -> Option<Ordering> {
(**self).partial_cmp(&**other)
}
}
impl<T, U> PartialOrd<IsCow<'_, U>> for IsMut<'_, T>
where
T: ?Sized + ToOwned + PartialOrd<U>,
U: ?Sized + ToOwned,
{
fn partial_cmp(&self, other: &IsCow<'_, U>) -> Option<Ordering> {
(**self).partial_cmp(&**other)
}
}
impl<T, U> PartialOrd<IsMut<'_, U>> for IsMut<'_, T>
where
T: ?Sized + ToOwned + PartialOrd<U>,
U: ?Sized + ToOwned,
{
fn partial_cmp(&self, other: &IsMut<'_, U>) -> Option<Ordering> {
(**self).partial_cmp(&**other)
}
}
impl<T> Ord for IsMut<'_, T>
where
T: ?Sized + ToOwned + Ord,
{
fn cmp(&self, other: &Self) -> Ordering {
(**self).cmp(&**other)
}
}
impl<T> Hash for IsMut<'_, T>
where
T: ?Sized + ToOwned + Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
impl<T> BorrowAsIs for IsMut<'_, T>
where
T: ?Sized + BorrowAsIs<Is = T> + ToOwned,
{
type Is = T;
fn borrow_or_clone<B: ?Sized>(&self) -> IsCow<'_, B>
where
T: Borrow<B>,
B: ToOwned<Owned = T::Owned>,
{
(**self).borrow_or_clone()
}
}
impl<T> AsIs for IsMut<'_, T>
where
T: ?Sized + BorrowAsIs<Is = T> + ToOwned,
{
fn as_is<'a>(self) -> Is<'a, T>
where
Self: 'a,
{
match self {
IsMut::Owned(x) => Is::Owned(x),
IsMut::MutBorrowed(x) => match x.borrow_or_clone() {
IsCow::Owned(x) => Is::Owned(x),
IsCow::Borrowed(_) => Is::MutBorrowed(x),
},
}
}
}
macro_rules! impl_unop {
($Op:ident, $op:ident, $RefOp:ident, $ref_op:ident, $RefMutOp:ident, $ref_mut_op:ident) => {
impl<T> $Op for IsMut<'_, T>
where
T: ?Sized + ToOwned + $RefMutOp,
T::Owned: $Op<Output = T::Output>,
{
type Output = T::Output;
fn $op(self) -> Self::Output {
match self {
IsMut::Owned(x) => x.$op(),
IsMut::MutBorrowed(x) => x.$ref_mut_op(),
}
}
}
impl<T> $Op for &IsMut<'_, T>
where
T: ?Sized + ToOwned + $RefOp,
{
type Output = T::Output;
fn $op(self) -> Self::Output {
(**self).$ref_op()
}
}
impl<T> $Op for &mut IsMut<'_, T>
where
T: ?Sized + ToOwnedMut + $RefMutOp,
{
type Output = T::Output;
fn $op(self) -> Self::Output {
match self {
IsMut::Owned(x) => x.borrow_mut().$ref_mut_op(),
IsMut::MutBorrowed(x) => x.$ref_mut_op(),
}
}
}
};
}
impl_unop!(Neg, neg, RefNeg, ref_neg, RefMutNeg, ref_mut_neg);
impl_unop!(Not, not, RefNot, ref_not, RefMutNot, ref_mut_not);
macro_rules! impl_binop {
($Op:ident, $op:ident, $RefOp:ident, $ref_op:ident, $RefMutOp:ident, $ref_mut_op:ident) => {
impl<T, U, O> $Op<U> for IsMut<'_, T>
where
T: ?Sized
+ ToOwned
+ $RefMutOp<Owned<U>, Output = O>
+ for<'a> $RefMutOp<&'a U::Is, Output = O>
+ for<'a> $RefMutOp<&'a mut U::Is, Output = O>,
U: AsIs,
T::Owned: $Op<Owned<U>, Output = O>
+ for<'a> $Op<&'a U::Is, Output = O>
+ for<'a> $Op<&'a mut U::Is, Output = O>,
{
type Output = O;
fn $op(self, rhs: U) -> Self::Output {
match self {
IsMut::Owned(x) => match rhs.as_is() {
Is::Owned(y) => x.$op(y),
Is::Borrowed(y) => x.$op(y),
Is::MutBorrowed(y) => x.$op(y),
},
IsMut::MutBorrowed(x) => match rhs.as_is() {
Is::Owned(y) => x.$ref_mut_op(y),
Is::Borrowed(y) => x.$ref_mut_op(y),
Is::MutBorrowed(y) => x.$ref_mut_op(y),
},
}
}
}
impl<T, U, O> $Op<U> for &IsMut<'_, T>
where
T: ?Sized
+ ToOwned
+ $RefOp<Owned<U>, Output = O>
+ for<'a> $RefOp<&'a U::Is, Output = O>
+ for<'a> $RefOp<&'a mut U::Is, Output = O>,
U: AsIs,
{
type Output = O;
fn $op(self, rhs: U) -> Self::Output {
match rhs.as_is() {
Is::Owned(y) => (**self).$ref_op(y),
Is::Borrowed(y) => (**self).$ref_op(y),
Is::MutBorrowed(y) => (**self).$ref_op(y),
}
}
}
impl<T, U, O> $Op<U> for &mut IsMut<'_, T>
where
T: ?Sized
+ ToOwnedMut
+ $RefMutOp<Owned<U>, Output = O>
+ for<'a> $RefMutOp<&'a U::Is, Output = O>
+ for<'a> $RefMutOp<&'a mut U::Is, Output = O>,
U: AsIs,
{
type Output = O;
fn $op(self, rhs: U) -> Self::Output {
match self {
IsMut::Owned(x) => match rhs.as_is() {
Is::Owned(y) => x.borrow_mut().$ref_mut_op(y),
Is::Borrowed(y) => x.borrow_mut().$ref_mut_op(y),
Is::MutBorrowed(y) => x.borrow_mut().$ref_mut_op(y),
},
IsMut::MutBorrowed(x) => match rhs.as_is() {
Is::Owned(y) => x.$ref_mut_op(y),
Is::Borrowed(y) => x.$ref_mut_op(y),
Is::MutBorrowed(y) => x.$ref_mut_op(y),
},
}
}
}
};
}
impl_binop!(Add, add, RefAdd, ref_add, RefMutAdd, ref_mut_add);
impl_binop!(Sub, sub, RefSub, ref_sub, RefMutSub, ref_mut_sub);
impl_binop!(Mul, mul, RefMul, ref_mul, RefMutMul, ref_mut_mul);
impl_binop!(Div, div, RefDiv, ref_div, RefMutDiv, ref_mut_div);
impl_binop!(Rem, rem, RefRem, ref_rem, RefMutRem, ref_mut_rem);
impl_binop!(Shl, shl, RefShl, ref_shl, RefMutShl, ref_mut_shl);
impl_binop!(Shr, shr, RefShr, ref_shr, RefMutShr, ref_mut_shr);
impl_binop!(
BitAnd,
bitand,
RefBitAnd,
ref_bitand,
RefMutBitAnd,
ref_mut_bitand
);
impl_binop!(
BitOr,
bitor,
RefBitOr,
ref_bitor,
RefMutBitOr,
ref_mut_bitor
);
impl_binop!(
BitXor,
bitxor,
RefBitXor,
ref_bitxor,
RefMutBitXor,
ref_mut_bitxor
);
macro_rules! impl_binop_assign {
($OpAssign:ident, $op_assign:ident) => {
impl<T, U> $OpAssign<U> for IsMut<'_, T>
where
T: ?Sized
+ ToOwned
+ $OpAssign<Owned<U>>
+ for<'a> $OpAssign<&'a U::Is>
+ for<'a> $OpAssign<&'a mut U::Is>,
U: AsIs,
T::Owned: $OpAssign<Owned<U>>
+ for<'a> $OpAssign<&'a U::Is>
+ for<'a> $OpAssign<&'a mut U::Is>,
{
fn $op_assign(&mut self, rhs: U) {
match self {
IsMut::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),
},
IsMut::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_assign!(AddAssign, add_assign);
impl_binop_assign!(SubAssign, sub_assign);
impl_binop_assign!(MulAssign, mul_assign);
impl_binop_assign!(DivAssign, div_assign);
impl_binop_assign!(RemAssign, rem_assign);
impl_binop_assign!(ShlAssign, shl_assign);
impl_binop_assign!(ShrAssign, shr_assign);
impl_binop_assign!(BitAndAssign, bitand_assign);
impl_binop_assign!(BitOrAssign, bitor_assign);
impl_binop_assign!(BitXorAssign, bitxor_assign);