1use std::{borrow::Cow, ops::Deref};
2
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4
5use crate::{registry, InputType, InputValueError, InputValueResult, Value};
6
7#[allow(missing_docs)]
50#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
51pub enum MaybeUndefined<T> {
52 Undefined,
53 Null,
54 Value(T),
55}
56
57impl<T> Default for MaybeUndefined<T> {
58 fn default() -> Self {
59 Self::Undefined
60 }
61}
62
63impl<T> MaybeUndefined<T> {
64 #[inline]
66 pub const fn is_undefined(&self) -> bool {
67 matches!(self, MaybeUndefined::Undefined)
68 }
69
70 #[inline]
72 pub const fn is_null(&self) -> bool {
73 matches!(self, MaybeUndefined::Null)
74 }
75
76 #[inline]
78 pub const fn is_value(&self) -> bool {
79 matches!(self, MaybeUndefined::Value(_))
80 }
81
82 #[inline]
85 pub const fn value(&self) -> Option<&T> {
86 match self {
87 MaybeUndefined::Value(value) => Some(value),
88 _ => None,
89 }
90 }
91
92 #[inline]
94 pub fn take(self) -> Option<T> {
95 match self {
96 MaybeUndefined::Value(value) => Some(value),
97 _ => None,
98 }
99 }
100
101 #[inline]
103 pub const fn as_opt_ref(&self) -> Option<Option<&T>> {
104 match self {
105 MaybeUndefined::Undefined => None,
106 MaybeUndefined::Null => Some(None),
107 MaybeUndefined::Value(value) => Some(Some(value)),
108 }
109 }
110
111 #[inline]
113 pub fn as_opt_deref<U>(&self) -> Option<Option<&U>>
114 where
115 U: ?Sized,
116 T: Deref<Target = U>,
117 {
118 match self {
119 MaybeUndefined::Undefined => None,
120 MaybeUndefined::Null => Some(None),
121 MaybeUndefined::Value(value) => Some(Some(value.deref())),
122 }
123 }
124
125 #[inline]
127 pub fn contains_value<U>(&self, x: &U) -> bool
128 where
129 U: PartialEq<T>,
130 {
131 match self {
132 MaybeUndefined::Value(y) => x == y,
133 _ => false,
134 }
135 }
136
137 #[inline]
140 pub fn contains<U>(&self, x: &Option<U>) -> bool
141 where
142 U: PartialEq<T>,
143 {
144 match self {
145 MaybeUndefined::Value(y) => matches!(x, Some(v) if v == y),
146 MaybeUndefined::Null => x.is_none(),
147 MaybeUndefined::Undefined => false,
148 }
149 }
150
151 #[inline]
154 pub fn map<U, F: FnOnce(Option<T>) -> Option<U>>(self, f: F) -> MaybeUndefined<U> {
155 match self {
156 MaybeUndefined::Value(v) => match f(Some(v)) {
157 Some(v) => MaybeUndefined::Value(v),
158 None => MaybeUndefined::Null,
159 },
160 MaybeUndefined::Null => match f(None) {
161 Some(v) => MaybeUndefined::Value(v),
162 None => MaybeUndefined::Null,
163 },
164 MaybeUndefined::Undefined => MaybeUndefined::Undefined,
165 }
166 }
167
168 #[inline]
171 pub fn map_value<U, F: FnOnce(T) -> U>(self, f: F) -> MaybeUndefined<U> {
172 match self {
173 MaybeUndefined::Value(v) => MaybeUndefined::Value(f(v)),
174 MaybeUndefined::Null => MaybeUndefined::Null,
175 MaybeUndefined::Undefined => MaybeUndefined::Undefined,
176 }
177 }
178
179 pub fn update_to(self, value: &mut Option<T>) {
198 match self {
199 MaybeUndefined::Value(new) => *value = Some(new),
200 MaybeUndefined::Null => *value = None,
201 MaybeUndefined::Undefined => {}
202 };
203 }
204}
205
206impl<T: InputType> InputType for MaybeUndefined<T> {
207 type RawValueType = T::RawValueType;
208
209 fn type_name() -> Cow<'static, str> {
210 T::type_name()
211 }
212
213 fn qualified_type_name() -> String {
214 T::type_name().to_string()
215 }
216
217 fn create_type_info(registry: &mut registry::Registry) -> String {
218 T::create_type_info(registry);
219 T::type_name().to_string()
220 }
221
222 fn parse(value: Option<Value>) -> InputValueResult<Self> {
223 match value {
224 None => Ok(MaybeUndefined::Undefined),
225 Some(Value::Null) => Ok(MaybeUndefined::Null),
226 Some(value) => Ok(MaybeUndefined::Value(
227 T::parse(Some(value)).map_err(InputValueError::propagate)?,
228 )),
229 }
230 }
231
232 fn to_value(&self) -> Value {
233 match self {
234 MaybeUndefined::Value(value) => value.to_value(),
235 _ => Value::Null,
236 }
237 }
238
239 fn as_raw_value(&self) -> Option<&Self::RawValueType> {
240 if let MaybeUndefined::Value(value) = self {
241 value.as_raw_value()
242 } else {
243 None
244 }
245 }
246}
247
248impl<T, E> MaybeUndefined<Result<T, E>> {
249 #[inline]
259 pub fn transpose(self) -> Result<MaybeUndefined<T>, E> {
260 match self {
261 MaybeUndefined::Undefined => Ok(MaybeUndefined::Undefined),
262 MaybeUndefined::Null => Ok(MaybeUndefined::Null),
263 MaybeUndefined::Value(Ok(v)) => Ok(MaybeUndefined::Value(v)),
264 MaybeUndefined::Value(Err(e)) => Err(e),
265 }
266 }
267}
268
269impl<T: Serialize> Serialize for MaybeUndefined<T> {
270 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
271 match self {
272 MaybeUndefined::Value(value) => value.serialize(serializer),
273 _ => serializer.serialize_none(),
274 }
275 }
276}
277
278impl<'de, T> Deserialize<'de> for MaybeUndefined<T>
279where
280 T: Deserialize<'de>,
281{
282 fn deserialize<D>(deserializer: D) -> Result<MaybeUndefined<T>, D::Error>
283 where
284 D: Deserializer<'de>,
285 {
286 Option::<T>::deserialize(deserializer).map(|value| match value {
287 Some(value) => MaybeUndefined::Value(value),
288 None => MaybeUndefined::Null,
289 })
290 }
291}
292
293impl<T> From<MaybeUndefined<T>> for Option<Option<T>> {
294 fn from(maybe_undefined: MaybeUndefined<T>) -> Self {
295 match maybe_undefined {
296 MaybeUndefined::Undefined => None,
297 MaybeUndefined::Null => Some(None),
298 MaybeUndefined::Value(value) => Some(Some(value)),
299 }
300 }
301}
302
303impl<T> From<Option<Option<T>>> for MaybeUndefined<T> {
304 fn from(value: Option<Option<T>>) -> Self {
305 match value {
306 Some(Some(value)) => Self::Value(value),
307 Some(None) => Self::Null,
308 None => Self::Undefined,
309 }
310 }
311}
312
313#[cfg(test)]
314mod tests {
315 use serde::{Deserialize, Serialize};
316
317 use crate::*;
318
319 #[test]
320 fn test_maybe_undefined_type() {
321 assert_eq!(MaybeUndefined::<i32>::type_name(), "Int");
322 assert_eq!(MaybeUndefined::<i32>::qualified_type_name(), "Int");
323 assert_eq!(&MaybeUndefined::<i32>::type_name(), "Int");
324 assert_eq!(&MaybeUndefined::<i32>::qualified_type_name(), "Int");
325 }
326
327 #[test]
328 fn test_maybe_undefined_serde() {
329 assert_eq!(
330 to_value(MaybeUndefined::Value(100i32)).unwrap(),
331 value!(100)
332 );
333
334 assert_eq!(
335 from_value::<MaybeUndefined<i32>>(value!(100)).unwrap(),
336 MaybeUndefined::Value(100)
337 );
338 assert_eq!(
339 from_value::<MaybeUndefined<i32>>(value!(null)).unwrap(),
340 MaybeUndefined::Null
341 );
342
343 #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)]
344 struct A {
345 a: MaybeUndefined<i32>,
346 }
347
348 assert_eq!(
349 to_value(&A {
350 a: MaybeUndefined::Value(100i32)
351 })
352 .unwrap(),
353 value!({"a": 100})
354 );
355
356 assert_eq!(
357 to_value(&A {
358 a: MaybeUndefined::Null,
359 })
360 .unwrap(),
361 value!({ "a": null })
362 );
363
364 assert_eq!(
365 to_value(&A {
366 a: MaybeUndefined::Undefined,
367 })
368 .unwrap(),
369 value!({ "a": null })
370 );
371
372 assert_eq!(
373 from_value::<A>(value!({"a": 100})).unwrap(),
374 A {
375 a: MaybeUndefined::Value(100i32)
376 }
377 );
378
379 assert_eq!(
380 from_value::<A>(value!({ "a": null })).unwrap(),
381 A {
382 a: MaybeUndefined::Null
383 }
384 );
385
386 assert_eq!(
387 from_value::<A>(value!({})).unwrap(),
388 A {
389 a: MaybeUndefined::Null
390 }
391 );
392 }
393
394 #[test]
395 fn test_maybe_undefined_to_nested_option() {
396 assert_eq!(Option::<Option<i32>>::from(MaybeUndefined::Undefined), None);
397
398 assert_eq!(
399 Option::<Option<i32>>::from(MaybeUndefined::Null),
400 Some(None)
401 );
402
403 assert_eq!(
404 Option::<Option<i32>>::from(MaybeUndefined::Value(42)),
405 Some(Some(42))
406 );
407 }
408
409 #[test]
410 fn test_as_opt_ref() {
411 let value = MaybeUndefined::<String>::Undefined;
412 let r = value.as_opt_ref();
413 assert_eq!(r, None);
414
415 let value = MaybeUndefined::<String>::Null;
416 let r = value.as_opt_ref();
417 assert_eq!(r, Some(None));
418
419 let value = MaybeUndefined::<String>::Value("abc".to_string());
420 let r = value.as_opt_ref();
421 assert_eq!(r, Some(Some(&"abc".to_string())));
422 }
423
424 #[test]
425 fn test_as_opt_deref() {
426 let value = MaybeUndefined::<String>::Undefined;
427 let r = value.as_opt_deref();
428 assert_eq!(r, None);
429
430 let value = MaybeUndefined::<String>::Null;
431 let r = value.as_opt_deref();
432 assert_eq!(r, Some(None));
433
434 let value = MaybeUndefined::<String>::Value("abc".to_string());
435 let r = value.as_opt_deref();
436 assert_eq!(r, Some(Some("abc")));
437 }
438
439 #[test]
440 fn test_contains_value() {
441 let test = "abc";
442
443 let mut value: MaybeUndefined<String> = MaybeUndefined::Undefined;
444 assert!(!value.contains_value(&test));
445
446 value = MaybeUndefined::Null;
447 assert!(!value.contains_value(&test));
448
449 value = MaybeUndefined::Value("abc".to_string());
450 assert!(value.contains_value(&test));
451 }
452
453 #[test]
454 fn test_contains() {
455 let test = Some("abc");
456 let none: Option<&str> = None;
457
458 let mut value: MaybeUndefined<String> = MaybeUndefined::Undefined;
459 assert!(!value.contains(&test));
460 assert!(!value.contains(&none));
461
462 value = MaybeUndefined::Null;
463 assert!(!value.contains(&test));
464 assert!(value.contains(&none));
465
466 value = MaybeUndefined::Value("abc".to_string());
467 assert!(value.contains(&test));
468 assert!(!value.contains(&none));
469 }
470
471 #[test]
472 fn test_map_value() {
473 let mut value: MaybeUndefined<i32> = MaybeUndefined::Undefined;
474 assert_eq!(value.map_value(|v| v > 2), MaybeUndefined::Undefined);
475
476 value = MaybeUndefined::Null;
477 assert_eq!(value.map_value(|v| v > 2), MaybeUndefined::Null);
478
479 value = MaybeUndefined::Value(5);
480 assert_eq!(value.map_value(|v| v > 2), MaybeUndefined::Value(true));
481 }
482
483 #[test]
484 fn test_map() {
485 let mut value: MaybeUndefined<i32> = MaybeUndefined::Undefined;
486 assert_eq!(value.map(|v| Some(v.is_some())), MaybeUndefined::Undefined);
487
488 value = MaybeUndefined::Null;
489 assert_eq!(
490 value.map(|v| Some(v.is_some())),
491 MaybeUndefined::Value(false)
492 );
493
494 value = MaybeUndefined::Value(5);
495 assert_eq!(
496 value.map(|v| Some(v.is_some())),
497 MaybeUndefined::Value(true)
498 );
499 }
500
501 #[test]
502 fn test_transpose() {
503 let mut value: MaybeUndefined<Result<i32, &'static str>> = MaybeUndefined::Undefined;
504 assert_eq!(value.transpose(), Ok(MaybeUndefined::Undefined));
505
506 value = MaybeUndefined::Null;
507 assert_eq!(value.transpose(), Ok(MaybeUndefined::Null));
508
509 value = MaybeUndefined::Value(Ok(5));
510 assert_eq!(value.transpose(), Ok(MaybeUndefined::Value(5)));
511
512 value = MaybeUndefined::Value(Err("error"));
513 assert_eq!(value.transpose(), Err("error"));
514 }
515}