1use std::{marker::PhantomData, ops::Deref};
2
3#[cfg(feature = "did-you-mean")]
4use ploidy_pointer::JsonPointeeType;
5use ploidy_pointer::{JsonPointee, JsonPointeeError, JsonPointer, JsonPointerTypeError};
6use serde::{Deserialize, Deserializer, Serialize, Serializer};
7
8#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
11pub enum AbsentOr<T> {
12 #[default]
13 Absent,
14 Null,
15 Present(T),
16}
17
18impl<T> AbsentOr<T> {
19 #[inline]
21 pub fn is_absent(&self) -> bool {
22 matches!(self, Self::Absent)
23 }
24
25 #[inline]
27 pub fn is_null(&self) -> bool {
28 matches!(self, Self::Null)
29 }
30
31 #[inline]
33 pub fn is_present(&self) -> bool {
34 matches!(self, Self::Present(_))
35 }
36
37 #[inline]
45 pub fn ok(self) -> Result<T, AbsentError> {
46 match self {
47 Self::Absent => Err(AbsentError::Absent),
48 Self::Null => Err(AbsentError::Null),
49 Self::Present(value) => Ok(value),
50 }
51 }
52
53 #[inline]
55 pub fn as_ref(&self) -> AbsentOr<&T> {
56 match self {
57 Self::Absent => AbsentOr::Absent,
58 Self::Null => AbsentOr::Null,
59 Self::Present(value) => AbsentOr::Present(value),
60 }
61 }
62
63 #[inline]
70 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> AbsentOr<U> {
71 match self {
72 Self::Absent => AbsentOr::Absent,
73 Self::Null => AbsentOr::Null,
74 Self::Present(value) => AbsentOr::Present(f(value)),
75 }
76 }
77
78 #[inline]
81 pub fn map_or<U>(self, default: U, f: impl FnOnce(T) -> U) -> U {
82 match self {
83 Self::Absent | Self::Null => default,
84 Self::Present(value) => f(value),
85 }
86 }
87
88 #[inline]
91 pub fn map_or_else<U>(self, default: impl FnOnce() -> U, f: impl FnOnce(T) -> U) -> U {
92 match self {
93 Self::Absent | Self::Null => default(),
94 Self::Present(value) => f(value),
95 }
96 }
97
98 #[inline]
105 pub fn and<U>(self, other: AbsentOr<U>) -> AbsentOr<U> {
106 match self {
107 Self::Absent => AbsentOr::Absent,
108 Self::Null => AbsentOr::Null,
109 Self::Present(_) => other,
110 }
111 }
112
113 #[inline]
120 pub fn and_then<U>(self, f: impl FnOnce(T) -> AbsentOr<U>) -> AbsentOr<U> {
121 match self {
122 Self::Absent => AbsentOr::Absent,
123 Self::Null => AbsentOr::Null,
124 Self::Present(value) => f(value),
125 }
126 }
127
128 #[inline]
131 pub fn or(self, other: AbsentOr<T>) -> AbsentOr<T> {
132 match self {
133 Self::Present(_) => self,
134 Self::Absent | Self::Null => other,
135 }
136 }
137
138 #[inline]
141 pub fn or_else(self, f: impl FnOnce() -> AbsentOr<T>) -> AbsentOr<T> {
142 match self {
143 Self::Present(_) => self,
144 Self::Absent | Self::Null => f(),
145 }
146 }
147
148 #[inline]
151 pub fn unwrap_or(self, default: T) -> T {
152 match self {
153 Self::Absent | Self::Null => default,
154 Self::Present(value) => value,
155 }
156 }
157
158 #[inline]
161 pub fn unwrap_or_else(self, f: impl FnOnce() -> T) -> T {
162 match self {
163 Self::Absent | Self::Null => f(),
164 Self::Present(value) => value,
165 }
166 }
167
168 #[inline]
174 pub fn into_option(self) -> Option<T> {
175 match self {
176 Self::Absent | Self::Null => None,
177 Self::Present(value) => Some(value),
178 }
179 }
180}
181
182impl<T: Deref> AbsentOr<T> {
183 #[inline]
185 pub fn as_deref(&self) -> AbsentOr<&T::Target> {
186 match self {
187 Self::Absent => AbsentOr::Absent,
188 Self::Null => AbsentOr::Null,
189 Self::Present(value) => AbsentOr::Present(value),
190 }
191 }
192}
193
194impl<T: Default> AbsentOr<T> {
195 #[inline]
198 pub fn unwrap_or_default(self) -> T {
199 match self {
200 Self::Absent | Self::Null => T::default(),
201 Self::Present(value) => value,
202 }
203 }
204}
205
206impl<T> From<T> for AbsentOr<T> {
207 #[inline]
208 fn from(value: T) -> Self {
209 Self::Present(value)
210 }
211}
212
213impl<T: JsonPointee> JsonPointee for AbsentOr<T> {
220 fn resolve(&self, pointer: &JsonPointer) -> Result<&dyn JsonPointee, JsonPointeeError> {
221 match self {
222 Self::Present(value) => value.resolve(pointer),
223 _ => Err({
224 #[cfg(feature = "did-you-mean")]
225 let err = JsonPointerTypeError::with_ty(pointer, JsonPointeeType::name_of(self));
226 #[cfg(not(feature = "did-you-mean"))]
227 let err = JsonPointerTypeError::new(pointer);
228 err
229 })?,
230 }
231 }
232}
233
234impl<T: Serialize> Serialize for AbsentOr<T> {
235 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
236 match self {
237 Self::Absent | Self::Null => serializer.serialize_none(),
238 Self::Present(value) => serializer.serialize_some(value),
239 }
240 }
241}
242
243impl<'de, T: Deserialize<'de>> Deserialize<'de> for AbsentOr<T> {
244 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
245 struct Visitor<T>(PhantomData<T>);
246 impl<'de, T: Deserialize<'de>> serde::de::Visitor<'de> for Visitor<T> {
247 type Value = AbsentOr<T>;
248
249 fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
250 f.write_str("`null` or value")
251 }
252
253 fn visit_unit<E: serde::de::Error>(self) -> Result<Self::Value, E> {
254 Ok(AbsentOr::Null)
255 }
256
257 fn visit_none<E: serde::de::Error>(self) -> Result<Self::Value, E> {
258 Ok(AbsentOr::Null)
259 }
260
261 fn visit_some<D: Deserializer<'de>>(
262 self,
263 deserializer: D,
264 ) -> Result<Self::Value, D::Error> {
265 T::deserialize(deserializer).map(AbsentOr::Present)
266 }
267 }
268 deserializer.deserialize_option(Visitor(PhantomData))
269 }
270}
271
272#[derive(Debug, thiserror::Error)]
273pub enum AbsentError {
274 #[error("value not present")]
275 Absent,
276 #[error("value is `null`")]
277 Null,
278}
279
280impl AbsentError {
281 #[inline]
285 pub fn field(self, name: &'static str) -> FieldAbsentError {
286 match self {
287 Self::Absent => FieldAbsentError::Absent(name),
288 Self::Null => FieldAbsentError::Null(name),
289 }
290 }
291}
292
293#[derive(Debug, thiserror::Error)]
294pub enum FieldAbsentError {
295 #[error("field `{0}` not present")]
296 Absent(&'static str),
297 #[error("field `{0}` is `null`")]
298 Null(&'static str),
299}
300
301#[cfg(test)]
302mod tests {
303 use ploidy_pointer::{JsonPointee, JsonPointeeExt, JsonPointerTarget};
304
305 use super::*;
306
307 #[derive(JsonPointee, JsonPointerTarget)]
308 #[ploidy(pointer(untagged))]
309 enum Response {
310 One(ResponseOne),
311 Two(ResponseTwo),
312 }
313
314 #[derive(JsonPointee, JsonPointerTarget)]
315 struct ResponseOne {
316 data: AbsentOr<String>,
317 error: AbsentOr<ResponseError>,
318 }
319
320 #[derive(JsonPointee, JsonPointerTarget)]
321 struct ResponseTwo {
322 data: AbsentOr<i32>,
323 error: AbsentOr<ResponseError>,
324 }
325
326 #[derive(JsonPointee, JsonPointerTarget)]
327 struct ResponseError {
328 message: String,
329 }
330
331 #[test]
332 fn test_absent_or_present_pointer_succeeds() {
333 let response = Response::One(ResponseOne {
334 error: AbsentOr::Present(ResponseError {
335 message: "oops".to_owned(),
336 }),
337 data: AbsentOr::Null,
338 });
339
340 let err = response.pointer::<&ResponseError>("/error").unwrap();
342 assert_eq!(err.message, "oops");
343 }
344
345 #[test]
346 fn test_absent_or_null_errors() {
347 let response = Response::Two(ResponseTwo {
348 data: AbsentOr::Present(2),
349 error: AbsentOr::Null,
350 });
351
352 let result = response.pointer::<&ResponseError>("/error");
355 assert!(result.is_err());
356 }
357
358 #[test]
359 fn test_absent_or_absent_errors() {
360 let response = Response::Two(ResponseTwo {
361 data: AbsentOr::Present(2),
362 error: AbsentOr::Absent,
363 });
364
365 let result = response.pointer::<&ResponseError>("/error");
367 assert!(result.is_err());
368 }
369}