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)
}
}