ploidy_util/
absent.rs

1use std::marker::PhantomData;
2
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4
5/// An [`Option`]-like type that distinguishes between
6/// "value not present" and "value present but `null`".
7#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
8pub enum AbsentOr<T> {
9    #[default]
10    Absent,
11    Null,
12    Present(T),
13}
14
15impl<T> AbsentOr<T> {
16    #[inline]
17    pub fn is_absent(&self) -> bool {
18        matches!(self, Self::Absent)
19    }
20
21    #[inline]
22    pub fn is_null(&self) -> bool {
23        matches!(self, Self::Null)
24    }
25
26    #[inline]
27    pub fn is_present(&self) -> bool {
28        matches!(self, Self::Present(_))
29    }
30
31    #[inline]
32    pub fn ok(self) -> Result<T, AbsentError> {
33        match self {
34            Self::Absent => Err(AbsentError::Absent),
35            Self::Null => Err(AbsentError::Null),
36            Self::Present(value) => Ok(value),
37        }
38    }
39
40    #[inline]
41    pub fn as_ref(&self) -> AbsentOr<&T> {
42        match self {
43            Self::Absent => AbsentOr::Absent,
44            Self::Null => AbsentOr::Null,
45            Self::Present(value) => AbsentOr::Present(value),
46        }
47    }
48
49    #[inline]
50    pub fn into_option(self) -> Option<T> {
51        match self {
52            Self::Absent | Self::Null => None,
53            Self::Present(value) => Some(value),
54        }
55    }
56}
57
58impl<T> From<T> for AbsentOr<T> {
59    #[inline]
60    fn from(value: T) -> Self {
61        Self::Present(value)
62    }
63}
64
65impl<T: Serialize> Serialize for AbsentOr<T> {
66    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
67        match self {
68            Self::Absent | Self::Null => serializer.serialize_none(),
69            Self::Present(value) => serializer.serialize_some(value),
70        }
71    }
72}
73
74impl<'de, T: Deserialize<'de>> Deserialize<'de> for AbsentOr<T> {
75    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
76        struct Visitor<T>(PhantomData<T>);
77        impl<'de, T: Deserialize<'de>> serde::de::Visitor<'de> for Visitor<T> {
78            type Value = AbsentOr<T>;
79
80            fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81                f.write_str("`null` or value")
82            }
83
84            fn visit_unit<E: serde::de::Error>(self) -> Result<Self::Value, E> {
85                Ok(AbsentOr::Null)
86            }
87
88            fn visit_none<E: serde::de::Error>(self) -> Result<Self::Value, E> {
89                Ok(AbsentOr::Null)
90            }
91
92            fn visit_some<D: Deserializer<'de>>(
93                self,
94                deserializer: D,
95            ) -> Result<Self::Value, D::Error> {
96                T::deserialize(deserializer).map(AbsentOr::Present)
97            }
98        }
99        deserializer.deserialize_option(Visitor(PhantomData))
100    }
101}
102
103#[derive(Debug, thiserror::Error)]
104pub enum AbsentError {
105    #[error("value not present")]
106    Absent,
107    #[error("value is `null`")]
108    Null,
109}
110
111impl AbsentError {
112    #[inline]
113    pub fn field(self, name: &'static str) -> FieldAbsentError {
114        match self {
115            Self::Absent => FieldAbsentError::Absent(name),
116            Self::Null => FieldAbsentError::Null(name),
117        }
118    }
119}
120
121#[derive(Debug, thiserror::Error)]
122pub enum FieldAbsentError {
123    #[error("field `{0}` not present")]
124    Absent(&'static str),
125    #[error("field `{0}` is `null`")]
126    Null(&'static str),
127}