summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs65
-rw-r--r--src/maybe.rs109
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)
+    }
+}