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
18pub trait AbsentOrExt<T> {
20 fn or_absent(self) -> AbsentOr<T>;
23
24 fn or_null(self) -> AbsentOr<T>;
27}
28
29impl<T> AbsentOrExt<T> for Option<T> {
30 #[inline]
31 fn or_absent(self) -> AbsentOr<T> {
32 match self {
33 Some(value) => AbsentOr::Present(value),
34 None => AbsentOr::Absent,
35 }
36 }
37
38 #[inline]
39 fn or_null(self) -> AbsentOr<T> {
40 match self {
41 Some(value) => AbsentOr::Present(value),
42 None => AbsentOr::Null,
43 }
44 }
45}
46
47impl<T> AbsentOr<T> {
48 #[inline]
50 pub fn is_absent(&self) -> bool {
51 matches!(self, Self::Absent)
52 }
53
54 #[inline]
56 pub fn is_null(&self) -> bool {
57 matches!(self, Self::Null)
58 }
59
60 #[inline]
62 pub fn is_present(&self) -> bool {
63 matches!(self, Self::Present(_))
64 }
65
66 #[inline]
74 pub fn ok(self) -> Result<T, AbsentError> {
75 match self {
76 Self::Absent => Err(AbsentError::Absent),
77 Self::Null => Err(AbsentError::Null),
78 Self::Present(value) => Ok(value),
79 }
80 }
81
82 #[inline]
84 pub fn as_ref(&self) -> AbsentOr<&T> {
85 match self {
86 Self::Absent => AbsentOr::Absent,
87 Self::Null => AbsentOr::Null,
88 Self::Present(value) => AbsentOr::Present(value),
89 }
90 }
91
92 #[inline]
99 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> AbsentOr<U> {
100 match self {
101 Self::Absent => AbsentOr::Absent,
102 Self::Null => AbsentOr::Null,
103 Self::Present(value) => AbsentOr::Present(f(value)),
104 }
105 }
106
107 #[inline]
110 pub fn map_or<U>(self, default: U, f: impl FnOnce(T) -> U) -> U {
111 match self {
112 Self::Absent | Self::Null => default,
113 Self::Present(value) => f(value),
114 }
115 }
116
117 #[inline]
120 pub fn map_or_else<U>(self, default: impl FnOnce() -> U, f: impl FnOnce(T) -> U) -> U {
121 match self {
122 Self::Absent | Self::Null => default(),
123 Self::Present(value) => f(value),
124 }
125 }
126
127 #[inline]
134 pub fn and<U>(self, other: AbsentOr<U>) -> AbsentOr<U> {
135 match self {
136 Self::Absent => AbsentOr::Absent,
137 Self::Null => AbsentOr::Null,
138 Self::Present(_) => other,
139 }
140 }
141
142 #[inline]
149 pub fn and_then<U>(self, f: impl FnOnce(T) -> AbsentOr<U>) -> AbsentOr<U> {
150 match self {
151 Self::Absent => AbsentOr::Absent,
152 Self::Null => AbsentOr::Null,
153 Self::Present(value) => f(value),
154 }
155 }
156
157 #[inline]
160 pub fn or(self, other: AbsentOr<T>) -> AbsentOr<T> {
161 match self {
162 Self::Present(_) => self,
163 Self::Absent | Self::Null => other,
164 }
165 }
166
167 #[inline]
170 pub fn or_else(self, f: impl FnOnce() -> AbsentOr<T>) -> AbsentOr<T> {
171 match self {
172 Self::Present(_) => self,
173 Self::Absent | Self::Null => f(),
174 }
175 }
176
177 #[inline]
180 pub fn unwrap_or(self, default: T) -> T {
181 match self {
182 Self::Absent | Self::Null => default,
183 Self::Present(value) => value,
184 }
185 }
186
187 #[inline]
190 pub fn unwrap_or_else(self, f: impl FnOnce() -> T) -> T {
191 match self {
192 Self::Absent | Self::Null => f(),
193 Self::Present(value) => value,
194 }
195 }
196
197 #[inline]
203 pub fn into_option(self) -> Option<T> {
204 match self {
205 Self::Absent | Self::Null => None,
206 Self::Present(value) => Some(value),
207 }
208 }
209}
210
211impl<T: Deref> AbsentOr<T> {
212 #[inline]
214 pub fn as_deref(&self) -> AbsentOr<&T::Target> {
215 match self {
216 Self::Absent => AbsentOr::Absent,
217 Self::Null => AbsentOr::Null,
218 Self::Present(value) => AbsentOr::Present(value),
219 }
220 }
221}
222
223impl<T: Default> AbsentOr<T> {
224 #[inline]
227 pub fn unwrap_or_default(self) -> T {
228 match self {
229 Self::Absent | Self::Null => T::default(),
230 Self::Present(value) => value,
231 }
232 }
233}
234
235impl<T> From<T> for AbsentOr<T> {
236 #[inline]
237 fn from(value: T) -> Self {
238 Self::Present(value)
239 }
240}
241
242impl<T: JsonPointee> JsonPointee for AbsentOr<T> {
249 fn resolve(&self, pointer: &JsonPointer) -> Result<&dyn JsonPointee, JsonPointeeError> {
250 match self {
251 Self::Present(value) => value.resolve(pointer),
252 _ => Err({
253 #[cfg(feature = "did-you-mean")]
254 let err = JsonPointerTypeError::with_ty(pointer, JsonPointeeType::name_of(self));
255 #[cfg(not(feature = "did-you-mean"))]
256 let err = JsonPointerTypeError::new(pointer);
257 err
258 })?,
259 }
260 }
261}
262
263impl<T: Serialize> Serialize for AbsentOr<T> {
264 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
265 match self {
266 Self::Absent | Self::Null => serializer.serialize_none(),
267 Self::Present(value) => serializer.serialize_some(value),
268 }
269 }
270}
271
272impl<'de, T: Deserialize<'de>> Deserialize<'de> for AbsentOr<T> {
273 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
274 struct Visitor<T>(PhantomData<T>);
275 impl<'de, T: Deserialize<'de>> serde::de::Visitor<'de> for Visitor<T> {
276 type Value = AbsentOr<T>;
277
278 fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
279 f.write_str("`null` or value")
280 }
281
282 fn visit_unit<E: serde::de::Error>(self) -> Result<Self::Value, E> {
283 Ok(AbsentOr::Null)
284 }
285
286 fn visit_none<E: serde::de::Error>(self) -> Result<Self::Value, E> {
287 Ok(AbsentOr::Null)
288 }
289
290 fn visit_some<D: Deserializer<'de>>(
291 self,
292 deserializer: D,
293 ) -> Result<Self::Value, D::Error> {
294 T::deserialize(deserializer).map(AbsentOr::Present)
295 }
296 }
297 deserializer.deserialize_option(Visitor(PhantomData))
298 }
299}
300
301#[derive(Debug, thiserror::Error)]
302pub enum AbsentError {
303 #[error("value not present")]
304 Absent,
305 #[error("value is `null`")]
306 Null,
307}
308
309impl AbsentError {
310 #[inline]
314 pub fn field(self, name: &'static str) -> FieldAbsentError {
315 match self {
316 Self::Absent => FieldAbsentError::Absent(name),
317 Self::Null => FieldAbsentError::Null(name),
318 }
319 }
320}
321
322#[derive(Debug, thiserror::Error)]
323pub enum FieldAbsentError {
324 #[error("field `{0}` not present")]
325 Absent(&'static str),
326 #[error("field `{0}` is `null`")]
327 Null(&'static str),
328}
329
330#[cfg(test)]
331mod tests {
332 use ploidy_pointer::{JsonPointee, JsonPointeeExt, JsonPointerTarget};
333
334 use super::*;
335
336 #[derive(JsonPointee, JsonPointerTarget)]
337 #[ploidy(pointer(untagged))]
338 enum Response {
339 One(ResponseOne),
340 Two(ResponseTwo),
341 }
342
343 #[derive(JsonPointee, JsonPointerTarget)]
344 struct ResponseOne {
345 data: AbsentOr<String>,
346 error: AbsentOr<ResponseError>,
347 }
348
349 #[derive(JsonPointee, JsonPointerTarget)]
350 struct ResponseTwo {
351 data: AbsentOr<i32>,
352 error: AbsentOr<ResponseError>,
353 }
354
355 #[derive(JsonPointee, JsonPointerTarget)]
356 struct ResponseError {
357 message: String,
358 }
359
360 #[test]
361 fn test_absent_or_present_pointer_succeeds() {
362 let response = Response::One(ResponseOne {
363 error: AbsentOr::Present(ResponseError {
364 message: "oops".to_owned(),
365 }),
366 data: AbsentOr::Null,
367 });
368
369 let err = response.pointer::<&ResponseError>("/error").unwrap();
371 assert_eq!(err.message, "oops");
372 }
373
374 #[test]
375 fn test_absent_or_null_errors() {
376 let response = Response::Two(ResponseTwo {
377 data: AbsentOr::Present(2),
378 error: AbsentOr::Null,
379 });
380
381 let result = response.pointer::<&ResponseError>("/error");
384 assert!(result.is_err());
385 }
386
387 #[test]
388 fn test_absent_or_absent_errors() {
389 let response = Response::Two(ResponseTwo {
390 data: AbsentOr::Present(2),
391 error: AbsentOr::Absent,
392 });
393
394 let result = response.pointer::<&ResponseError>("/error");
396 assert!(result.is_err());
397 }
398
399 #[test]
400 fn test_absent_or_ext_option_some_is_present() {
401 let value = Some("value").or_absent();
402 assert_eq!(value, AbsentOr::Present("value"));
403
404 let value = Some("value").or_null();
405 assert_eq!(value, AbsentOr::Present("value"));
406 }
407
408 #[test]
409 fn test_absent_or_ext_option_none_or_absent_is_absent() {
410 let value: AbsentOr<&str> = None.or_absent();
411 assert_eq!(value, AbsentOr::Absent);
412 }
413
414 #[test]
415 fn test_absent_or_ext_option_none_or_null_is_null() {
416 let value: AbsentOr<&str> = None.or_null();
417 assert_eq!(value, AbsentOr::Null);
418 }
419}