use super::{Gyu, IntoOwned, Is, Owned};
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,
};
#[derive(Debug)]
pub enum GyuMut<'a, T>
where
T: Owned,
{
Owned(T),
MutBorrowed(&'a mut T),
}
impl<T> Deref for GyuMut<'_, T>
where
T: Owned,
{
type Target = T;
fn deref(&self) -> &Self::Target {
match self {
Self::Owned(t) => t,
Self::MutBorrowed(t) => &**t,
}
}
}
impl<T> DerefMut for GyuMut<'_, T>
where
T: Owned,
{
fn deref_mut(&mut self) -> &mut Self::Target {
match self {
Self::Owned(t) => t,
Self::MutBorrowed(t) => *t,
}
}
}
impl<T, U> PartialEq<GyuMut<'_, U>> for GyuMut<'_, T>
where
T: Owned + PartialEq<U>,
U: Owned,
{
fn eq(&self, other: &GyuMut<'_, U>) -> bool {
**self == **other
}
}
impl<T> Eq for GyuMut<'_, T> where T: Owned + Eq {}
impl<T, U> PartialOrd<GyuMut<'_, U>> for GyuMut<'_, T>
where
T: Owned + PartialOrd<U>,
U: Owned,
{
fn partial_cmp(&self, other: &GyuMut<'_, U>) -> Option<Ordering> {
(**self).partial_cmp(other)
}
}
impl<T> Ord for GyuMut<'_, T>
where
T: Owned + Ord,
{
fn cmp(&self, other: &Self) -> Ordering {
(**self).cmp(other)
}
}
impl<T> Hash for GyuMut<'_, T>
where
T: Owned + Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state)
}
}
impl<T> Borrow<T> for GyuMut<'_, T>
where
T: Owned,
{
fn borrow(&self) -> &T {
self
}
}
impl<T> BorrowMut<T> for GyuMut<'_, T>
where
T: Owned,
{
fn borrow_mut(&mut self) -> &mut T {
self
}
}
impl<T> IntoOwned for GyuMut<'_, T>
where
T: Owned,
{
type Owned = T;
fn as_is<'a>(self) -> Is<'a, <Self as IntoOwned>::Owned>
where
Self: 'a,
{
match self {
Self::Owned(t) => Is::Owned(t),
Self::MutBorrowed(t) => Is::MutBorrowed(t),
}
}
}
impl<T> Clone for GyuMut<'_, T>
where
T: Owned + Clone,
{
fn clone(&self) -> Self {
match self {
Self::Owned(t) => Self::Owned(t.clone()),
Self::MutBorrowed(t) => Self::Owned((*t).clone()),
}
}
fn clone_from(&mut self, source: &Self) {
match self {
Self::Owned(t) => {
t.clone_from(&*source);
}
Self::MutBorrowed(t) => {
t.clone_from(&*source);
}
}
}
}
impl<T> Default for GyuMut<'_, T>
where
T: Owned + Default,
{
fn default() -> Self {
Self::Owned(T::default())
}
}
impl<T, U> AsRef<U> for GyuMut<'_, T>
where
T: Owned + AsRef<U>,
U: ?Sized,
{
fn as_ref(&self) -> &U {
(**self).as_ref()
}
}
impl<T, U> AsMut<U> for GyuMut<'_, T>
where
T: Owned + AsMut<U>,
U: ?Sized,
{
fn as_mut(&mut self) -> &mut U {
(**self).as_mut()
}
}
macro_rules! impl_fmt {
($Trait:ident) => {
impl<T> fmt::$Trait for GyuMut<'_, T>
where
T: Owned + fmt::$Trait,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(**self).fmt(f)
}
}
};
}
impl_fmt!(Binary);
impl_fmt!(Display);
impl_fmt!(LowerExp);
impl_fmt!(LowerHex);
impl_fmt!(Octal);
impl_fmt!(UpperExp);
impl_fmt!(UpperHex);
macro_rules! impl_unop {
($Op:ident, $op:ident) => {
impl<T, Out> $Op for GyuMut<'_, T>
where
T: Owned + $Op<Output = Out>,
for<'a> &'a T: $Op<Output = Out>,
{
type Output = Out;
fn $op(self) -> Self::Output {
use Gyu::*;
match self.into_gyu() {
Owned(t) => t.$op(),
Borrowed(t) => t.$op(),
}
}
}
};
}
impl_unop!(Neg, neg);
impl_unop!(Not, not);
macro_rules! impl_binop {
($Op:ident, $op:ident, $OpAssign:ident, $op_assign:ident) => {
impl<T, U, Out> $Op<U> for GyuMut<'_, T>
where
for<'a> T: Owned + $Op<U::Owned, Output = Out> + $Op<&'a U::Owned, Output = Out>,
for<'a, 'b> &'a T: $Op<U::Owned, Output = Out> + $Op<&'b U::Owned, Output = Out>,
U: IntoOwned,
{
type Output = Out;
fn $op(self, rhs: U) -> Self::Output {
use Gyu::*;
match (self.into_gyu(), rhs.into_gyu()) {
(Owned(t), Owned(u)) => t.$op(u),
(Owned(t), Borrowed(u)) => t.$op(u),
(Borrowed(t), Owned(u)) => t.$op(u),
(Borrowed(t), Borrowed(u)) => t.$op(u),
}
}
}
impl<T, U> $OpAssign<U> for GyuMut<'_, T>
where
for<'a> T: Owned + $OpAssign<U::Owned> + $OpAssign<&'a U::Owned>,
U: IntoOwned,
{
fn $op_assign(&mut self, rhs: U) {
use Gyu::*;
match rhs.into_gyu() {
Owned(u) => (**self).$op_assign(u),
Borrowed(u) => (**self).$op_assign(u),
}
}
}
};
}
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);