use extendr_ffi::{R_IsNA, R_NaReal, Rcomplex};
use once_cell::sync::Lazy;
use std::alloc::{self, Layout};
static EXTENDR_NA_STRING: Lazy<&'static str> = Lazy::new(|| unsafe {
let layout = Layout::array::<u8>(2).unwrap();
let ptr = alloc::alloc(layout);
let v: &mut [u8] = std::slice::from_raw_parts_mut(ptr, 2);
v[0] = b'N';
v[1] = b'A';
std::str::from_utf8_unchecked(v)
});
pub trait CanBeNA {
fn is_na(&self) -> bool;
fn na() -> Self;
}
impl CanBeNA for f64 {
fn is_na(&self) -> bool {
unsafe { R_IsNA(*self) != 0 }
}
fn na() -> f64 {
unsafe { R_NaReal }
}
}
impl CanBeNA for i32 {
fn is_na(&self) -> bool {
*self == i32::na()
}
fn na() -> i32 {
i32::MIN
}
}
impl CanBeNA for &str {
fn is_na(&self) -> bool {
self.as_ptr() == <&str>::na().as_ptr()
}
fn na() -> Self {
&EXTENDR_NA_STRING
}
}
impl CanBeNA for u8 {
fn is_na(&self) -> bool {
false
}
fn na() -> Self {
0
}
}
impl CanBeNA for Rcomplex {
fn is_na(&self) -> bool {
unsafe { R_IsNA(self.r) != 0 || R_IsNA(self.i) != 0 }
}
fn na() -> Self {
unsafe {
Rcomplex {
r: R_NaReal,
i: R_NaReal,
}
}
}
}