into-owned 0.3.0-alpha.3

This crate has been merged into as-is crate and is no longer developed by the current author.
Documentation
// Copyright 2020 Koichi Kitahara
//
// Licensed under either of Apache License, Version 2.0:
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//
// or MIT license:
//
//   Permission is hereby granted, free of charge, to any person obtaining a
//   copy of this software and associated documentation files (the "Software"),
//   to deal in the Software without restriction, including without limitation
//   the rights to use, copy, modify, merge, publish, distribute, sublicense,
//   and/or sell copies of the Software, and to permit persons to whom the
//   Software is furnished to do so, subject to the following conditions:
//
//   The above copyright notice and this permission notice shall be included in
//   all copies or substantial portions of the Software.
//
//   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
//   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//   DEALINGS IN THE SOFTWARE.
//
// at your option.

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,
};

/// Represents an owned value or a mutably borrowed reference.
///
/// `GyuMut` (not `GyuNyu` [牛乳]: cow's milk) is similar to [`Cow<'a, B>`].
/// Unlike [`Cow<'a, B>`], it cannot hold an immutably borrowed reference but a *mutably* borrowed reference.
/// It can be created by the [`into_gyu_mut`] method on [`IntoOwned`].
///
/// This enum, as a clone-on-write smart pointer, is highly experimental.
/// Most parts are subject to change.
/// Especially, more traits may be implemented.
///
/// [`into_gyu_mut`]: trait.IntoOwned.html#method.into_gyu_mut
/// [`IntoOwned`]: trait.IntoOwned.html
/// [牛乳]: https://en.wiktionary.org/wiki/牛乳
/// [`Cow<'a, B>`]: https://doc.rust-lang.org/std/convert/trait.Cow.html
#[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,
{
    /// Creates an owned `GyuMut<'a, T>` with the default value of `T`.
    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);