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 | |
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')
-rw-r--r-- | src/lib.rs | 65 | ||||
-rw-r--r-- | src/maybe.rs | 109 |
2 files changed, 116 insertions, 58 deletions
diff --git a/src/lib.rs b/src/lib.rs index 0002663..335a283 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,60 +1,9 @@ -use serde::Deserialize; +//! Soni's Serde Utilities. +//! +//! This crate provides some utilities for use with [`serde`]. -#[derive(Deserialize)] -#[serde(untagged)] -enum MaybeHelper<T> { - Some(T), - None(serde::de::IgnoredAny), -} +pub use crate::maybe::MayBe; -/// Something that may be an `T`. -/// -/// Unlike `Option<T>`, this places no restriction on whether something -/// can't be something else entirely. -/// -/// Can only be used with self-describing formats, like JSON. -#[derive(Deserialize)] -#[serde(from = "Option<MaybeHelper<T>>")] -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[repr(transparent)] -pub struct MayBe<T>(pub Option<T>); - -impl<T> Default for MayBe<T> { - fn default() -> Self { - Self(Default::default()) - } -} - -impl<T> std::ops::Deref for MayBe<T> { - type Target = Option<T>; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl<T> std::ops::DerefMut for MayBe<T> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl<T> From<MayBe<T>> for Option<T> { - fn from(thing: MayBe<T>) -> Option<T> { - thing.0 - } -} - -impl<T> From<Option<T>> for MayBe<T> { - fn from(thing: Option<T>) -> MayBe<T> { - Self(thing) - } -} - -impl<T> From<Option<MaybeHelper<T>>> for MayBe<T> { - fn from(thing: Option<MaybeHelper<T>>) -> MayBe<T> { - Self(match thing { - Some(MaybeHelper::Some(v)) => Some(v), - _ => None, - }) - } -} +mod maybe; +// TODO: stuff for use with MayBe + Vec/HashMap/BTreeMap/etc +//mod container_utils; 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) + } +} |