1use std::{
17 borrow::Cow,
18 ffi::OsStr,
19 ops::Deref,
20 path::{Path, PathBuf},
21 sync::Arc,
22};
23
24use schemars::JsonSchema;
25use serde::{Deserialize, Deserializer, Serialize, Serializer};
26
27#[cfg(feature = "tracing")]
40#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
41#[non_exhaustive]
42pub 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 type SkipListener = ();
59
60#[cfg(test)]
61mod skip_listener_tests {
62 use std::cell::Cell;
63
64 use serde::{Deserialize, Serialize};
65 use serde_json::json;
66 use serde_with::{DefaultOnError, VecSkipError, serde_as};
67
68 thread_local! {
69 static SKIP_COUNT: Cell<u32> = const { Cell::new(0) };
70 }
71
72 struct CountingListener;
74
75 impl serde_with::InspectError for CountingListener {
76 fn inspect_error(_error: impl serde::de::Error) {
77 SKIP_COUNT.with(|c| c.set(c.get() + 1));
78 }
79 }
80
81 #[serde_as]
82 #[derive(Serialize, Deserialize, Debug, PartialEq)]
83 struct Wrapper {
84 #[serde_as(deserialize_as = "VecSkipError<_, CountingListener>")]
85 values: Vec<u32>,
86 }
87
88 #[test]
89 fn inspector_runs_for_each_skipped_entry() {
90 SKIP_COUNT.with(|c| c.set(0));
91
92 let input = json!({"values": [1, "oops", 2, {}, 3]});
93 let wrapper: Wrapper = serde_json::from_value(input).unwrap();
94
95 assert_eq!(wrapper.values, vec![1, 2, 3]);
96 assert_eq!(SKIP_COUNT.with(Cell::get), 2);
97 }
98
99 #[serde_as]
104 #[derive(Deserialize, Debug, PartialEq)]
105 struct ResilientVec {
106 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, CountingListener>>")]
107 #[serde(default)]
108 values: Vec<u32>,
109 }
110
111 #[test]
112 fn resilient_vec_tolerates_missing_null_and_wrong_type() {
113 let r: ResilientVec = serde_json::from_value(json!({})).unwrap();
115 assert_eq!(r.values, Vec::<u32>::new());
116
117 let r: ResilientVec = serde_json::from_value(json!({"values": null})).unwrap();
119 assert_eq!(r.values, Vec::<u32>::new());
120
121 let r: ResilientVec = serde_json::from_value(json!({"values": "oops"})).unwrap();
123 assert_eq!(r.values, Vec::<u32>::new());
124
125 let r: ResilientVec = serde_json::from_value(json!({"values": {"k": 1}})).unwrap();
127 assert_eq!(r.values, Vec::<u32>::new());
128
129 SKIP_COUNT.with(|c| c.set(0));
131 let r: ResilientVec =
132 serde_json::from_value(json!({"values": [1, "oops", 2, {}, 3]})).unwrap();
133 assert_eq!(r.values, vec![1, 2, 3]);
134 assert_eq!(SKIP_COUNT.with(Cell::get), 2);
135 }
136
137 #[test]
138 fn resilient_vec_does_not_invoke_inspector_on_outer_failure() {
139 SKIP_COUNT.with(|c| c.set(0));
140
141 let _r: ResilientVec = serde_json::from_value(json!({"values": null})).unwrap();
144 let _r: ResilientVec = serde_json::from_value(json!({"values": "oops"})).unwrap();
145 let _r: ResilientVec = serde_json::from_value(json!({"values": {}})).unwrap();
146
147 assert_eq!(SKIP_COUNT.with(Cell::get), 0);
148 }
149
150 #[serde_as]
155 #[derive(Deserialize, Debug, PartialEq)]
156 struct ResilientOptionVec {
157 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, CountingListener>>>")]
158 #[serde(default)]
159 values: Option<Vec<u32>>,
160 }
161
162 #[test]
163 fn resilient_option_vec_tolerates_missing_null_and_wrong_type() {
164 let r: ResilientOptionVec = serde_json::from_value(json!({})).unwrap();
166 assert_eq!(r.values, None);
167
168 let r: ResilientOptionVec = serde_json::from_value(json!({"values": null})).unwrap();
170 assert_eq!(r.values, None);
171
172 let r: ResilientOptionVec = serde_json::from_value(json!({"values": []})).unwrap();
174 assert_eq!(r.values, Some(Vec::<u32>::new()));
175
176 let r: ResilientOptionVec = serde_json::from_value(json!({"values": [1, 2, 3]})).unwrap();
178 assert_eq!(r.values, Some(vec![1, 2, 3]));
179
180 let r: ResilientOptionVec = serde_json::from_value(json!({"values": "oops"})).unwrap();
182 assert_eq!(r.values, None);
183
184 let r: ResilientOptionVec = serde_json::from_value(json!({"values": {"k": 1}})).unwrap();
186 assert_eq!(r.values, None);
187
188 SKIP_COUNT.with(|c| c.set(0));
190 let r: ResilientOptionVec =
191 serde_json::from_value(json!({"values": [1, "oops", 2, {}, 3]})).unwrap();
192 assert_eq!(r.values, Some(vec![1, 2, 3]));
193 assert_eq!(SKIP_COUNT.with(Cell::get), 2);
194 }
195}
196
197pub trait IntoOption<T> {
203 fn into_option(self) -> Option<T>;
204}
205
206impl<T> IntoOption<T> for Option<T> {
207 fn into_option(self) -> Option<T> {
208 self
209 }
210}
211
212impl<T> IntoOption<T> for T {
213 fn into_option(self) -> Option<T> {
214 Some(self)
215 }
216}
217
218impl IntoOption<String> for &str {
219 fn into_option(self) -> Option<String> {
220 Some(self.into())
221 }
222}
223
224impl IntoOption<String> for &mut str {
225 fn into_option(self) -> Option<String> {
226 Some(self.into())
227 }
228}
229
230impl IntoOption<String> for &String {
231 fn into_option(self) -> Option<String> {
232 Some(self.into())
233 }
234}
235
236impl IntoOption<String> for Box<str> {
237 fn into_option(self) -> Option<String> {
238 Some(self.into())
239 }
240}
241
242impl IntoOption<String> for Cow<'_, str> {
243 fn into_option(self) -> Option<String> {
244 Some(self.into())
245 }
246}
247
248impl IntoOption<String> for Arc<str> {
249 fn into_option(self) -> Option<String> {
250 Some(self.to_string())
251 }
252}
253
254impl<T: ?Sized + AsRef<OsStr>> IntoOption<PathBuf> for &T {
255 fn into_option(self) -> Option<PathBuf> {
256 Some(self.into())
257 }
258}
259
260impl IntoOption<PathBuf> for Box<Path> {
261 fn into_option(self) -> Option<PathBuf> {
262 Some(self.into())
263 }
264}
265
266impl IntoOption<PathBuf> for Cow<'_, Path> {
267 fn into_option(self) -> Option<PathBuf> {
268 Some(self.into())
269 }
270}
271
272impl IntoOption<serde_json::Value> for &str {
273 fn into_option(self) -> Option<serde_json::Value> {
274 Some(self.into())
275 }
276}
277
278impl IntoOption<serde_json::Value> for String {
279 fn into_option(self) -> Option<serde_json::Value> {
280 Some(self.into())
281 }
282}
283
284impl IntoOption<serde_json::Value> for Cow<'_, str> {
285 fn into_option(self) -> Option<serde_json::Value> {
286 Some(self.into())
287 }
288}
289
290#[allow(missing_docs)]
310#[derive(Copy, Clone, Default, PartialEq, PartialOrd, Eq, Ord, Debug, Hash, JsonSchema)]
311#[schemars(with = "Option<Option<T>>", inline)]
312#[expect(clippy::exhaustive_enums)]
313pub enum MaybeUndefined<T> {
314 #[default]
315 Undefined,
316 Null,
317 Value(T),
318}
319
320impl<T> MaybeUndefined<T> {
321 #[inline]
323 pub const fn is_undefined(&self) -> bool {
324 matches!(self, MaybeUndefined::Undefined)
325 }
326
327 #[inline]
329 pub const fn is_null(&self) -> bool {
330 matches!(self, MaybeUndefined::Null)
331 }
332
333 #[inline]
335 pub const fn is_value(&self) -> bool {
336 matches!(self, MaybeUndefined::Value(_))
337 }
338
339 #[inline]
342 pub const fn value(&self) -> Option<&T> {
343 match self {
344 MaybeUndefined::Value(value) => Some(value),
345 _ => None,
346 }
347 }
348
349 #[inline]
351 pub fn take(self) -> Option<T> {
352 match self {
353 MaybeUndefined::Value(value) => Some(value),
354 _ => None,
355 }
356 }
357
358 #[inline]
360 pub const fn as_opt_ref(&self) -> Option<Option<&T>> {
361 match self {
362 MaybeUndefined::Undefined => None,
363 MaybeUndefined::Null => Some(None),
364 MaybeUndefined::Value(value) => Some(Some(value)),
365 }
366 }
367
368 #[inline]
370 pub fn as_opt_deref<U>(&self) -> Option<Option<&U>>
371 where
372 U: ?Sized,
373 T: Deref<Target = U>,
374 {
375 match self {
376 MaybeUndefined::Undefined => None,
377 MaybeUndefined::Null => Some(None),
378 MaybeUndefined::Value(value) => Some(Some(&**value)),
379 }
380 }
381
382 #[inline]
384 pub fn contains_value<U>(&self, x: &U) -> bool
385 where
386 U: PartialEq<T>,
387 {
388 match self {
389 MaybeUndefined::Value(y) => x == y,
390 _ => false,
391 }
392 }
393
394 #[inline]
397 pub fn contains<U>(&self, x: Option<&U>) -> bool
398 where
399 U: PartialEq<T>,
400 {
401 match self {
402 MaybeUndefined::Value(y) => matches!(x, Some(v) if v == y),
403 MaybeUndefined::Null => x.is_none(),
404 MaybeUndefined::Undefined => false,
405 }
406 }
407
408 #[inline]
411 pub fn map<U, F: FnOnce(Option<T>) -> Option<U>>(self, f: F) -> MaybeUndefined<U> {
412 match self {
413 MaybeUndefined::Value(v) => match f(Some(v)) {
414 Some(v) => MaybeUndefined::Value(v),
415 None => MaybeUndefined::Null,
416 },
417 MaybeUndefined::Null => match f(None) {
418 Some(v) => MaybeUndefined::Value(v),
419 None => MaybeUndefined::Null,
420 },
421 MaybeUndefined::Undefined => MaybeUndefined::Undefined,
422 }
423 }
424
425 #[inline]
428 pub fn map_value<U, F: FnOnce(T) -> U>(self, f: F) -> MaybeUndefined<U> {
429 match self {
430 MaybeUndefined::Value(v) => MaybeUndefined::Value(f(v)),
431 MaybeUndefined::Null => MaybeUndefined::Null,
432 MaybeUndefined::Undefined => MaybeUndefined::Undefined,
433 }
434 }
435
436 pub fn update_to(self, value: &mut Option<T>) {
455 match self {
456 MaybeUndefined::Value(new) => *value = Some(new),
457 MaybeUndefined::Null => *value = None,
458 MaybeUndefined::Undefined => {}
459 }
460 }
461}
462
463impl<T, E> MaybeUndefined<Result<T, E>> {
464 #[inline]
478 pub fn transpose(self) -> Result<MaybeUndefined<T>, E> {
479 match self {
480 MaybeUndefined::Undefined => Ok(MaybeUndefined::Undefined),
481 MaybeUndefined::Null => Ok(MaybeUndefined::Null),
482 MaybeUndefined::Value(Ok(v)) => Ok(MaybeUndefined::Value(v)),
483 MaybeUndefined::Value(Err(e)) => Err(e),
484 }
485 }
486}
487
488impl<T: Serialize> Serialize for MaybeUndefined<T> {
489 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
490 match self {
491 MaybeUndefined::Value(value) => value.serialize(serializer),
492 MaybeUndefined::Null => serializer.serialize_none(),
493 MaybeUndefined::Undefined => serializer.serialize_unit(),
494 }
495 }
496}
497
498impl<'de, T> Deserialize<'de> for MaybeUndefined<T>
499where
500 T: Deserialize<'de>,
501{
502 fn deserialize<D>(deserializer: D) -> Result<MaybeUndefined<T>, D::Error>
503 where
504 D: Deserializer<'de>,
505 {
506 Option::<T>::deserialize(deserializer).map(|value| match value {
507 Some(value) => MaybeUndefined::Value(value),
508 None => MaybeUndefined::Null,
509 })
510 }
511}
512
513impl<T> From<MaybeUndefined<T>> for Option<Option<T>> {
514 fn from(maybe_undefined: MaybeUndefined<T>) -> Self {
515 match maybe_undefined {
516 MaybeUndefined::Undefined => None,
517 MaybeUndefined::Null => Some(None),
518 MaybeUndefined::Value(value) => Some(Some(value)),
519 }
520 }
521}
522
523impl<T> From<Option<Option<T>>> for MaybeUndefined<T> {
524 fn from(value: Option<Option<T>>) -> Self {
525 match value {
526 Some(Some(value)) => Self::Value(value),
527 Some(None) => Self::Null,
528 None => Self::Undefined,
529 }
530 }
531}
532
533pub trait IntoMaybeUndefined<T> {
537 fn into_maybe_undefined(self) -> MaybeUndefined<T>;
538}
539
540impl<T> IntoMaybeUndefined<T> for T {
541 fn into_maybe_undefined(self) -> MaybeUndefined<T> {
542 MaybeUndefined::Value(self)
543 }
544}
545
546impl<T> IntoMaybeUndefined<T> for Option<T> {
547 fn into_maybe_undefined(self) -> MaybeUndefined<T> {
548 match self {
549 Some(value) => MaybeUndefined::Value(value),
550 None => MaybeUndefined::Null,
551 }
552 }
553}
554
555impl<T> IntoMaybeUndefined<T> for MaybeUndefined<T> {
556 fn into_maybe_undefined(self) -> MaybeUndefined<T> {
557 self
558 }
559}
560
561impl IntoMaybeUndefined<String> for &str {
562 fn into_maybe_undefined(self) -> MaybeUndefined<String> {
563 MaybeUndefined::Value(self.into())
564 }
565}
566
567impl IntoMaybeUndefined<String> for &mut str {
568 fn into_maybe_undefined(self) -> MaybeUndefined<String> {
569 MaybeUndefined::Value(self.into())
570 }
571}
572
573impl IntoMaybeUndefined<String> for &String {
574 fn into_maybe_undefined(self) -> MaybeUndefined<String> {
575 MaybeUndefined::Value(self.into())
576 }
577}
578
579impl IntoMaybeUndefined<String> for Box<str> {
580 fn into_maybe_undefined(self) -> MaybeUndefined<String> {
581 MaybeUndefined::Value(self.into())
582 }
583}
584
585impl IntoMaybeUndefined<String> for Cow<'_, str> {
586 fn into_maybe_undefined(self) -> MaybeUndefined<String> {
587 MaybeUndefined::Value(self.into())
588 }
589}
590
591impl IntoMaybeUndefined<String> for Arc<str> {
592 fn into_maybe_undefined(self) -> MaybeUndefined<String> {
593 MaybeUndefined::Value(self.to_string())
594 }
595}
596
597impl<T: ?Sized + AsRef<OsStr>> IntoMaybeUndefined<PathBuf> for &T {
598 fn into_maybe_undefined(self) -> MaybeUndefined<PathBuf> {
599 MaybeUndefined::Value(self.into())
600 }
601}
602
603impl IntoMaybeUndefined<PathBuf> for Box<Path> {
604 fn into_maybe_undefined(self) -> MaybeUndefined<PathBuf> {
605 MaybeUndefined::Value(self.into())
606 }
607}
608
609impl IntoMaybeUndefined<PathBuf> for Cow<'_, Path> {
610 fn into_maybe_undefined(self) -> MaybeUndefined<PathBuf> {
611 MaybeUndefined::Value(self.into())
612 }
613}
614
615impl IntoMaybeUndefined<serde_json::Value> for &str {
616 fn into_maybe_undefined(self) -> MaybeUndefined<serde_json::Value> {
617 MaybeUndefined::Value(self.into())
618 }
619}
620
621impl IntoMaybeUndefined<serde_json::Value> for String {
622 fn into_maybe_undefined(self) -> MaybeUndefined<serde_json::Value> {
623 MaybeUndefined::Value(self.into())
624 }
625}
626
627impl IntoMaybeUndefined<serde_json::Value> for Cow<'_, str> {
628 fn into_maybe_undefined(self) -> MaybeUndefined<serde_json::Value> {
629 MaybeUndefined::Value(self.into())
630 }
631}
632
633#[cfg(feature = "unstable_llm_providers")]
672#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, JsonSchema)]
673#[schemars(with = "Option<T>", inline)]
674#[non_exhaustive]
675pub struct RequiredNullable<T>(pub Option<T>);
676
677#[cfg(feature = "unstable_llm_providers")]
678impl<T> Default for RequiredNullable<T> {
679 fn default() -> Self {
680 Self(None)
681 }
682}
683
684#[cfg(feature = "unstable_llm_providers")]
685impl<T: Serialize> Serialize for RequiredNullable<T> {
686 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
687 self.0.serialize(serializer)
688 }
689}
690
691#[cfg(feature = "unstable_llm_providers")]
692impl<'de, T: Deserialize<'de>> Deserialize<'de> for RequiredNullable<T> {
693 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
694 let value = serde_json::Value::deserialize(deserializer)?;
698 if value.is_null() {
699 Ok(RequiredNullable(None))
700 } else {
701 T::deserialize(value)
702 .map(RequiredNullable::new)
703 .map_err(serde::de::Error::custom)
704 }
705 }
706}
707
708#[cfg(feature = "unstable_llm_providers")]
709impl<T> RequiredNullable<T> {
710 #[must_use]
712 pub fn new(value: T) -> Self {
713 Self(Some(value))
714 }
715
716 #[must_use]
718 pub fn null() -> Self {
719 Self(None)
720 }
721
722 #[must_use]
724 pub fn is_null(&self) -> bool {
725 self.0.is_none()
726 }
727
728 #[must_use]
730 pub fn is_value(&self) -> bool {
731 self.0.is_some()
732 }
733
734 #[must_use]
736 pub fn value(&self) -> Option<&T> {
737 self.0.as_ref()
738 }
739
740 #[must_use]
742 pub fn value_mut(&mut self) -> Option<&mut T> {
743 self.0.as_mut()
744 }
745
746 #[must_use]
748 pub fn into_inner(self) -> Option<T> {
749 self.0
750 }
751}
752
753#[cfg(feature = "unstable_llm_providers")]
754impl<T> From<Option<T>> for RequiredNullable<T> {
755 fn from(value: Option<T>) -> Self {
756 Self(value)
757 }
758}
759
760#[cfg(feature = "unstable_llm_providers")]
761impl<T> From<RequiredNullable<T>> for Option<T> {
762 fn from(value: RequiredNullable<T>) -> Self {
763 value.0
764 }
765}
766
767#[cfg(test)]
768mod tests {
769 use serde::{Deserialize, Serialize};
770 use serde_json::{from_value, json, to_value};
771
772 use super::*;
773
774 #[test]
775 fn test_maybe_undefined_serde() {
776 #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)]
777 struct A {
778 #[serde(default, skip_serializing_if = "MaybeUndefined::is_undefined")]
779 a: MaybeUndefined<i32>,
780 }
781
782 assert_eq!(to_value(MaybeUndefined::Value(100i32)).unwrap(), json!(100));
783
784 assert_eq!(
785 from_value::<MaybeUndefined<i32>>(json!(100)).unwrap(),
786 MaybeUndefined::Value(100)
787 );
788 assert_eq!(
789 from_value::<MaybeUndefined<i32>>(json!(null)).unwrap(),
790 MaybeUndefined::Null
791 );
792
793 assert_eq!(
794 to_value(&A {
795 a: MaybeUndefined::Value(100i32)
796 })
797 .unwrap(),
798 json!({"a": 100})
799 );
800
801 assert_eq!(
802 to_value(&A {
803 a: MaybeUndefined::Null,
804 })
805 .unwrap(),
806 json!({ "a": null })
807 );
808
809 assert_eq!(
810 to_value(&A {
811 a: MaybeUndefined::Undefined,
812 })
813 .unwrap(),
814 json!({})
815 );
816
817 assert_eq!(
818 from_value::<A>(json!({"a": 100})).unwrap(),
819 A {
820 a: MaybeUndefined::Value(100i32)
821 }
822 );
823
824 assert_eq!(
825 from_value::<A>(json!({ "a": null })).unwrap(),
826 A {
827 a: MaybeUndefined::Null
828 }
829 );
830
831 assert_eq!(
832 from_value::<A>(json!({})).unwrap(),
833 A {
834 a: MaybeUndefined::Undefined
835 }
836 );
837 }
838
839 #[test]
840 fn test_maybe_undefined_to_nested_option() {
841 assert_eq!(Option::<Option<i32>>::from(MaybeUndefined::Undefined), None);
842
843 assert_eq!(
844 Option::<Option<i32>>::from(MaybeUndefined::Null),
845 Some(None)
846 );
847
848 assert_eq!(
849 Option::<Option<i32>>::from(MaybeUndefined::Value(42)),
850 Some(Some(42))
851 );
852 }
853
854 #[test]
855 fn test_as_opt_ref() {
856 let value = MaybeUndefined::<String>::Undefined;
857 let r = value.as_opt_ref();
858 assert_eq!(r, None);
859
860 let value = MaybeUndefined::<String>::Null;
861 let r = value.as_opt_ref();
862 assert_eq!(r, Some(None));
863
864 let value = MaybeUndefined::<String>::Value("abc".to_string());
865 let r = value.as_opt_ref();
866 assert_eq!(r, Some(Some(&"abc".to_string())));
867 }
868
869 #[test]
870 fn test_as_opt_deref() {
871 let value = MaybeUndefined::<String>::Undefined;
872 let r = value.as_opt_deref();
873 assert_eq!(r, None);
874
875 let value = MaybeUndefined::<String>::Null;
876 let r = value.as_opt_deref();
877 assert_eq!(r, Some(None));
878
879 let value = MaybeUndefined::<String>::Value("abc".to_string());
880 let r = value.as_opt_deref();
881 assert_eq!(r, Some(Some("abc")));
882 }
883
884 #[test]
885 fn test_contains_value() {
886 let test = "abc";
887
888 let mut value: MaybeUndefined<String> = MaybeUndefined::Undefined;
889 assert!(!value.contains_value(&test));
890
891 value = MaybeUndefined::Null;
892 assert!(!value.contains_value(&test));
893
894 value = MaybeUndefined::Value("abc".to_string());
895 assert!(value.contains_value(&test));
896 }
897
898 #[test]
899 fn test_contains() {
900 let test = Some("abc");
901 let none: Option<&str> = None;
902
903 let mut value: MaybeUndefined<String> = MaybeUndefined::Undefined;
904 assert!(!value.contains(test.as_ref()));
905 assert!(!value.contains(none.as_ref()));
906
907 value = MaybeUndefined::Null;
908 assert!(!value.contains(test.as_ref()));
909 assert!(value.contains(none.as_ref()));
910
911 value = MaybeUndefined::Value("abc".to_string());
912 assert!(value.contains(test.as_ref()));
913 assert!(!value.contains(none.as_ref()));
914 }
915
916 #[test]
917 fn test_map_value() {
918 let mut value: MaybeUndefined<i32> = MaybeUndefined::Undefined;
919 assert_eq!(value.map_value(|v| v > 2), MaybeUndefined::Undefined);
920
921 value = MaybeUndefined::Null;
922 assert_eq!(value.map_value(|v| v > 2), MaybeUndefined::Null);
923
924 value = MaybeUndefined::Value(5);
925 assert_eq!(value.map_value(|v| v > 2), MaybeUndefined::Value(true));
926 }
927
928 #[test]
929 fn test_map() {
930 let mut value: MaybeUndefined<i32> = MaybeUndefined::Undefined;
931 assert_eq!(value.map(|v| Some(v.is_some())), MaybeUndefined::Undefined);
932
933 value = MaybeUndefined::Null;
934 assert_eq!(
935 value.map(|v| Some(v.is_some())),
936 MaybeUndefined::Value(false)
937 );
938
939 value = MaybeUndefined::Value(5);
940 assert_eq!(
941 value.map(|v| Some(v.is_some())),
942 MaybeUndefined::Value(true)
943 );
944 }
945
946 #[test]
947 fn test_transpose() {
948 let mut value: MaybeUndefined<Result<i32, &'static str>> = MaybeUndefined::Undefined;
949 assert_eq!(value.transpose(), Ok(MaybeUndefined::Undefined));
950
951 value = MaybeUndefined::Null;
952 assert_eq!(value.transpose(), Ok(MaybeUndefined::Null));
953
954 value = MaybeUndefined::Value(Ok(5));
955 assert_eq!(value.transpose(), Ok(MaybeUndefined::Value(5)));
956
957 value = MaybeUndefined::Value(Err("error"));
958 assert_eq!(value.transpose(), Err("error"));
959 }
960
961 #[cfg(feature = "unstable_llm_providers")]
964 mod nullable_tests {
965 use super::*;
966 use serde_json::from_str;
967
968 #[derive(Serialize, Deserialize, Debug, PartialEq)]
969 struct Example {
970 value: RequiredNullable<String>,
971 }
972
973 #[test]
974 fn present_with_value() {
975 let example: Example = from_str(r#"{"value":"hello"}"#).unwrap();
976 assert_eq!(example.value, RequiredNullable(Some("hello".to_string())));
977 }
978
979 #[test]
980 fn present_as_null() {
981 let example: Example = from_str(r#"{"value":null}"#).unwrap();
982 assert_eq!(example.value, RequiredNullable(None));
983 }
984
985 #[test]
986 fn missing_key_fails() {
987 assert!(from_str::<Example>(r"{}").is_err());
988 }
989
990 #[test]
991 fn serialize_value() {
992 let example = Example {
993 value: RequiredNullable(Some("hello".to_string())),
994 };
995 assert_eq!(to_value(&example).unwrap(), json!({"value": "hello"}));
996 }
997
998 #[test]
999 fn serialize_null() {
1000 let example = Example {
1001 value: RequiredNullable(None),
1002 };
1003 assert_eq!(to_value(&example).unwrap(), json!({"value": null}));
1004 }
1005
1006 #[test]
1007 fn from_option() {
1008 let nullable: RequiredNullable<i32> = Some(42).into();
1009 assert_eq!(nullable, RequiredNullable(Some(42)));
1010
1011 let nullable: RequiredNullable<i32> = None.into();
1012 assert_eq!(nullable, RequiredNullable(None));
1013 }
1014
1015 #[test]
1016 fn into_option() {
1017 let option: Option<i32> = RequiredNullable(Some(42)).into();
1018 assert_eq!(option, Some(42));
1019
1020 let option: Option<i32> = RequiredNullable(None).into();
1021 assert_eq!(option, None);
1022 }
1023
1024 #[test]
1025 fn methods() {
1026 let value = RequiredNullable::new(42);
1027 assert!(value.is_value());
1028 assert!(!value.is_null());
1029 assert_eq!(value.value(), Some(&42));
1030 assert_eq!(value.into_inner(), Some(42));
1031
1032 let null: RequiredNullable<i32> = RequiredNullable::null();
1033 assert!(!null.is_value());
1034 assert!(null.is_null());
1035 assert_eq!(null.value(), None);
1036 assert_eq!(null.into_inner(), None);
1037 }
1038
1039 #[test]
1040 fn default_is_null() {
1041 let nullable: RequiredNullable<i32> = RequiredNullable::default();
1042 assert_eq!(nullable, RequiredNullable(None));
1043 }
1044 }
1045}