From f17c00795f9b1fc1a7e0c636478e13d66fda737c Mon Sep 17 00:00:00 2001 From: SoniEx2 Date: Fri, 17 Sep 2021 16:17:28 -0300 Subject: Tweak MayBe to better align with Datafu This is a breaking change, but aligning with Datafu is useful. --- src/lib.rs | 65 ++++------------------------------- src/maybe.rs | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 58 deletions(-) create mode 100644 src/maybe.rs (limited to 'src') 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 { - Some(T), - None(serde::de::IgnoredAny), -} +pub use crate::maybe::MayBe; -/// Something that may be an `T`. -/// -/// Unlike `Option`, 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>")] -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[repr(transparent)] -pub struct MayBe(pub Option); - -impl Default for MayBe { - fn default() -> Self { - Self(Default::default()) - } -} - -impl std::ops::Deref for MayBe { - type Target = Option; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl std::ops::DerefMut for MayBe { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl From> for Option { - fn from(thing: MayBe) -> Option { - thing.0 - } -} - -impl From> for MayBe { - fn from(thing: Option) -> MayBe { - Self(thing) - } -} - -impl From>> for MayBe { - fn from(thing: Option>) -> MayBe { - 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 { + 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 Default for MayBe { +// fn default() -> Self { +// MayBe::IsNot +// } +//} +//impl Default for MayBe { +// fn default() -> Self { +// MayBe::Is(T::default()) +// } +//} + +impl MayBe { + /// 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` into an `Option`. + pub fn into_opt(self) -> Option { + self.into() + } + + /// Converts this `&MayBe` 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` 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 Clone for MayBe { + 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 From> for Option { + fn from(thing: MayBe) -> Option { + match thing { + MayBe::Is(t) => Some(t), + MayBe::IsNot => None, + } + } +} + +impl From> for MayBe { + fn from(thing: Option) -> MayBe { + match thing { + Some(t) => MayBe::Is(t), + None => MayBe::IsNot, + } + } +} + +impl From for MayBe { + fn from(thing: T) -> MayBe { + MayBe::Is(thing) + } +} -- cgit 1.4.1