use crate::{AsIs, Is, IsCow, Owned, ToOwned};
use core::borrow::Borrow;
use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::ops::{Add, BitAnd, BitOr, BitXor, Deref, Div, Mul, Neg, Not, Rem, Shl, Shr, Sub};
impl<T: ?Sized> AsIs for IsCow<'_, 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::Borrowed(x) => Is::Borrowed(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::Borrowed(x) => x.borrow_or_clone(),
}
}
}
impl<T: ?Sized> Deref for IsCow<'_, T>
where
T: ToOwned,
{
type Target = T;
fn deref(&self) -> &Self::Target {
match self {
Self::Owned(x) => x.borrow(),
Self::Borrowed(x) => x,
}
}
}
impl<T: ?Sized> Borrow<T> for IsCow<'_, T>
where
T: ToOwned,
{
fn borrow(&self) -> &T {
self
}
}
impl<T: ?Sized, U: ?Sized> PartialEq<U> for IsCow<'_, 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 IsCow<'_, T>
where
Self: PartialEq,
T: ToOwned + Eq,
{
}
impl<T: ?Sized, U: ?Sized> PartialOrd<U> for IsCow<'_, 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 IsCow<'_, T>
where
Self: PartialOrd,
T: ToOwned + Ord,
{
fn cmp(&self, other: &Self) -> Ordering {
(**self).cmp(&**other)
}
}
impl<T: ?Sized> Hash for IsCow<'_, T>
where
T: ToOwned + Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
impl<T: ?Sized> Default for IsCow<'_, T>
where
T: ToOwned,
T::Owned: Default,
{
fn default() -> Self {
Self::Owned(T::Owned::default())
}
}
impl<T: ?Sized, U: ?Sized> AsRef<U> for IsCow<'_, T>
where
T: ToOwned + AsRef<U>,
{
fn as_ref(&self) -> &U {
(**self).as_ref()
}
}
macro_rules! impl_fmt {
($($Trait:ident),*$(,)?) => {
$(
impl<T: ?Sized> fmt::$Trait for IsCow<'_, 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 IsCow<'_, 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::Borrowed(x) => x.$op(),
}
}
}
};
}
impl_unop!(Neg, neg);
impl_unop!(Not, not);
macro_rules! impl_binop {
($Op:ident, $op:ident) => {
impl<T: ?Sized, U, O> $Op<U> for IsCow<'_, 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::Borrowed(x) => match rhs.as_is() {
Is::Owned(y) => x.$op(y),
Is::Borrowed(y) => x.$op(y),
Is::MutBorrowed(y) => x.$op(&*y),
},
}
}
}
};
}
impl_binop!(Add, add);
impl_binop!(Sub, sub);
impl_binop!(Mul, mul);
impl_binop!(Div, div);
impl_binop!(Rem, rem);
impl_binop!(Shl, shl);
impl_binop!(Shr, shr);
impl_binop!(BitAnd, bitand);
impl_binop!(BitOr, bitor);
impl_binop!(BitXor, bitxor);