summary refs log blame commit diff stats
path: root/src/maybe.rs
blob: 9b2c419e0f2ab133c2abae76ddef3023b8b31623 (plain) (tree)












































































































                                                                             
use serde::Deserialize;
use serde::Deserializer;

/// Something that may be an `T`.
///
/// If a value cannot be deserialized as a `T`, this will *discard* the value
/// and provide an `MayBe::IsNot`.
///
/// Can only be used with self-describing formats, like JSON.
#[derive(Deserialize)]
#[serde(untagged)]
#[derive(Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum MayBe<T> {
    Is(T),
    #[serde(deserialize_with = "ignore_any")]
    IsNot,
}

fn ignore_any<'de, D: Deserializer<'de>>(d: D) -> Result<(), D::Error> {
    serde::de::IgnoredAny::deserialize(d).map(|_| ())
}

// FIXME decide on Default
// This enum is analogous to Result, *not* Option.
//
//impl<T> Default for MayBe<T> {
//    fn default() -> Self {
//        MayBe::IsNot
//    }
//}
//impl<T: Default> Default for MayBe<T> {
//    fn default() -> Self {
//        MayBe::Is(T::default())
//    }
//}

impl<T> MayBe<T> {
    /// Returns whether the `MayBe` contains a `T`.
    pub fn is(&self) -> bool {
        matches!(self, MayBe::Is(_))
    }

    /// Returns whether the `MayBe` does not contain a `T`.
    pub fn is_not(&self) -> bool {
        !self.is()
    }

    /// Converts this `MayBe<T>` into an `Option<T>`.
    pub fn into_opt(self) -> Option<T> {
        self.into()
    }

    /// Converts this `&MayBe<T>` into an `Option<&T>`.
    pub fn as_opt(&self) -> Option<&T> {
        match self {
            MayBe::Is(t) => Some(t),
            MayBe::IsNot => None,
        }
    }

    /// Converts this `&mut MayBe<T>` into an `Option<&mut T>`.
    pub fn as_mut_opt(&mut self) -> Option<&mut T> {
        match self {
            MayBe::Is(t) => Some(t),
            MayBe::IsNot => None,
        }
    }
}

impl<T: Clone> Clone for MayBe<T> {
    fn clone(&self) -> Self {
        match self {
            MayBe::Is(t) => MayBe::Is(t.clone()),
            MayBe::IsNot => MayBe::IsNot,
        }
    }

    fn clone_from(&mut self, source: &Self) {
        match (self, source) {
            (MayBe::Is(a), MayBe::Is(b)) => a.clone_from(b),
            (MayBe::IsNot, MayBe::IsNot) => (),
            (a, b) => *a = b.clone(),
        }
    }
}

impl<T> From<MayBe<T>> for Option<T> {
    fn from(thing: MayBe<T>) -> Option<T> {
        match thing {
            MayBe::Is(t) => Some(t),
            MayBe::IsNot => None,
        }
    }
}

impl<T> From<Option<T>> for MayBe<T> {
    fn from(thing: Option<T>) -> MayBe<T> {
        match thing {
            Some(t) => MayBe::Is(t),
            None => MayBe::IsNot,
        }
    }
}

impl<T> From<T> for MayBe<T> {
    fn from(thing: T) -> MayBe<T> {
        MayBe::Is(thing)
    }
}