s2_common/
maybe.rs

1use serde::{Deserialize, Serialize};
2
3/// The [`Maybe`] type represents an optional that might or might not be specified.
4///
5/// An [`Option`] is deserialized as [`None`] if either the value is not specified or the value is
6/// `null`. [`Maybe`] allows us to distinguish between the two.
7///
8/// # Examples
9///
10/// ```
11/// use s2_common::maybe::Maybe;
12///
13/// #[derive(Debug, PartialEq, Eq, serde::Deserialize)]
14/// pub struct MyStruct {
15///     #[serde(default)]
16///     pub field: Maybe<Option<u32>>,
17/// }
18///
19/// assert_eq!(
20///     MyStruct { field: Maybe::Unspecified },
21///     serde_json::from_str("{}").unwrap(),
22/// );
23///
24/// assert_eq!(
25///     MyStruct { field: Maybe::Specified(None) },
26///     serde_json::from_str(r#"{ "field": null }"#).unwrap(),
27/// );
28///
29/// assert_eq!(
30///     MyStruct { field: Maybe::Specified(Some(10)) },
31///     serde_json::from_str(r#"{ "field": 10 }"#).unwrap(),
32/// );
33/// ```
34#[derive(Debug, Clone, Default, PartialEq, Eq)]
35pub enum Maybe<T> {
36    #[default]
37    Unspecified,
38    Specified(T),
39}
40
41impl<T> Maybe<T> {
42    pub fn is_unspecified(&self) -> bool {
43        matches!(self, Self::Unspecified)
44    }
45
46    pub fn map<U, F>(self, f: F) -> Maybe<U>
47    where
48        F: FnOnce(T) -> U,
49    {
50        match self {
51            Self::Unspecified => Maybe::Unspecified,
52            Self::Specified(x) => Maybe::Specified(f(x)),
53        }
54    }
55
56    pub fn unwrap_or_default(self) -> T
57    where
58        T: Default,
59    {
60        match self {
61            Self::Unspecified => T::default(),
62            Self::Specified(x) => x,
63        }
64    }
65}
66
67impl<T> Maybe<Option<T>> {
68    pub fn map_opt<U, F>(self, f: F) -> Maybe<Option<U>>
69    where
70        F: FnOnce(T) -> U,
71    {
72        self.map(|opt| opt.map(f))
73    }
74
75    pub fn try_map_opt<U, E, F>(self, f: F) -> Result<Maybe<Option<U>>, E>
76    where
77        F: FnOnce(T) -> Result<U, E>,
78    {
79        match self {
80            Maybe::Unspecified => Ok(Maybe::Unspecified),
81            Maybe::Specified(opt) => match opt {
82                Some(value) => f(value).map(|converted| Maybe::Specified(Some(converted))),
83                None => Ok(Maybe::Specified(None)),
84            },
85        }
86    }
87
88    pub fn opt_or_default_mut(&mut self) -> &mut T
89    where
90        T: Default,
91    {
92        match self {
93            Maybe::Unspecified | Maybe::Specified(None) => {
94                *self = Self::Specified(Some(T::default()));
95                match self {
96                    Self::Specified(Some(x)) => x,
97                    _ => unreachable!(),
98                }
99            }
100            Maybe::Specified(Some(x)) => x,
101        }
102    }
103}
104
105impl<T> From<T> for Maybe<T> {
106    fn from(value: T) -> Self {
107        Self::Specified(value)
108    }
109}
110
111impl<T: Serialize> Serialize for Maybe<T> {
112    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
113    where
114        S: serde::Serializer,
115    {
116        match self {
117            Self::Unspecified => serializer.serialize_none(),
118            Self::Specified(v) => v.serialize(serializer),
119        }
120    }
121}
122
123impl<'de, T: Deserialize<'de>> Deserialize<'de> for Maybe<T> {
124    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
125    where
126        D: serde::Deserializer<'de>,
127    {
128        let v = T::deserialize(deserializer)?;
129        Ok(v.into())
130    }
131}