blob: 711bbdd42a2208c14f64f64e9eff1d4091d3fb1a [file] [log] [blame] [edit]
use core::{
cmp::Ordering,
fmt::{Display, Formatter},
hash::{Hash, Hasher},
};
/// # Maybe Owned Object
///
/// This is analogous to [`Cow`], but without the additional [`ToOwned`] trait requirement which
/// makes it unsuitable for `no_std` environments.
///
/// ## Name
///
/// The name `Moo` is a play on `Cow`, and is also a reference to the fact that cows moo.
///
/// > I totally didn't come up with the name first and then try to find an abbreviation that fit.
///
/// [`Cow`]: alloc::borrow::Cow
#[derive(Debug, Copy, Clone)]
pub enum Moo<'a, T> {
Borrowed(&'a T),
Owned(T),
}
impl<T> Display for Moo<'_, T>
where
T: Display,
{
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
Display::fmt(self.as_ref(), f)
}
}
impl<'a, T> From<T> for Moo<'a, T> {
fn from(value: T) -> Self {
Self::Owned(value)
}
}
impl<'a, T> From<&'a T> for Moo<'a, T> {
fn from(value: &'a T) -> Self {
Self::Borrowed(value)
}
}
impl<'a, T> Moo<'a, T> {
/// Returns a mutable reference to the owned value, if any.
///
/// # Example
///
/// ```
/// use numi::borrow::Moo;
///
/// let mut value = Moo::Owned(42);
/// assert_eq!(value.as_mut(), Some(&mut 42));
///
/// let mut value = Moo::Borrowed(&42);
/// assert_eq!(value.as_mut(), None);
/// ```
pub fn as_mut(&mut self) -> Option<&mut T> {
match self {
Self::Borrowed(_) => None,
Self::Owned(value) => Some(value),
}
}
/// Converts the `Moo` into an owned value.
///
/// This is a no-op if the value is already owned, and requires cloning if it is borrowed.
///
/// # Example
///
/// ```
/// use numi::borrow::Moo;
///
/// let value = Moo::Owned(42);
/// assert_eq!(value.into_owned(), 42);
///
/// let value = Moo::Borrowed(&42);
/// assert_eq!(value.into_owned(), 42);
/// ```
pub fn into_owned(self) -> T
where
T: Clone,
{
match self {
Self::Borrowed(value) => value.clone(),
Self::Owned(value) => value,
}
}
}
impl<T> AsRef<T> for Moo<'_, T> {
fn as_ref(&self) -> &T {
match self {
Self::Borrowed(value) => value,
Self::Owned(value) => value,
}
}
}
impl<T> PartialEq<T> for Moo<'_, T>
where
T: PartialEq,
{
fn eq(&self, other: &T) -> bool {
self.as_ref().eq(other)
}
}
impl<T> PartialEq for Moo<'_, T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.as_ref().eq(other.as_ref())
}
}
impl<T> Eq for Moo<'_, T> where T: Eq {}
impl<T> PartialOrd<T> for Moo<'_, T>
where
T: PartialOrd,
{
fn partial_cmp(&self, other: &T) -> Option<Ordering> {
self.as_ref().partial_cmp(other)
}
}
impl<T> PartialOrd for Moo<'_, T>
where
T: PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.as_ref().partial_cmp(other.as_ref())
}
}
impl<T> Ord for Moo<'_, T>
where
T: Ord,
{
fn cmp(&self, other: &Self) -> Ordering {
self.as_ref().cmp(other.as_ref())
}
}
impl<T> Hash for Moo<'_, T>
where
T: Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_ref().hash(state);
}
}