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};
#[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,
{
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);