1use std::{borrow::Cow, ops::Deref};
2
3use poem::{http::HeaderValue, web::Field as PoemField};
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use serde_json::Value;
6
7use crate::{
8 registry::{MetaSchemaRef, Registry},
9 types::{
10 ParseError, ParseFromJSON, ParseFromMultipartField, ParseFromParameter, ParseResult,
11 ToHeader, ToJSON, Type,
12 },
13};
14
15#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
87pub enum MaybeUndefined<T> {
88 Undefined,
90 Null,
92 Value(T),
94}
95
96impl<T> Default for MaybeUndefined<T> {
97 fn default() -> Self {
98 Self::Undefined
99 }
100}
101
102impl<T> From<T> for MaybeUndefined<T> {
103 fn from(value: T) -> Self {
104 MaybeUndefined::Value(value)
105 }
106}
107
108impl<T> IntoIterator for MaybeUndefined<T> {
109 type Item = T;
110 type IntoIter = std::option::IntoIter<T>;
111
112 fn into_iter(self) -> Self::IntoIter {
113 self.take().into_iter()
114 }
115}
116
117impl<T> MaybeUndefined<T> {
118 pub fn from_opt_undefined(value: Option<T>) -> Self {
121 match value {
122 Some(value) => MaybeUndefined::Value(value),
123 None => MaybeUndefined::Undefined,
124 }
125 }
126
127 pub fn from_opt_null(value: Option<T>) -> Self {
130 match value {
131 Some(value) => MaybeUndefined::Value(value),
132 None => MaybeUndefined::Null,
133 }
134 }
135
136 #[inline]
138 pub const fn is_undefined(&self) -> bool {
139 matches!(self, MaybeUndefined::Undefined)
140 }
141
142 #[inline]
144 pub const fn is_null(&self) -> bool {
145 matches!(self, MaybeUndefined::Null)
146 }
147
148 #[inline]
150 pub const fn is_value(&self) -> bool {
151 matches!(self, MaybeUndefined::Value(_))
152 }
153
154 #[inline]
157 pub const fn value(&self) -> Option<&T> {
158 match self {
159 MaybeUndefined::Value(value) => Some(value),
160 _ => None,
161 }
162 }
163
164 #[inline]
167 pub fn value_mut(&mut self) -> Option<&mut T> {
168 match self {
169 MaybeUndefined::Value(value) => Some(value),
170 _ => None,
171 }
172 }
173
174 #[inline]
176 pub fn take(self) -> Option<T> {
177 match self {
178 MaybeUndefined::Value(value) => Some(value),
179 _ => None,
180 }
181 }
182
183 #[inline]
185 pub const fn as_ref(&self) -> MaybeUndefined<&T> {
186 match self {
187 MaybeUndefined::Undefined => MaybeUndefined::Undefined,
188 MaybeUndefined::Null => MaybeUndefined::Null,
189 MaybeUndefined::Value(value) => MaybeUndefined::Value(value),
190 }
191 }
192
193 #[inline]
195 pub const fn as_opt_ref(&self) -> Option<Option<&T>> {
196 match self {
197 MaybeUndefined::Undefined => None,
198 MaybeUndefined::Null => Some(None),
199 MaybeUndefined::Value(value) => Some(Some(value)),
200 }
201 }
202
203 #[inline]
205 pub fn as_opt_deref<U>(&self) -> Option<Option<&U>>
206 where
207 U: ?Sized,
208 T: Deref<Target = U>,
209 {
210 match self {
211 MaybeUndefined::Undefined => None,
212 MaybeUndefined::Null => Some(None),
213 MaybeUndefined::Value(value) => Some(Some(value.deref())),
214 }
215 }
216
217 #[inline]
219 pub fn contains_value<U>(&self, x: &U) -> bool
220 where
221 U: PartialEq<T>,
222 {
223 match self {
224 MaybeUndefined::Value(y) => x == y,
225 _ => false,
226 }
227 }
228
229 #[inline]
232 pub fn contains<U>(&self, x: &Option<U>) -> bool
233 where
234 U: PartialEq<T>,
235 {
236 match self {
237 MaybeUndefined::Value(y) => matches!(x, Some(v) if v == y),
238 MaybeUndefined::Null => x.is_none(),
239 MaybeUndefined::Undefined => false,
240 }
241 }
242
243 #[inline]
246 pub fn map<U, F: FnOnce(Option<T>) -> Option<U>>(self, f: F) -> MaybeUndefined<U> {
247 match self {
248 MaybeUndefined::Value(v) => match f(Some(v)) {
249 Some(v) => MaybeUndefined::Value(v),
250 None => MaybeUndefined::Null,
251 },
252 MaybeUndefined::Null => match f(None) {
253 Some(v) => MaybeUndefined::Value(v),
254 None => MaybeUndefined::Null,
255 },
256 MaybeUndefined::Undefined => MaybeUndefined::Undefined,
257 }
258 }
259
260 #[inline]
263 pub fn map_value<U, F: FnOnce(T) -> U>(self, f: F) -> MaybeUndefined<U> {
264 match self {
265 MaybeUndefined::Value(v) => MaybeUndefined::Value(f(v)),
266 MaybeUndefined::Null => MaybeUndefined::Null,
267 MaybeUndefined::Undefined => MaybeUndefined::Undefined,
268 }
269 }
270
271 pub fn update_to(self, value: &mut Option<T>) {
290 match self {
291 MaybeUndefined::Value(new) => *value = Some(new),
292 MaybeUndefined::Null => *value = None,
293 MaybeUndefined::Undefined => {}
294 };
295 }
296}
297
298impl<T: Deref> MaybeUndefined<T> {
299 #[inline]
302 pub fn as_deref(&self) -> MaybeUndefined<&T::Target> {
303 match self {
304 MaybeUndefined::Undefined => MaybeUndefined::Undefined,
305 MaybeUndefined::Null => MaybeUndefined::Null,
306 MaybeUndefined::Value(value) => MaybeUndefined::Value(value.deref()),
307 }
308 }
309}
310
311impl<T: Type> Type for MaybeUndefined<T> {
312 const IS_REQUIRED: bool = false;
313
314 type RawValueType = T::RawValueType;
315
316 type RawElementValueType = T::RawElementValueType;
317
318 fn name() -> Cow<'static, str> {
319 format!("optional_{}", T::name()).into()
320 }
321
322 fn schema_ref() -> MetaSchemaRef {
323 T::schema_ref()
324 }
325
326 fn register(registry: &mut Registry) {
327 T::register(registry);
328 }
329
330 fn as_raw_value(&self) -> Option<&Self::RawValueType> {
331 match self {
332 MaybeUndefined::Value(value) => value.as_raw_value(),
333 _ => None,
334 }
335 }
336
337 fn raw_element_iter<'a>(
338 &'a self,
339 ) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
340 match self {
341 MaybeUndefined::Value(value) => value.raw_element_iter(),
342 _ => Box::new(std::iter::empty()),
343 }
344 }
345
346 #[inline]
347 fn is_none(&self) -> bool {
348 match self {
349 MaybeUndefined::Undefined | MaybeUndefined::Null => true,
350 MaybeUndefined::Value(_) => false,
351 }
352 }
353}
354
355impl<T: ParseFromJSON> ParseFromJSON for MaybeUndefined<T> {
356 fn parse_from_json(value: Option<Value>) -> ParseResult<Self> {
357 match value {
358 Some(Value::Null) => Ok(MaybeUndefined::Null),
359 Some(value) => Ok(MaybeUndefined::Value(
360 T::parse_from_json(Some(value)).map_err(ParseError::propagate)?,
361 )),
362 None => Ok(MaybeUndefined::Undefined),
363 }
364 }
365}
366
367impl<T: ParseFromParameter> ParseFromParameter for MaybeUndefined<T> {
368 fn parse_from_parameter(_value: &str) -> ParseResult<Self> {
369 unreachable!()
370 }
371
372 fn parse_from_parameters<I: IntoIterator<Item = A>, A: AsRef<str>>(
373 iter: I,
374 ) -> ParseResult<Self> {
375 let mut iter = iter.into_iter().peekable();
376
377 if iter.peek().is_none() {
378 return Ok(MaybeUndefined::Undefined);
379 }
380
381 T::parse_from_parameters(iter)
382 .map_err(ParseError::propagate)
383 .map(MaybeUndefined::Value)
384 }
385}
386
387impl<T: ParseFromMultipartField> ParseFromMultipartField for MaybeUndefined<T> {
388 async fn parse_from_multipart(value: Option<PoemField>) -> ParseResult<Self> {
389 match value {
390 Some(value) => T::parse_from_multipart(Some(value))
391 .await
392 .map_err(ParseError::propagate)
393 .map(MaybeUndefined::Value),
394 None => Ok(MaybeUndefined::Undefined),
395 }
396 }
397}
398
399impl<T: ToJSON> ToJSON for MaybeUndefined<T> {
400 fn to_json(&self) -> Option<Value> {
401 match self {
402 MaybeUndefined::Value(value) => value.to_json(),
403 MaybeUndefined::Undefined => None,
404 MaybeUndefined::Null => Some(Value::Null),
405 }
406 }
407}
408
409impl<T: ToHeader> ToHeader for MaybeUndefined<T> {
410 fn to_header(&self) -> Option<HeaderValue> {
411 match self {
412 MaybeUndefined::Value(value) => value.to_header(),
413 _ => None,
414 }
415 }
416}
417
418impl<T, E> MaybeUndefined<Result<T, E>> {
419 #[inline]
429 pub fn transpose(self) -> Result<MaybeUndefined<T>, E> {
430 match self {
431 MaybeUndefined::Undefined => Ok(MaybeUndefined::Undefined),
432 MaybeUndefined::Null => Ok(MaybeUndefined::Null),
433 MaybeUndefined::Value(Ok(v)) => Ok(MaybeUndefined::Value(v)),
434 MaybeUndefined::Value(Err(e)) => Err(e),
435 }
436 }
437}
438
439impl<T: Serialize> Serialize for MaybeUndefined<T> {
440 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
441 match self {
442 MaybeUndefined::Value(value) => value.serialize(serializer),
443 _ => serializer.serialize_none(),
444 }
445 }
446}
447
448impl<'de, T> Deserialize<'de> for MaybeUndefined<T>
449where
450 T: Deserialize<'de>,
451{
452 fn deserialize<D>(deserializer: D) -> Result<MaybeUndefined<T>, D::Error>
453 where
454 D: Deserializer<'de>,
455 {
456 Option::<T>::deserialize(deserializer).map(|value| match value {
457 Some(value) => MaybeUndefined::Value(value),
458 None => MaybeUndefined::Null,
459 })
460 }
461}
462
463impl<T> From<MaybeUndefined<T>> for Option<Option<T>> {
464 fn from(maybe_undefined: MaybeUndefined<T>) -> Self {
465 match maybe_undefined {
466 MaybeUndefined::Undefined => None,
467 MaybeUndefined::Null => Some(None),
468 MaybeUndefined::Value(value) => Some(Some(value)),
469 }
470 }
471}
472
473impl<T> From<Option<Option<T>>> for MaybeUndefined<T> {
474 fn from(value: Option<Option<T>>) -> Self {
475 match value {
476 Some(Some(value)) => Self::Value(value),
477 Some(None) => Self::Null,
478 None => Self::Undefined,
479 }
480 }
481}
482
483#[cfg(test)]
484mod tests {
485 use serde::{Deserialize, Serialize};
486 use serde_json::json;
487
488 use super::*;
489 use crate::Object;
490
491 #[test]
492 fn test_maybe_undefined_serde() {
493 assert_eq!(
494 serde_json::to_value(MaybeUndefined::Value(100i32)).unwrap(),
495 json!(100)
496 );
497
498 assert_eq!(
499 serde_json::from_value::<MaybeUndefined<i32>>(json!(100)).unwrap(),
500 MaybeUndefined::Value(100)
501 );
502 assert_eq!(
503 serde_json::from_value::<MaybeUndefined<i32>>(json!(null)).unwrap(),
504 MaybeUndefined::Null
505 );
506
507 #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)]
508 struct A {
509 a: MaybeUndefined<i32>,
510 }
511
512 assert_eq!(
513 serde_json::to_value(&A {
514 a: MaybeUndefined::Value(100i32)
515 })
516 .unwrap(),
517 json!({"a": 100})
518 );
519
520 assert_eq!(
521 serde_json::to_value(&A {
522 a: MaybeUndefined::Null,
523 })
524 .unwrap(),
525 json!({ "a": null })
526 );
527
528 assert_eq!(
529 serde_json::to_value(&A {
530 a: MaybeUndefined::Undefined,
531 })
532 .unwrap(),
533 json!({ "a": null })
534 );
535
536 assert_eq!(
537 serde_json::from_value::<A>(json!({"a": 100})).unwrap(),
538 A {
539 a: MaybeUndefined::Value(100i32)
540 }
541 );
542
543 assert_eq!(
544 serde_json::from_value::<A>(json!({ "a": null })).unwrap(),
545 A {
546 a: MaybeUndefined::Null
547 }
548 );
549
550 assert_eq!(
551 serde_json::from_value::<A>(json!({})).unwrap(),
552 A {
553 a: MaybeUndefined::Null
554 }
555 );
556 }
557
558 #[test]
559 fn test_maybe_undefined_to_nested_option() {
560 assert_eq!(Option::<Option<i32>>::from(MaybeUndefined::Undefined), None);
561
562 assert_eq!(
563 Option::<Option<i32>>::from(MaybeUndefined::Null),
564 Some(None)
565 );
566
567 assert_eq!(
568 Option::<Option<i32>>::from(MaybeUndefined::Value(42)),
569 Some(Some(42))
570 );
571 }
572
573 #[test]
574 fn test_as_opt_ref() {
575 let mut value = MaybeUndefined::<String>::Undefined;
576 let mut r = value.as_opt_ref();
577 assert_eq!(r, None);
578
579 value = MaybeUndefined::Null;
580 r = value.as_opt_ref();
581 assert_eq!(r, Some(None));
582
583 value = MaybeUndefined::Value("abc".to_string());
584 r = value.as_opt_ref();
585 assert_eq!(r, Some(Some(&"abc".to_string())));
586 }
587
588 #[test]
589 fn test_as_opt_deref() {
590 let mut value = MaybeUndefined::<String>::Undefined;
591 let mut r = value.as_opt_deref();
592 assert_eq!(r, None);
593
594 value = MaybeUndefined::Null;
595 r = value.as_opt_deref();
596 assert_eq!(r, Some(None));
597
598 value = MaybeUndefined::Value("abc".to_string());
599 r = value.as_opt_deref();
600 assert_eq!(r, Some(Some("abc")));
601 }
602
603 #[test]
604 fn test_contains_value() {
605 let test = "abc";
606
607 let mut value: MaybeUndefined<String> = MaybeUndefined::Undefined;
608 assert!(!value.contains_value(&test));
609
610 value = MaybeUndefined::Null;
611 assert!(!value.contains_value(&test));
612
613 value = MaybeUndefined::Value("abc".to_string());
614 assert!(value.contains_value(&test));
615 }
616
617 #[test]
618 fn test_contains() {
619 let test = Some("abc");
620 let none: Option<&str> = None;
621
622 let mut value: MaybeUndefined<String> = MaybeUndefined::Undefined;
623 assert!(!value.contains(&test));
624 assert!(!value.contains(&none));
625
626 value = MaybeUndefined::Null;
627 assert!(!value.contains(&test));
628 assert!(value.contains(&none));
629
630 value = MaybeUndefined::Value("abc".to_string());
631 assert!(value.contains(&test));
632 assert!(!value.contains(&none));
633 }
634
635 #[test]
636 fn test_map_value() {
637 let mut value: MaybeUndefined<i32> = MaybeUndefined::Undefined;
638 assert_eq!(value.map_value(|v| v > 2), MaybeUndefined::Undefined);
639
640 value = MaybeUndefined::Null;
641 assert_eq!(value.map_value(|v| v > 2), MaybeUndefined::Null);
642
643 value = MaybeUndefined::Value(5);
644 assert_eq!(value.map_value(|v| v > 2), MaybeUndefined::Value(true));
645 }
646
647 #[test]
648 fn test_map() {
649 let mut value: MaybeUndefined<i32> = MaybeUndefined::Undefined;
650 assert_eq!(value.map(|v| Some(v.is_some())), MaybeUndefined::Undefined);
651
652 value = MaybeUndefined::Null;
653 assert_eq!(
654 value.map(|v| Some(v.is_some())),
655 MaybeUndefined::Value(false)
656 );
657
658 value = MaybeUndefined::Value(5);
659 assert_eq!(
660 value.map(|v| Some(v.is_some())),
661 MaybeUndefined::Value(true)
662 );
663 }
664
665 #[test]
666 fn test_transpose() {
667 let mut value: MaybeUndefined<Result<i32, &'static str>> = MaybeUndefined::Undefined;
668 assert_eq!(value.transpose(), Ok(MaybeUndefined::Undefined));
669
670 value = MaybeUndefined::Null;
671 assert_eq!(value.transpose(), Ok(MaybeUndefined::Null));
672
673 value = MaybeUndefined::Value(Ok(5));
674 assert_eq!(value.transpose(), Ok(MaybeUndefined::Value(5)));
675
676 value = MaybeUndefined::Value(Err("error"));
677 assert_eq!(value.transpose(), Err("error"));
678 }
679
680 #[test]
681 fn test_parse_from_json() {
682 assert_eq!(
683 MaybeUndefined::<i32>::parse_from_json(Some(json!(100))).unwrap(),
684 MaybeUndefined::Value(100)
685 );
686
687 assert_eq!(
688 MaybeUndefined::<i32>::parse_from_json(Some(json!(null))).unwrap(),
689 MaybeUndefined::Null
690 );
691
692 assert_eq!(
693 MaybeUndefined::<i32>::parse_from_json(None).unwrap(),
694 MaybeUndefined::Undefined
695 );
696
697 #[derive(Debug, Object, PartialEq)]
698 #[oai(internal)]
699 struct MyObj {
700 a: MaybeUndefined<i32>,
701 }
702
703 assert_eq!(
704 MyObj::parse_from_json(Some(json!({
705 "a": 100,
706 })))
707 .unwrap(),
708 MyObj {
709 a: MaybeUndefined::Value(100)
710 }
711 );
712
713 assert_eq!(
714 MyObj::parse_from_json(Some(json!({
715 "a": null,
716 })))
717 .unwrap(),
718 MyObj {
719 a: MaybeUndefined::Null
720 }
721 );
722
723 assert_eq!(
724 MyObj::parse_from_json(Some(json!({}))).unwrap(),
725 MyObj {
726 a: MaybeUndefined::Undefined
727 }
728 );
729 }
730
731 #[test]
732 fn test_to_json() {
733 assert_eq!(
734 MaybeUndefined::<i32>::Value(100).to_json(),
735 Some(json!(100))
736 );
737 assert_eq!(MaybeUndefined::<i32>::Null.to_json(), Some(json!(null)));
738 assert_eq!(MaybeUndefined::<i32>::Undefined.to_json(), None);
739
740 #[derive(Debug, Object, PartialEq)]
741 #[oai(internal)]
742 struct MyObj {
743 a: MaybeUndefined<i32>,
744 }
745
746 assert_eq!(
747 MyObj {
748 a: MaybeUndefined::Value(100)
749 }
750 .to_json(),
751 Some(json!({
752 "a": 100,
753 }))
754 );
755
756 assert_eq!(
757 MyObj {
758 a: MaybeUndefined::Null
759 }
760 .to_json(),
761 Some(json!({
762 "a": null,
763 }))
764 );
765
766 assert_eq!(
767 MyObj {
768 a: MaybeUndefined::Undefined
769 }
770 .to_json(),
771 Some(json!({}))
772 );
773 }
774}