Skip to main content

miniextendr_api/
nullable.rs

1//! [`Nullable<T>`]: an optional return whose `None` is `NULL` in R.
2//!
3//! An `Option<T>` return converts through `Option<T>`'s own [`IntoR`]: `None`
4//! is `NULL` for a vector, list or class, but `NA` for a scalar
5//! (`Option<i32>` gives `NA_integer_`), because R stores a missing scalar as
6//! `NA`. Where `None` means that there is no value at all, whatever `T` is,
7//! return `Nullable<T>`: `Some(v)` converts as `v` does, and `None` is `NULL`.
8//! [`RIterator`] uses it for the end of iteration, which an `NA` item would be
9//! indistinguishable from.
10//!
11//! ```ignore
12//! use miniextendr_api::{miniextendr, Nullable};
13//!
14//! #[miniextendr]
15//! pub fn first_even(xs: Vec<i32>) -> Nullable<i32> {
16//!     Nullable(xs.into_iter().find(|x| x % 2 == 0))
17//! }
18//! // R: first_even(c(1L, 4L)) → 4L
19//! //    first_even(c(1L, 3L)) → NULL  (an `Option<i32>` return gives NA_integer_)
20//! ```
21//!
22//! `Nullable<T>` is a return type only; an optional argument is `Option<T>`,
23//! which already reads `NULL` as `None`.
24
25use crate::SEXP;
26use crate::into_r::IntoR;
27
28/// An optional return value that R receives as `NULL` when `None`, whatever
29/// `T` is. See the [module docs](self).
30#[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug> ::core::fmt::Debug for Nullable<T> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Nullable",
            &&self.0)
    }
}Debug, #[automatically_derived]
impl<T: ::core::clone::Clone> ::core::clone::Clone for Nullable<T> {
    #[inline]
    fn clone(&self) -> Self { Nullable(::core::clone::Clone::clone(&self.0)) }
}Clone, #[automatically_derived]
impl<T: ::core::marker::Copy> ::core::marker::Copy for Nullable<T> { }Copy, #[automatically_derived]
impl<T: ::core::cmp::PartialEq> ::core::marker::StructuralPartialEq for
    Nullable<T> {
}
#[automatically_derived]
impl<T: ::core::cmp::PartialEq> ::core::cmp::PartialEq for Nullable<T> {
    #[inline]
    fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl<T: ::core::cmp::Eq> ::core::cmp::Eq for Nullable<T> {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Option<T>>;
    }
}Eq, #[automatically_derived]
impl<T: ::core::cmp::PartialOrd> ::core::cmp::PartialOrd for Nullable<T> {
    #[inline]
    fn partial_cmp(&self, other: &Self)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
    }
}PartialOrd, #[automatically_derived]
impl<T: ::core::cmp::Ord> ::core::cmp::Ord for Nullable<T> {
    #[inline]
    fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
        ::core::cmp::Ord::cmp(&self.0, &other.0)
    }
}Ord, #[automatically_derived]
impl<T: ::core::hash::Hash> ::core::hash::Hash for Nullable<T> {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.0, state)
    }
}Hash, #[automatically_derived]
impl<T: ::core::default::Default> ::core::default::Default for Nullable<T> {
    #[inline]
    fn default() -> Self { Nullable(::core::default::Default::default()) }
}Default)]
31pub struct Nullable<T>(pub Option<T>);
32
33impl<T> From<Option<T>> for Nullable<T> {
34    #[inline]
35    fn from(value: Option<T>) -> Self {
36        Self(value)
37    }
38}
39
40impl<T: IntoR> IntoR for Nullable<T> {
41    type Error = T::Error;
42    #[inline]
43    fn try_into_sexp(self) -> Result<SEXP, Self::Error> {
44        match self.0 {
45            Some(v) => v.try_into_sexp(),
46            None => Ok(SEXP::nil()),
47        }
48    }
49    #[inline]
50    unsafe fn try_into_sexp_unchecked(self) -> Result<SEXP, Self::Error> {
51        match self.0 {
52            Some(v) => unsafe { v.try_into_sexp_unchecked() },
53            None => Ok(SEXP::nil()),
54        }
55    }
56    #[inline]
57    fn into_sexp(self) -> SEXP {
58        match self.0 {
59            Some(v) => v.into_sexp(),
60            None => SEXP::nil(),
61        }
62    }
63    #[inline]
64    unsafe fn into_sexp_unchecked(self) -> SEXP {
65        match self.0 {
66            Some(v) => unsafe { v.into_sexp_unchecked() },
67            None => SEXP::nil(),
68        }
69    }
70}