summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs60
1 files changed, 60 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..0002663
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,60 @@
+use serde::Deserialize;
+
+#[derive(Deserialize)]
+#[serde(untagged)]
+enum MaybeHelper<T> {
+    Some(T),
+    None(serde::de::IgnoredAny),
+}
+
+/// 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,
+        })
+    }
+}