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::{IntoOwned, Is, Owned};
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};

/// Represents an owned value or an immutably borrowed reference.
///
/// `Gyu<'a, T>` ([牛]: cow) is similar to [`Cow<'a, B>`].
/// It holds an owned value or an immutably borrowed reference.
/// It can be created by the [`into_gyu`] 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`]: trait.IntoOwned.html#method.into_gyu
/// [`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 Gyu<'a, T>
where
    T: Owned,
{
    Owned(T),
    Borrowed(&'a T),
}

impl<T> Gyu<'_, T>
where
    T: Owned,
{
    pub fn to_mut(&mut self) -> &mut T
    where
        T: Clone,
    {
        match self {
            Gyu::Owned(t) => t,
            Gyu::Borrowed(t) => {
                *self = Gyu::Owned(t.clone());
                self.to_mut()
            }
        }
    }
}

impl<T> Deref for Gyu<'_, T>
where
    T: Owned,
{
    type Target = T;

    fn deref(&self) -> &Self::Target {
        match self {
            Self::Owned(t) => t,
            Self::Borrowed(t) => *t,
        }
    }
}

impl<T, U> PartialEq<Gyu<'_, U>> for Gyu<'_, T>
where
    T: Owned + PartialEq<U>,
    U: Owned,
{
    fn eq(&self, other: &Gyu<'_, U>) -> bool {
        **self == **other
    }
}

impl<T> Eq for Gyu<'_, T> where T: Owned + Eq {}

impl<T, U> PartialOrd<Gyu<'_, U>> for Gyu<'_, T>
where
    T: Owned + PartialOrd<U>,
    U: Owned,
{
    fn partial_cmp(&self, other: &Gyu<'_, U>) -> Option<Ordering> {
        (**self).partial_cmp(other)
    }
}

impl<T> Ord for Gyu<'_, T>
where
    T: Owned + Ord,
{
    fn cmp(&self, other: &Self) -> Ordering {
        (**self).cmp(other)
    }
}

impl<T> Hash for Gyu<'_, T>
where
    T: Owned + Hash,
{
    fn hash<H: Hasher>(&self, state: &mut H) {
        (**self).hash(state)
    }
}

impl<T> Borrow<T> for Gyu<'_, T>
where
    T: Owned,
{
    fn borrow(&self) -> &T {
        self
    }
}

impl<T> IntoOwned for Gyu<'_, 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::Borrowed(t) => Is::Borrowed(t),
        }
    }
}

impl<T> Clone for Gyu<'_, T>
where
    T: Owned + Clone,
{
    fn clone(&self) -> Self {
        match self {
            Self::Owned(t) => Self::Owned(t.clone()),
            Self::Borrowed(t) => Self::Borrowed(t),
        }
    }

    fn clone_from(&mut self, source: &Self) {
        match self {
            Self::Owned(t) => {
                t.clone_from(&*source);
            }
            Self::Borrowed(_) => {
                *self = source.clone();
            }
        }
    }
}

impl<T> Default for Gyu<'_, T>
where
    T: Owned + Default,
{
    /// Creates an owned `Gyu<'a, T>` with the default value of `T`.
    fn default() -> Self {
        Self::Owned(T::default())
    }
}

impl<T, U> AsRef<U> for Gyu<'_, T>
where
    T: Owned + AsRef<U>,
    U: ?Sized,
{
    fn as_ref(&self) -> &U {
        (**self).as_ref()
    }
}

macro_rules! impl_fmt {
    ($Trait:ident) => {
        impl<T> fmt::$Trait for Gyu<'_, 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 Gyu<'_, 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 {
                    Owned(t) => t.$op(),
                    Borrowed(t) => t.$op(),
                }
            }
        }
    };
}

impl_unop!(Neg, neg);
impl_unop!(Not, not);

macro_rules! impl_binop {
    ($Op:ident, $op:ident) => {
        impl<T, U, Out> $Op<U> for Gyu<'_, 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, 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_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);