kutil 0.0.6

Kutil utilities collection
Documentation
use super::{
    super::{borrow::*, immutable::*},
    foster::*,
    has_length::*,
};

use std::{cmp::*, fmt, hash::*};

/// [Foster] for [ImmutableString].
///
/// Supports [IntoOwned], [HasLength], [AsRef]\<str\>, [Eq]/[PartialEq], [Ord]/[PartialOrd],
/// [Hash], and [Display](fmt::Display).
///
/// Note that we need to wrap [ImmutableString] in a [Box] because [ImmutableString] has interior
/// mutability and thus cannot be part of a constant value's type.
pub type FosterImmutableString = Foster<Box<ImmutableString>, &'static str>;

impl IntoOwned for FosterImmutableString {
    /// Into owned.
    fn into_owned(self) -> Self {
        match self {
            Self::Owned(_) => self,
            Self::Fostered(string) => Self::Owned(Box::new(string.into())),
        }
    }
}

impl HasLength for FosterImmutableString {
    fn len(&self) -> usize {
        match self {
            Self::Owned(string) => string.len(),
            Self::Fostered(string) => string.len(),
        }
    }
}

impl From<&'static str> for FosterImmutableString {
    fn from(string: &'static str) -> Self {
        Self::Fostered(string)
    }
}

impl From<ImmutableString> for FosterImmutableString {
    fn from(string: ImmutableString) -> Self {
        Self::Owned(string.into())
    }
}

impl From<String> for FosterImmutableString {
    fn from(string: String) -> Self {
        ImmutableString::from(string).into()
    }
}

impl AsRef<str> for FosterImmutableString {
    fn as_ref(&self) -> &str {
        match self {
            Self::Owned(string) => string,
            Self::Fostered(string) => string,
        }
    }
}

impl PartialEq for FosterImmutableString {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (Self::Owned(left), Self::Owned(right)) => left == right,
            (Self::Owned(left), Self::Fostered(right)) => left.as_ref() == *right,
            (Self::Fostered(left), Self::Owned(right)) => {
                let right: &str = &right;
                *left == right
            }
            (Self::Fostered(left), Self::Fostered(right)) => left.eq(right),
        }
    }
}

impl Eq for FosterImmutableString {}

impl PartialOrd for FosterImmutableString {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        match (self, other) {
            (Self::Owned(left), Self::Owned(right)) => left.partial_cmp(right),
            (Self::Owned(left), Self::Fostered(right)) => (***left).partial_cmp(*right),
            (Self::Fostered(left), Self::Owned(right)) => {
                let right: &str = &right;
                (*left).partial_cmp(right)
            }
            (Self::Fostered(left), Self::Fostered(right)) => left.partial_cmp(right),
        }
    }
}

impl Ord for FosterImmutableString {
    fn cmp(&self, other: &Self) -> Ordering {
        match (self, other) {
            (Self::Owned(left), Self::Owned(right)) => left.cmp(right),
            (Self::Owned(left), Self::Fostered(right)) => (***left).cmp(right),
            (Self::Fostered(left), Self::Owned(right)) => (*left).cmp(right),
            (Self::Fostered(left), Self::Fostered(right)) => left.cmp(right),
        }
    }
}

impl Hash for FosterImmutableString {
    fn hash<HasherT>(&self, state: &mut HasherT)
    where
        HasherT: Hasher,
    {
        match self {
            Self::Owned(string) => state.write(string.as_bytes()),
            Self::Fostered(string) => state.write(string.as_bytes()),
        }
    }
}

impl fmt::Display for FosterImmutableString {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Self::Owned(string) => string.fmt(formatter),
            Self::Fostered(string) => string.fmt(formatter),
        }
    }
}

/// Delegates traits to a [FosterImmutableString] newtype.
///
/// Example:
///
/// ```
/// #[derive(Clone, Debug)]
/// pub struct MyType(FosterImmutableString);
///
/// delegate_newtype_of_foster_immutable_string!(MyType);
/// ```
#[macro_export]
macro_rules! delegate_newtype_of_foster_immutable_string {
    ( $type:ty $(,)? ) => {
        impl $type {
            /// Constructor.
            pub const fn new_owned(string: ::std::boxed::Box<$crate::std::immutable::ImmutableString>) -> Self {
                Self($crate::std::foster::Foster::new_owned(string))
            }

            /// Constructor.
            pub const fn new_fostered(string: &'static str) -> Self {
                Self($crate::std::foster::Foster::new_fostered(string))
            }
        }

        impl $crate::std::borrow::IntoOwned for $type {
            fn into_owned(self) -> Self {
                match self.0 {
                    $crate::std::foster::Foster::Owned(_) => self,
                    $crate::std::foster::Foster::Fostered(string) => {
                        Self::new_owned(::std::boxed::Box::new(string.into()))
                    }
                }
            }
        }

        impl $crate::std::foster::HasLength for $type {
            fn len(&self) -> usize {
                self.0.len()
            }
        }

        impl ::std::convert::From<&'static str> for $type {
            fn from(string: &'static str) -> Self {
                Self(string.into())
            }
        }

        impl ::std::convert::From<$crate::std::immutable::ImmutableString> for $type {
            fn from(string: $crate::std::immutable::ImmutableString) -> Self {
                Self(string.into())
            }
        }

        impl ::std::convert::From<String> for $type {
            fn from(string: ::std::string::String) -> Self {
                Self(string.into())
            }
        }

        impl ::std::convert::AsRef<str> for $type {
            fn as_ref(&self) -> &str {
                self.0.as_ref()
            }
        }

        impl ::std::cmp::PartialEq for $type {
            fn eq(&self, other: &Self) -> bool {
                self.0.eq(&other.0)
            }
        }

        impl ::std::cmp::Eq for $type {}

        impl ::std::cmp::PartialOrd for $type {
            fn partial_cmp(&self, other: &Self) -> ::std::option::Option<::std::cmp::Ordering> {
                self.0.partial_cmp(&other.0)
            }
        }

        impl ::std::cmp::Ord for $type {
            fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
                self.0.cmp(&other.0)
            }
        }

        impl ::std::hash::Hash for $type {
            fn hash<HasherT>(&self, state: &mut HasherT)
            where
                HasherT: ::std::hash::Hasher,
            {
                self.0.hash(state)
            }
        }

        impl ::std::fmt::Display for $type {
            fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                ::std::fmt::Display::fmt(&self.0, formatter)
            }
        }
    };
}

#[allow(unused_imports)]
pub use delegate_newtype_of_foster_immutable_string;