diff options
author | SoniEx2 <endermoneymod@gmail.com> | 2021-09-17 16:17:28 -0300 |
---|---|---|
committer | SoniEx2 <endermoneymod@gmail.com> | 2021-09-17 16:17:28 -0300 |
commit | f17c00795f9b1fc1a7e0c636478e13d66fda737c (patch) | |
tree | 1bdd38fa760c0da944ef2fe8964de782ed7f7267 /src/maybe.rs | |
parent | 134727652dc3a65bc5cf6a4d3cfb1c24fd023d5e (diff) |
Tweak MayBe to better align with Datafu
This is a breaking change, but aligning with Datafu is useful.
Diffstat (limited to 'src/maybe.rs')
-rw-r--r-- | src/maybe.rs | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/src/maybe.rs b/src/maybe.rs new file mode 100644 index 0000000..9b2c419 --- /dev/null +++ b/src/maybe.rs @@ -0,0 +1,109 @@ +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) + } +} |