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