1use std::{
16 borrow::Cow,
17 ffi::OsStr,
18 ops::Deref,
19 path::{Path, PathBuf},
20 sync::Arc,
21};
22
23use schemars::JsonSchema;
24use serde::{Deserialize, Deserializer, Serialize, Serializer};
25use serde_with::{DeserializeAs, de::DeserializeAsWrap};
26
27#[cfg(feature = "tracing")]
40#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
41#[non_exhaustive]
42pub(crate) struct SkipListener;
43
44#[cfg(feature = "tracing")]
45impl serde_with::InspectError for SkipListener {
46 fn inspect_error(error: impl serde::de::Error) {
47 tracing::warn!(
48 %error,
49 "skipped malformed list entry during deserialization",
50 );
51 }
52}
53
54#[cfg(not(feature = "tracing"))]
58pub(crate) type SkipListener = ();
59
60#[cfg(any(feature = "unstable_auth_methods", test))]
63#[derive(Deserialize)]
64#[serde(transparent)]
65struct BoolDefaultTrue(bool);
66
67#[cfg(any(feature = "unstable_auth_methods", test))]
68impl Default for BoolDefaultTrue {
69 fn default() -> Self {
70 Self(true)
71 }
72}
73
74#[cfg(any(feature = "unstable_auth_methods", test))]
76pub(crate) struct DefaultTrueOnError;
77
78#[cfg(any(feature = "unstable_auth_methods", test))]
79impl<'de> DeserializeAs<'de, bool> for DefaultTrueOnError {
80 fn deserialize_as<D>(deserializer: D) -> Result<bool, D::Error>
81 where
82 D: Deserializer<'de>,
83 {
84 <serde_with::DefaultOnError as DeserializeAs<'de, BoolDefaultTrue>>::deserialize_as(
85 deserializer,
86 )
87 .map(|value| value.0)
88 }
89}
90
91#[cfg(test)]
92mod skip_listener_tests {
93 use std::cell::Cell;
94
95 use serde::{Deserialize, Serialize};
96 use serde_json::json;
97 use serde_with::{DefaultOnError, VecSkipError, serde_as};
98
99 thread_local! {
100 static SKIP_COUNT: Cell<u32> = const { Cell::new(0) };
101 }
102
103 struct CountingListener;
105
106 impl serde_with::InspectError for CountingListener {
107 fn inspect_error(_error: impl serde::de::Error) {
108 SKIP_COUNT.with(|c| c.set(c.get() + 1));
109 }
110 }
111
112 #[serde_as]
113 #[derive(Serialize, Deserialize, Debug, PartialEq)]
114 struct Wrapper {
115 #[serde_as(deserialize_as = "VecSkipError<_, CountingListener>")]
116 values: Vec<u32>,
117 }
118
119 #[test]
120 fn inspector_runs_for_each_skipped_entry() {
121 SKIP_COUNT.with(|c| c.set(0));
122
123 let input = json!({"values": [1, "oops", 2, {}, 3]});
124 let wrapper: Wrapper = serde_json::from_value(input).unwrap();
125
126 assert_eq!(wrapper.values, vec![1, 2, 3]);
127 assert_eq!(SKIP_COUNT.with(Cell::get), 2);
128 }
129
130 #[serde_as]
135 #[derive(Deserialize, Debug, PartialEq)]
136 struct ResilientVec {
137 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, CountingListener>>")]
138 #[serde(default)]
139 values: Vec<u32>,
140 }
141
142 #[test]
143 fn resilient_vec_tolerates_missing_null_and_wrong_type() {
144 let r: ResilientVec = serde_json::from_value(json!({})).unwrap();
146 assert_eq!(r.values, Vec::<u32>::new());
147
148 let r: ResilientVec = serde_json::from_value(json!({"values": null})).unwrap();
150 assert_eq!(r.values, Vec::<u32>::new());
151
152 let r: ResilientVec = serde_json::from_value(json!({"values": "oops"})).unwrap();
154 assert_eq!(r.values, Vec::<u32>::new());
155
156 let r: ResilientVec = serde_json::from_value(json!({"values": {"k": 1}})).unwrap();
158 assert_eq!(r.values, Vec::<u32>::new());
159
160 SKIP_COUNT.with(|c| c.set(0));
162 let r: ResilientVec =
163 serde_json::from_value(json!({"values": [1, "oops", 2, {}, 3]})).unwrap();
164 assert_eq!(r.values, vec![1, 2, 3]);
165 assert_eq!(SKIP_COUNT.with(Cell::get), 2);
166 }
167
168 #[test]
169 fn resilient_vec_does_not_invoke_inspector_on_outer_failure() {
170 SKIP_COUNT.with(|c| c.set(0));
171
172 let _r: ResilientVec = serde_json::from_value(json!({"values": null})).unwrap();
175 let _r: ResilientVec = serde_json::from_value(json!({"values": "oops"})).unwrap();
176 let _r: ResilientVec = serde_json::from_value(json!({"values": {}})).unwrap();
177
178 assert_eq!(SKIP_COUNT.with(Cell::get), 0);
179 }
180
181 #[serde_as]
186 #[derive(Deserialize, Debug, PartialEq)]
187 struct ResilientOptionVec {
188 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, CountingListener>>>")]
189 #[serde(default)]
190 values: Option<Vec<u32>>,
191 }
192
193 #[test]
194 fn resilient_option_vec_tolerates_missing_null_and_wrong_type() {
195 let r: ResilientOptionVec = serde_json::from_value(json!({})).unwrap();
197 assert_eq!(r.values, None);
198
199 let r: ResilientOptionVec = serde_json::from_value(json!({"values": null})).unwrap();
201 assert_eq!(r.values, None);
202
203 let r: ResilientOptionVec = serde_json::from_value(json!({"values": []})).unwrap();
205 assert_eq!(r.values, Some(Vec::<u32>::new()));
206
207 let r: ResilientOptionVec = serde_json::from_value(json!({"values": [1, 2, 3]})).unwrap();
209 assert_eq!(r.values, Some(vec![1, 2, 3]));
210
211 let r: ResilientOptionVec = serde_json::from_value(json!({"values": "oops"})).unwrap();
213 assert_eq!(r.values, None);
214
215 let r: ResilientOptionVec = serde_json::from_value(json!({"values": {"k": 1}})).unwrap();
217 assert_eq!(r.values, None);
218
219 SKIP_COUNT.with(|c| c.set(0));
221 let r: ResilientOptionVec =
222 serde_json::from_value(json!({"values": [1, "oops", 2, {}, 3]})).unwrap();
223 assert_eq!(r.values, Some(vec![1, 2, 3]));
224 assert_eq!(SKIP_COUNT.with(Cell::get), 2);
225 }
226
227 fn default_true() -> bool {
228 true
229 }
230
231 #[serde_as]
232 #[derive(Deserialize, Debug, PartialEq)]
233 struct DefaultTrueWrapper {
234 #[serde_as(deserialize_as = "super::DefaultTrueOnError")]
235 #[serde(default = "default_true")]
236 value: bool,
237 }
238
239 #[test]
240 fn default_true_on_error_uses_true_for_missing_and_malformed_values() {
241 let wrapper: DefaultTrueWrapper = serde_json::from_value(json!({})).unwrap();
242 assert!(wrapper.value);
243
244 let wrapper: DefaultTrueWrapper = serde_json::from_value(json!({"value": false})).unwrap();
245 assert!(!wrapper.value);
246
247 let wrapper: DefaultTrueWrapper = serde_json::from_value(json!({"value": "oops"})).unwrap();
248 assert!(wrapper.value);
249 }
250}
251
252pub trait IntoOption<T> {
258 fn into_option(self) -> Option<T>;
260}
261
262impl<T> IntoOption<T> for Option<T> {
263 fn into_option(self) -> Option<T> {
264 self
265 }
266}
267
268impl<T> IntoOption<T> for T {
269 fn into_option(self) -> Option<T> {
270 Some(self)
271 }
272}
273
274impl IntoOption<String> for &str {
275 fn into_option(self) -> Option<String> {
276 Some(self.into())
277 }
278}
279
280impl IntoOption<String> for &mut str {
281 fn into_option(self) -> Option<String> {
282 Some(self.into())
283 }
284}
285
286impl IntoOption<String> for &String {
287 fn into_option(self) -> Option<String> {
288 Some(self.into())
289 }
290}
291
292impl IntoOption<String> for Box<str> {
293 fn into_option(self) -> Option<String> {
294 Some(self.into())
295 }
296}
297
298impl IntoOption<String> for Cow<'_, str> {
299 fn into_option(self) -> Option<String> {
300 Some(self.into())
301 }
302}
303
304impl IntoOption<String> for Arc<str> {
305 fn into_option(self) -> Option<String> {
306 Some(self.to_string())
307 }
308}
309
310impl<T: ?Sized + AsRef<OsStr>> IntoOption<PathBuf> for &T {
311 fn into_option(self) -> Option<PathBuf> {
312 Some(self.into())
313 }
314}
315
316impl IntoOption<PathBuf> for Box<Path> {
317 fn into_option(self) -> Option<PathBuf> {
318 Some(self.into())
319 }
320}
321
322impl IntoOption<PathBuf> for Cow<'_, Path> {
323 fn into_option(self) -> Option<PathBuf> {
324 Some(self.into())
325 }
326}
327
328impl IntoOption<serde_json::Value> for &str {
329 fn into_option(self) -> Option<serde_json::Value> {
330 Some(self.into())
331 }
332}
333
334impl IntoOption<serde_json::Value> for String {
335 fn into_option(self) -> Option<serde_json::Value> {
336 Some(self.into())
337 }
338}
339
340impl IntoOption<serde_json::Value> for Cow<'_, str> {
341 fn into_option(self) -> Option<serde_json::Value> {
342 Some(self.into())
343 }
344}
345
346#[derive(Copy, Clone, Default, PartialEq, PartialOrd, Eq, Ord, Debug, Hash, JsonSchema)]
366#[schemars(with = "Option<Option<T>>", inline)]
367#[expect(clippy::exhaustive_enums)]
368pub enum MaybeUndefined<T> {
369 #[default]
371 Undefined,
372 Null,
374 Value(T),
376}
377
378impl<T> MaybeUndefined<T> {
379 #[inline]
381 pub const fn is_undefined(&self) -> bool {
382 matches!(self, MaybeUndefined::Undefined)
383 }
384
385 #[inline]
387 pub const fn is_null(&self) -> bool {
388 matches!(self, MaybeUndefined::Null)
389 }
390
391 #[inline]
393 pub const fn is_value(&self) -> bool {
394 matches!(self, MaybeUndefined::Value(_))
395 }
396
397 #[inline]
400 pub const fn value(&self) -> Option<&T> {
401 match self {
402 MaybeUndefined::Value(value) => Some(value),
403 _ => None,
404 }
405 }
406
407 #[inline]
409 pub fn take(self) -> Option<T> {
410 match self {
411 MaybeUndefined::Value(value) => Some(value),
412 _ => None,
413 }
414 }
415
416 #[inline]
418 pub const fn as_opt_ref(&self) -> Option<Option<&T>> {
419 match self {
420 MaybeUndefined::Undefined => None,
421 MaybeUndefined::Null => Some(None),
422 MaybeUndefined::Value(value) => Some(Some(value)),
423 }
424 }
425
426 #[inline]
428 pub fn as_opt_deref<U>(&self) -> Option<Option<&U>>
429 where
430 U: ?Sized,
431 T: Deref<Target = U>,
432 {
433 match self {
434 MaybeUndefined::Undefined => None,
435 MaybeUndefined::Null => Some(None),
436 MaybeUndefined::Value(value) => Some(Some(&**value)),
437 }
438 }
439
440 #[inline]
442 pub fn contains_value<U>(&self, x: &U) -> bool
443 where
444 U: PartialEq<T>,
445 {
446 match self {
447 MaybeUndefined::Value(y) => x == y,
448 _ => false,
449 }
450 }
451
452 #[inline]
455 pub fn contains<U>(&self, x: Option<&U>) -> bool
456 where
457 U: PartialEq<T>,
458 {
459 match self {
460 MaybeUndefined::Value(y) => matches!(x, Some(v) if v == y),
461 MaybeUndefined::Null => x.is_none(),
462 MaybeUndefined::Undefined => false,
463 }
464 }
465
466 #[inline]
469 pub fn map<U, F: FnOnce(Option<T>) -> Option<U>>(self, f: F) -> MaybeUndefined<U> {
470 match self {
471 MaybeUndefined::Value(v) => match f(Some(v)) {
472 Some(v) => MaybeUndefined::Value(v),
473 None => MaybeUndefined::Null,
474 },
475 MaybeUndefined::Null => match f(None) {
476 Some(v) => MaybeUndefined::Value(v),
477 None => MaybeUndefined::Null,
478 },
479 MaybeUndefined::Undefined => MaybeUndefined::Undefined,
480 }
481 }
482
483 #[inline]
486 pub fn map_value<U, F: FnOnce(T) -> U>(self, f: F) -> MaybeUndefined<U> {
487 match self {
488 MaybeUndefined::Value(v) => MaybeUndefined::Value(f(v)),
489 MaybeUndefined::Null => MaybeUndefined::Null,
490 MaybeUndefined::Undefined => MaybeUndefined::Undefined,
491 }
492 }
493
494 pub fn update_to(self, value: &mut Option<T>) {
513 match self {
514 MaybeUndefined::Value(new) => *value = Some(new),
515 MaybeUndefined::Null => *value = None,
516 MaybeUndefined::Undefined => {}
517 }
518 }
519}
520
521impl<T, E> MaybeUndefined<Result<T, E>> {
522 #[inline]
536 pub fn transpose(self) -> Result<MaybeUndefined<T>, E> {
537 match self {
538 MaybeUndefined::Undefined => Ok(MaybeUndefined::Undefined),
539 MaybeUndefined::Null => Ok(MaybeUndefined::Null),
540 MaybeUndefined::Value(Ok(v)) => Ok(MaybeUndefined::Value(v)),
541 MaybeUndefined::Value(Err(e)) => Err(e),
542 }
543 }
544}
545
546impl<T: Serialize> Serialize for MaybeUndefined<T> {
547 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
548 match self {
549 MaybeUndefined::Value(value) => value.serialize(serializer),
550 MaybeUndefined::Null => serializer.serialize_none(),
551 MaybeUndefined::Undefined => serializer.serialize_unit(),
552 }
553 }
554}
555
556impl<'de, T> Deserialize<'de> for MaybeUndefined<T>
557where
558 T: Deserialize<'de>,
559{
560 fn deserialize<D>(deserializer: D) -> Result<MaybeUndefined<T>, D::Error>
561 where
562 D: Deserializer<'de>,
563 {
564 Option::<T>::deserialize(deserializer).map(|value| match value {
565 Some(value) => MaybeUndefined::Value(value),
566 None => MaybeUndefined::Null,
567 })
568 }
569}
570
571impl<T> From<MaybeUndefined<T>> for Option<Option<T>> {
572 fn from(maybe_undefined: MaybeUndefined<T>) -> Self {
573 match maybe_undefined {
574 MaybeUndefined::Undefined => None,
575 MaybeUndefined::Null => Some(None),
576 MaybeUndefined::Value(value) => Some(Some(value)),
577 }
578 }
579}
580
581impl<T> From<Option<Option<T>>> for MaybeUndefined<T> {
582 fn from(value: Option<Option<T>>) -> Self {
583 match value {
584 Some(Some(value)) => Self::Value(value),
585 Some(None) => Self::Null,
586 None => Self::Undefined,
587 }
588 }
589}
590
591impl<'de, T, TAs> DeserializeAs<'de, MaybeUndefined<T>> for MaybeUndefined<TAs>
592where
593 TAs: DeserializeAs<'de, T>,
594{
595 fn deserialize_as<D>(deserializer: D) -> Result<MaybeUndefined<T>, D::Error>
596 where
597 D: Deserializer<'de>,
598 {
599 Option::<DeserializeAsWrap<T, TAs>>::deserialize(deserializer).map(|value| match value {
600 Some(value) => MaybeUndefined::Value(value.into_inner()),
601 None => MaybeUndefined::Null,
602 })
603 }
604}
605
606pub trait IntoMaybeUndefined<T> {
610 fn into_maybe_undefined(self) -> MaybeUndefined<T>;
612}
613
614impl<T> IntoMaybeUndefined<T> for T {
615 fn into_maybe_undefined(self) -> MaybeUndefined<T> {
616 MaybeUndefined::Value(self)
617 }
618}
619
620impl<T> IntoMaybeUndefined<T> for Option<T> {
621 fn into_maybe_undefined(self) -> MaybeUndefined<T> {
622 match self {
623 Some(value) => MaybeUndefined::Value(value),
624 None => MaybeUndefined::Null,
625 }
626 }
627}
628
629impl<T> IntoMaybeUndefined<T> for MaybeUndefined<T> {
630 fn into_maybe_undefined(self) -> MaybeUndefined<T> {
631 self
632 }
633}
634
635impl IntoMaybeUndefined<String> for &str {
636 fn into_maybe_undefined(self) -> MaybeUndefined<String> {
637 MaybeUndefined::Value(self.into())
638 }
639}
640
641impl IntoMaybeUndefined<String> for &mut str {
642 fn into_maybe_undefined(self) -> MaybeUndefined<String> {
643 MaybeUndefined::Value(self.into())
644 }
645}
646
647impl IntoMaybeUndefined<String> for &String {
648 fn into_maybe_undefined(self) -> MaybeUndefined<String> {
649 MaybeUndefined::Value(self.into())
650 }
651}
652
653impl IntoMaybeUndefined<String> for Box<str> {
654 fn into_maybe_undefined(self) -> MaybeUndefined<String> {
655 MaybeUndefined::Value(self.into())
656 }
657}
658
659impl IntoMaybeUndefined<String> for Cow<'_, str> {
660 fn into_maybe_undefined(self) -> MaybeUndefined<String> {
661 MaybeUndefined::Value(self.into())
662 }
663}
664
665impl IntoMaybeUndefined<String> for Arc<str> {
666 fn into_maybe_undefined(self) -> MaybeUndefined<String> {
667 MaybeUndefined::Value(self.to_string())
668 }
669}
670
671impl<T: ?Sized + AsRef<OsStr>> IntoMaybeUndefined<PathBuf> for &T {
672 fn into_maybe_undefined(self) -> MaybeUndefined<PathBuf> {
673 MaybeUndefined::Value(self.into())
674 }
675}
676
677impl IntoMaybeUndefined<PathBuf> for Box<Path> {
678 fn into_maybe_undefined(self) -> MaybeUndefined<PathBuf> {
679 MaybeUndefined::Value(self.into())
680 }
681}
682
683impl IntoMaybeUndefined<PathBuf> for Cow<'_, Path> {
684 fn into_maybe_undefined(self) -> MaybeUndefined<PathBuf> {
685 MaybeUndefined::Value(self.into())
686 }
687}
688
689impl IntoMaybeUndefined<serde_json::Value> for &str {
690 fn into_maybe_undefined(self) -> MaybeUndefined<serde_json::Value> {
691 MaybeUndefined::Value(self.into())
692 }
693}
694
695impl IntoMaybeUndefined<serde_json::Value> for String {
696 fn into_maybe_undefined(self) -> MaybeUndefined<serde_json::Value> {
697 MaybeUndefined::Value(self.into())
698 }
699}
700
701impl IntoMaybeUndefined<serde_json::Value> for Cow<'_, str> {
702 fn into_maybe_undefined(self) -> MaybeUndefined<serde_json::Value> {
703 MaybeUndefined::Value(self.into())
704 }
705}
706
707#[cfg(test)]
708mod tests {
709 use serde::{Deserialize, Serialize};
710 use serde_json::{from_value, json, to_value};
711
712 use super::*;
713
714 #[test]
715 fn test_maybe_undefined_serde() {
716 #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)]
717 struct A {
718 #[serde(default, skip_serializing_if = "MaybeUndefined::is_undefined")]
719 a: MaybeUndefined<i32>,
720 }
721
722 assert_eq!(to_value(MaybeUndefined::Value(100i32)).unwrap(), json!(100));
723
724 assert_eq!(
725 from_value::<MaybeUndefined<i32>>(json!(100)).unwrap(),
726 MaybeUndefined::Value(100)
727 );
728 assert_eq!(
729 from_value::<MaybeUndefined<i32>>(json!(null)).unwrap(),
730 MaybeUndefined::Null
731 );
732
733 assert_eq!(
734 to_value(&A {
735 a: MaybeUndefined::Value(100i32)
736 })
737 .unwrap(),
738 json!({"a": 100})
739 );
740
741 assert_eq!(
742 to_value(&A {
743 a: MaybeUndefined::Null,
744 })
745 .unwrap(),
746 json!({ "a": null })
747 );
748
749 assert_eq!(
750 to_value(&A {
751 a: MaybeUndefined::Undefined,
752 })
753 .unwrap(),
754 json!({})
755 );
756
757 assert_eq!(
758 from_value::<A>(json!({"a": 100})).unwrap(),
759 A {
760 a: MaybeUndefined::Value(100i32)
761 }
762 );
763
764 assert_eq!(
765 from_value::<A>(json!({ "a": null })).unwrap(),
766 A {
767 a: MaybeUndefined::Null
768 }
769 );
770
771 assert_eq!(
772 from_value::<A>(json!({})).unwrap(),
773 A {
774 a: MaybeUndefined::Undefined
775 }
776 );
777 }
778
779 #[test]
780 fn test_maybe_undefined_to_nested_option() {
781 assert_eq!(Option::<Option<i32>>::from(MaybeUndefined::Undefined), None);
782
783 assert_eq!(
784 Option::<Option<i32>>::from(MaybeUndefined::Null),
785 Some(None)
786 );
787
788 assert_eq!(
789 Option::<Option<i32>>::from(MaybeUndefined::Value(42)),
790 Some(Some(42))
791 );
792 }
793
794 #[test]
795 fn test_as_opt_ref() {
796 let value = MaybeUndefined::<String>::Undefined;
797 let r = value.as_opt_ref();
798 assert_eq!(r, None);
799
800 let value = MaybeUndefined::<String>::Null;
801 let r = value.as_opt_ref();
802 assert_eq!(r, Some(None));
803
804 let value = MaybeUndefined::<String>::Value("abc".to_string());
805 let r = value.as_opt_ref();
806 assert_eq!(r, Some(Some(&"abc".to_string())));
807 }
808
809 #[test]
810 fn test_as_opt_deref() {
811 let value = MaybeUndefined::<String>::Undefined;
812 let r = value.as_opt_deref();
813 assert_eq!(r, None);
814
815 let value = MaybeUndefined::<String>::Null;
816 let r = value.as_opt_deref();
817 assert_eq!(r, Some(None));
818
819 let value = MaybeUndefined::<String>::Value("abc".to_string());
820 let r = value.as_opt_deref();
821 assert_eq!(r, Some(Some("abc")));
822 }
823
824 #[test]
825 fn test_contains_value() {
826 let test = "abc";
827
828 let mut value: MaybeUndefined<String> = MaybeUndefined::Undefined;
829 assert!(!value.contains_value(&test));
830
831 value = MaybeUndefined::Null;
832 assert!(!value.contains_value(&test));
833
834 value = MaybeUndefined::Value("abc".to_string());
835 assert!(value.contains_value(&test));
836 }
837
838 #[test]
839 fn test_contains() {
840 let test = Some("abc");
841 let none: Option<&str> = None;
842
843 let mut value: MaybeUndefined<String> = MaybeUndefined::Undefined;
844 assert!(!value.contains(test.as_ref()));
845 assert!(!value.contains(none.as_ref()));
846
847 value = MaybeUndefined::Null;
848 assert!(!value.contains(test.as_ref()));
849 assert!(value.contains(none.as_ref()));
850
851 value = MaybeUndefined::Value("abc".to_string());
852 assert!(value.contains(test.as_ref()));
853 assert!(!value.contains(none.as_ref()));
854 }
855
856 #[test]
857 fn test_map_value() {
858 let mut value: MaybeUndefined<i32> = MaybeUndefined::Undefined;
859 assert_eq!(value.map_value(|v| v > 2), MaybeUndefined::Undefined);
860
861 value = MaybeUndefined::Null;
862 assert_eq!(value.map_value(|v| v > 2), MaybeUndefined::Null);
863
864 value = MaybeUndefined::Value(5);
865 assert_eq!(value.map_value(|v| v > 2), MaybeUndefined::Value(true));
866 }
867
868 #[test]
869 fn test_map() {
870 let mut value: MaybeUndefined<i32> = MaybeUndefined::Undefined;
871 assert_eq!(value.map(|v| Some(v.is_some())), MaybeUndefined::Undefined);
872
873 value = MaybeUndefined::Null;
874 assert_eq!(
875 value.map(|v| Some(v.is_some())),
876 MaybeUndefined::Value(false)
877 );
878
879 value = MaybeUndefined::Value(5);
880 assert_eq!(
881 value.map(|v| Some(v.is_some())),
882 MaybeUndefined::Value(true)
883 );
884 }
885
886 #[test]
887 fn test_transpose() {
888 let mut value: MaybeUndefined<Result<i32, &'static str>> = MaybeUndefined::Undefined;
889 assert_eq!(value.transpose(), Ok(MaybeUndefined::Undefined));
890
891 value = MaybeUndefined::Null;
892 assert_eq!(value.transpose(), Ok(MaybeUndefined::Null));
893
894 value = MaybeUndefined::Value(Ok(5));
895 assert_eq!(value.transpose(), Ok(MaybeUndefined::Value(5)));
896
897 value = MaybeUndefined::Value(Err("error"));
898 assert_eq!(value.transpose(), Err("error"));
899 }
900}