aorist_extendr_api/wrapper/nullable.rs
1use super::*;
2
3/// Wrapper for handling potentially NULL values.
4/// ```
5/// use extendr_api::prelude::*;
6/// test! {
7/// use extendr_api::wrapper::Nullable::*;
8///
9/// // Plain integer.
10/// let s1 = r!(1);
11/// let n1 = <Nullable<i32>>::from_robj(&s1)?;
12/// assert_eq!(n1, NotNull(1));
13///
14/// // NA integer - error.
15/// let sna = r!(NA_INTEGER);
16/// assert_eq!(<Nullable<i32>>::from_robj(&sna).is_err(), true);
17///
18/// // NA integer - option gives none.
19/// assert_eq!(<Nullable<Option<i32>>>::from_robj(&sna)?, NotNull(None));
20///
21/// // NULL object.
22/// let snull = r!(NULL);
23/// let nnull = <Nullable<i32>>::from_robj(&snull)?;
24/// assert_eq!(nnull, Null);
25///
26/// assert_eq!(r!(Nullable::<i32>::Null), r!(NULL));
27/// assert_eq!(r!(Nullable::<i32>::NotNull(1)), r!(1));
28/// }
29/// ```
30#[derive(Debug, PartialEq, Clone)]
31pub enum Nullable<T> {
32 NotNull(T),
33 Null,
34}
35
36impl<'a, T> FromRobj<'a> for Nullable<T>
37where
38 T: FromRobj<'a>,
39{
40 /// Convert an object that may be null to a rust type.
41 /// ```
42 /// use extendr_api::prelude::*;
43 /// test! {
44 /// let s1 = r!(1);
45 /// let n1 = <Nullable<i32>>::from_robj(&s1)?;
46 /// assert_eq!(n1, Nullable::NotNull(1));
47 /// let snull = r!(NULL);
48 /// let nnull = <Nullable<i32>>::from_robj(&snull)?;
49 /// assert_eq!(nnull, Nullable::Null);
50 /// }
51 /// ```
52 fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
53 if robj.is_null() {
54 Ok(Nullable::Null)
55 } else {
56 Ok(Nullable::NotNull(<T>::from_robj(robj)?))
57 }
58 }
59}
60
61impl<T> From<Nullable<T>> for Robj
62where
63 T: Into<Robj>,
64{
65 /// Convert a rust object to NULL or another type.
66 /// ```
67 /// use extendr_api::prelude::*;
68 /// test! {
69 /// assert_eq!(r!(Nullable::<i32>::Null), r!(NULL));
70 /// assert_eq!(r!(Nullable::<i32>::NotNull(1)), r!(1));
71 /// }
72 /// ```
73 fn from(val: Nullable<T>) -> Self {
74 match val {
75 Nullable::NotNull(t) => t.into(),
76 Nullable::Null => r!(NULL),
77 }
78 }
79}