#![allow(dead_code)]
use crate::rbindings::*;
use std::convert::{TryFrom, TryInto};
use std::ffi::CStr;
use std::num::TryFromIntError;
use std::os::raw::{c_char, c_void};
#[derive(Copy, Clone)]
#[repr(C)]
pub struct Rval(pub SEXP);
pub fn random_bytes<const LENGTH: usize>() -> [u8; LENGTH] {
unsafe {
let m = (u8::MAX as f64) + 1.0;
let mut bytes: [u8; LENGTH] = [0; LENGTH];
GetRNGstate();
for x in bytes.iter_mut() {
*x = R_unif_index(m) as u8;
}
PutRNGstate();
bytes
}
}
#[doc(hidden)]
pub fn _print(x: &str, use_stdout: bool) -> bool {
struct DummyFat {
len: usize,
ptr: *const c_char,
use_stdout: bool,
}
let mut y = DummyFat {
len: x.len(),
ptr: x.as_ptr() as *const c_char,
use_stdout,
};
let y_ptr = &mut y as *mut DummyFat as *mut c_void;
extern "C" fn print_fn(y_ptr: *mut c_void) {
unsafe {
let y_ptr = y_ptr as *mut DummyFat;
if (*y_ptr).use_stdout {
Rprintf(
b"%.*s\0".as_ptr() as *const c_char,
(*y_ptr).len,
(*y_ptr).ptr,
);
} else {
REprintf(
b"%.*s\0".as_ptr() as *const c_char,
(*y_ptr).len,
(*y_ptr).ptr,
);
}
}
}
unsafe { R_ToplevelExec(Some(print_fn), y_ptr) == 0 }
}
#[macro_export]
macro_rules! rprint {
($fmt_string:expr) => {
r::_print(format!($fmt_string).as_str(), true)
};
($fmt_string:expr, $( $arg:expr ),* ) => {
r::_print(format!($fmt_string, $($arg),*).as_str(), true)
}
}
#[macro_export]
macro_rules! rprintln {
() => {
r::_print("\n", true)
};
($fmt_string:expr) => {
r::_print(format!(concat!($fmt_string,"\n")).as_str(), true)
};
($fmt_string:expr, $( $arg:expr ),* ) => {
r::_print(format!(concat!($fmt_string,"\n"), $($arg),*).as_str(), true)
}
}
#[macro_export]
macro_rules! reprint {
($fmt_string:expr) => {
r::_print(format!($fmt_string).as_str(), false)
};
($fmt_string:expr, $( $arg:expr ),* ) => {
r::_print(format!($fmt_string, $($arg),*).as_str(), false)
}
}
#[macro_export]
macro_rules! reprintln {
() => {
r::_print("\n", false)
};
($fmt_string:expr) => {
r::_print(format!(concat!($fmt_string,"\n")).as_str(), false)
};
($fmt_string:expr, $( $arg:expr ),* ) => {
r::_print(format!(concat!($fmt_string,"\n"), $($arg),*).as_str(), false)
}
}
pub fn flush_console() {
unsafe { R_FlushConsole() };
}
pub fn check_user_interrupt() -> bool {
extern "C" fn check_interrupt_fn(_: *mut c_void) {
unsafe { R_CheckUserInterrupt() };
}
unsafe { R_ToplevelExec(Some(check_interrupt_fn), std::ptr::null_mut()) == 0 }
}
impl Rval {
fn new_vector<T>(
len: usize,
code: u32,
get_ptr: impl Fn(SEXP) -> *mut T,
pc: &mut Pc,
) -> (Rval, &'static mut [T]) {
unsafe {
let sexp = pc.protect(Rf_allocVector(code, len.try_into().unwrap()));
let slice = std::slice::from_raw_parts_mut(get_ptr(sexp), len);
(Rval(sexp), slice)
}
}
fn new_matrix<T>(
nrow: usize,
ncol: usize,
code: u32,
get_ptr: impl Fn(SEXP) -> *mut T,
pc: &mut Pc,
) -> (Rval, &'static mut [T]) {
unsafe {
let sexp = pc.protect(Rf_allocMatrix(
code,
nrow.try_into().unwrap(),
ncol.try_into().unwrap(),
));
let slice = std::slice::from_raw_parts_mut(get_ptr(sexp), nrow * ncol);
(Rval(sexp), slice)
}
}
pub fn new_vector_double(len: usize, pc: &mut Pc) -> (Self, &'static mut [f64]) {
Self::new_vector(len, REALSXP, |x| unsafe { REAL(x) }, pc)
}
pub fn new_vector_integer(len: usize, pc: &mut Pc) -> (Self, &'static mut [i32]) {
Self::new_vector(len, INTSXP, |x| unsafe { INTEGER(x) }, pc)
}
pub fn new_vector_logical(len: usize, pc: &mut Pc) -> (Self, &'static mut [i32]) {
Self::new_vector(len, LGLSXP, |x| unsafe { LOGICAL(x) }, pc)
}
pub fn new_vector_character(len: usize, pc: &mut Pc) -> Self {
Self(pc.protect(unsafe { Rf_allocVector(STRSXP, len.try_into().unwrap()) }))
}
pub fn new_vector_raw(len: usize, pc: &mut Pc) -> (Self, &'static mut [u8]) {
Self::new_vector(len, RAWSXP, |x| unsafe { RAW(x) }, pc)
}
pub fn new_matrix_double(nrow: usize, ncol: usize, pc: &mut Pc) -> (Self, &'static mut [f64]) {
Self::new_matrix(nrow, ncol, REALSXP, |x| unsafe { REAL(x) }, pc)
}
pub fn new_matrix_integer(nrow: usize, ncol: usize, pc: &mut Pc) -> (Self, &'static mut [i32]) {
Self::new_matrix(nrow, ncol, INTSXP, |x| unsafe { INTEGER(x) }, pc)
}
pub fn new_matrix_logical(nrow: usize, ncol: usize, pc: &mut Pc) -> (Self, &'static mut [i32]) {
Self::new_matrix(nrow, ncol, LGLSXP, |x| unsafe { LOGICAL(x) }, pc)
}
pub fn new_matrix_character(nrow: usize, ncol: usize, pc: &mut Pc) -> Self {
unsafe {
let sexp = pc.protect(Rf_allocMatrix(
STRSXP,
nrow.try_into().unwrap(),
ncol.try_into().unwrap(),
));
Self(sexp)
}
}
pub fn new_list(len: usize, pc: &mut Pc) -> Self {
Self(pc.protect(unsafe { Rf_allocVector(VECSXP, len.try_into().unwrap()) }))
}
pub fn new_error(message: &str, pc: &mut Pc) -> Self {
let list = Self::new_list(2, pc);
list.set_list_element(0, Self::new(message, pc));
list.set_list_element(1, Self::nil());
list.names_gets(Self::new(["message", "calls"], pc));
list.class_gets(Self::new(["error", "condition"], pc));
list
}
pub fn new_character(x: &str, pc: &mut Pc) -> Self {
Self(pc.protect(unsafe {
Rf_mkCharLen(x.as_ptr() as *const c_char, x.len().try_into().unwrap())
}))
}
pub fn new_symbol(x: &str, pc: &mut Pc) -> Self {
let sexp = Self::new_character(x, pc).0;
Self(pc.protect(unsafe { Rf_installChar(sexp) }))
}
pub fn duplicate(self, pc: &mut Pc) -> Self {
Self(pc.protect(unsafe { Rf_duplicate(self.0) }))
}
pub fn external_pointer_encode<T>(x: T, tag: Self) -> Self {
unsafe {
let ptr = Box::into_raw(Box::new(x)) as *mut c_void;
Self(R_MakeExternalPtr(ptr, tag.0, R_NilValue))
}
}
pub fn external_pointer_tag(self) -> Self {
unsafe { Rval(R_ExternalPtrTag(self.0)) }
}
pub fn external_pointer_decode<T>(self) -> T {
unsafe {
let ptr = R_ExternalPtrAddr(self.0) as *mut T;
*Box::from_raw(ptr)
}
}
pub fn external_pointer_decode_as_ref<T>(self) -> &'static T {
unsafe {
let ptr = R_ExternalPtrAddr(self.0) as *mut T;
ptr.as_ref().unwrap()
}
}
pub fn external_pointer_decode_as_mut_ref<T>(self) -> &'static mut T {
unsafe {
let ptr = R_ExternalPtrAddr(self.0) as *mut T;
ptr.as_mut().unwrap()
}
}
pub fn nil() -> Self {
Self(unsafe { R_NilValue })
}
pub fn infinity_positive() -> f64 {
unsafe { R_PosInf }
}
pub fn infinity_negative() -> f64 {
unsafe { R_NegInf }
}
pub fn nan() -> f64 {
unsafe { R_NaN }
}
pub fn na_double() -> f64 {
unsafe { R_NaReal }
}
pub fn na_integer() -> i32 {
unsafe { R_NaInt }
}
pub fn na_logical() -> i32 {
unsafe { R_NaInt }
}
pub fn na_character() -> Self {
Self(unsafe { R_NaString })
}
pub fn is_finite(x: f64) -> bool {
unsafe { R_finite(x) != 0 }
}
pub fn is_nan(x: f64) -> bool {
unsafe { R_IsNaN(x) != 0 }
}
pub fn is_na_double(x: f64) -> bool {
unsafe { R_IsNA(x) != 0 }
}
pub fn is_na_integer(x: i32) -> bool {
unsafe { x == R_NaInt }
}
pub fn is_na_logical(x: i32) -> bool {
unsafe { x == R_NaInt }
}
pub fn is_na_character(self) -> bool {
unsafe { self.0 == R_NaString }
}
pub fn is_double(self) -> bool {
unsafe { Rf_isReal(self.0) != 0 }
}
pub fn is_integer(self) -> bool {
unsafe { Rf_isInteger(self.0) != 0 }
}
pub fn is_double_or_integer(self) -> bool {
self.is_double() || self.is_integer()
}
pub fn is_double_or_integer_scalar(self) -> bool {
self.is_double_or_integer() && self.len() == 1
}
pub fn is_logical(self) -> bool {
unsafe { Rf_isLogical(self.0) != 0 }
}
pub fn is_raw(self) -> bool {
unsafe { TYPEOF(self.0) == RAWSXP.try_into().unwrap() }
}
pub fn is_symbol(self) -> bool {
unsafe { TYPEOF(self.0) == SYMSXP.try_into().unwrap() }
}
pub fn is_character_element(self) -> bool {
unsafe { TYPEOF(self.0) == CHARSXP.try_into().unwrap() }
}
pub fn is_character(self) -> bool {
unsafe { Rf_isString(self.0) != 0 }
}
pub fn is_list(self) -> bool {
unsafe { TYPEOF(self.0) == VECSXP.try_into().unwrap() }
}
pub fn is_vector_atomic(self) -> bool {
unsafe { Rf_isVectorAtomic(self.0) != 0 }
}
pub fn is_vector(self) -> bool {
unsafe { Rf_isVector(self.0) != 0 }
}
pub fn is_scalar(self) -> bool {
self.len() == 1
}
pub fn is_matrix(self) -> bool {
unsafe { Rf_isMatrix(self.0) != 0 }
}
pub fn is_square_matrix(self) -> bool {
self.is_matrix() && self.nrow() == self.ncol()
}
pub fn is_array(self) -> bool {
unsafe { Rf_isArray(self.0) != 0 }
}
pub fn is_data_frame(self) -> bool {
unsafe { Rf_isFrame(self.0) != 0 }
}
pub fn is_nil(self) -> bool {
unsafe { Rf_isNull(self.0) != 0 }
}
pub fn is_function(self) -> bool {
unsafe { Rf_isFunction(self.0) != 0 }
}
pub fn is_environment(self) -> bool {
unsafe { Rf_isEnvironment(self.0) != 0 }
}
pub fn is_true(self) -> bool {
unsafe { Rf_asLogical(self.0) == Rboolean_TRUE.try_into().unwrap() }
}
pub fn is_false(self) -> bool {
unsafe { Rf_asLogical(self.0) == Rboolean_FALSE.try_into().unwrap() }
}
pub fn get_character_element(self, i: usize) -> Self {
if !self.is_character() {
panic!("Not of storage mode `character`");
}
let len = self.len();
if i >= len {
panic!("Index {} is out of bounds for vector of length {}", i, len);
}
Self(unsafe { STRING_ELT(self.0, i.try_into().unwrap()) })
}
pub fn set_character_element(self, i: usize, value: &str, pc: &mut Pc) {
if !self.is_character() {
panic!("Not of storage mode `character`");
}
let len = self.len();
if i >= len {
panic!("Index {} is out of bounds for vector of length {}", i, len);
}
unsafe {
SET_STRING_ELT(
self.0,
i.try_into().unwrap(),
Self::new_character(value, pc).0,
);
}
}
pub fn get_list_element(self, i: usize) -> Self {
if !self.is_list() {
panic!("Not a list");
}
let len = self.len();
if i >= len {
panic!("Index {} is out of bounds for list of length {}", i, len);
}
Self(unsafe { VECTOR_ELT(self.0, i.try_into().unwrap()) })
}
pub fn set_list_element(self, i: usize, value: Self) {
if !self.is_list() {
panic!("Not a list");
}
let len = self.len();
if i >= len {
panic!("Index {} is out of bounds for list of length {}", i, len);
}
unsafe {
SET_VECTOR_ELT(self.0, i.try_into().unwrap(), value.0);
}
}
pub fn get_attribute(self, which: &str, pc: &mut Pc) -> Self {
Self(unsafe { Rf_getAttrib(self.0, Self::new_symbol(which, pc).0) })
}
pub fn set_attribute(self, which: &str, value: Self, pc: &mut Pc) {
unsafe {
Rf_setAttrib(self.0, Self::new_symbol(which, pc).0, value.0);
}
}
pub fn assign(self, value: Self, environment: Self) {
if !self.is_symbol() {
panic!("Not a symbol")
}
unsafe { Rf_defineVar(self.0, value.0, environment.0) };
}
pub fn assign_inherits(self, value: Self, environment: Self) {
if !self.is_symbol() {
panic!("Not a symbol")
}
unsafe { Rf_setVar(self.0, value.0, environment.0) };
}
pub fn names_gets(self, names: Self) {
if !self.is_vector() {
panic!("Not a vector")
}
if names.len() != self.len() {
panic!("'names' is not the same length as vector")
}
unsafe { Rf_namesgets(self.0, names.0) };
}
pub fn class_gets(self, value: Self) {
if !value.is_character() {
panic!("'value' is not a character vector")
}
unsafe { Rf_classgets(self.0, value.0) };
}
pub fn len(self) -> usize {
unsafe { Rf_length(self.0).try_into().unwrap() }
}
pub fn is_empty(self) -> bool {
unsafe { Rf_length(self.0) == 0 }
}
pub fn as_f64(self) -> f64 {
unsafe { Rf_asReal(self.0) }
}
pub fn as_i32(self) -> i32 {
unsafe { Rf_asInteger(self.0) }
}
pub fn as_bool(self) -> bool {
unsafe { Rf_asLogical(self.0) == Rboolean_TRUE.try_into().unwrap() }
}
pub fn as_usize(self) -> usize {
let len = unsafe { Rf_asInteger(self.0) };
len.try_into().unwrap_or(0)
}
pub fn as_string(self) -> String {
let c_str = unsafe { CStr::from_ptr(R_CHAR(Rf_asChar(self.0)) as *const c_char) };
match c_str.to_str() {
Ok(x) => x.to_string(),
Err(_) => "".to_string(),
}
}
pub fn as_str(self) -> &'static str {
let c_str = unsafe { CStr::from_ptr(R_CHAR(Rf_asChar(self.0)) as *const c_char) };
match c_str.to_str() {
Ok(x) => x,
Err(_) => "",
}
}
pub fn nrow(self) -> usize {
if !self.is_matrix() {
panic!("Not a matrix");
}
unsafe { Rf_nrows(self.0).try_into().unwrap() }
}
pub fn ncol(self) -> usize {
if !self.is_matrix() {
panic!("Not a matrix");
}
unsafe { Rf_ncols(self.0).try_into().unwrap() }
}
pub fn transpose(self, pc: &mut Pc) -> Self {
if !self.is_matrix() {
panic!("Not a matrix");
}
unsafe {
let sexp = pc.protect(Rf_allocMatrix(
TYPEOF(self.0).try_into().unwrap(),
Rf_ncols(self.0),
Rf_nrows(self.0),
));
Rf_copyMatrix(sexp, self.0, 1);
Self(sexp)
}
}
fn slice<T>(
rval: Self,
code: u32,
get_ptr: impl Fn(SEXP) -> *mut T,
) -> Result<&'static [T], &'static str> {
let ft = unsafe { TYPEOF(rval.0) } as u32;
if ft == code {
let len = rval.len();
let slice = unsafe { std::slice::from_raw_parts(get_ptr(rval.0), len) };
Ok(slice)
} else {
Err("Object is not of the asserted type")
}
}
pub fn slice_double(self) -> Result<&'static [f64], &'static str> {
Self::slice(self, REALSXP, |x| unsafe { REAL(x) })
}
pub fn slice_integer(self) -> Result<&'static [i32], &'static str> {
Self::slice(self, INTSXP, |x| unsafe { INTEGER(x) })
}
pub fn slice_logical(self) -> Result<&'static [i32], &'static str> {
Self::slice(self, LGLSXP, |x| unsafe { LOGICAL(x) })
}
pub fn slice_raw(self) -> Result<&'static [u8], &'static str> {
Self::slice(self, RAWSXP, |x| unsafe { RAW(x) })
}
fn slice_mut<T>(
rval: Self,
code: u32,
get_ptr: impl Fn(SEXP) -> *mut T,
) -> Result<&'static mut [T], &'static str> {
let ft = unsafe { TYPEOF(rval.0) } as u32;
if ft == code {
let len = rval.len();
let slice = unsafe { std::slice::from_raw_parts_mut(get_ptr(rval.0), len) };
Ok(slice)
} else {
Err("Object is not of the asserted type")
}
}
pub fn slice_mut_double(self) -> Result<&'static mut [f64], &'static str> {
Self::slice_mut(self, REALSXP, |x| unsafe { REAL(x) })
}
pub fn slice_mut_integer(self) -> Result<&'static mut [i32], &'static str> {
Self::slice_mut(self, INTSXP, |x| unsafe { INTEGER(x) })
}
pub fn slice_mut_logical(self) -> Result<&'static mut [i32], &'static str> {
Self::slice_mut(self, LGLSXP, |x| unsafe { LOGICAL(x) })
}
pub fn slice_mut_raw(self) -> Result<&'static mut [u8], &'static str> {
Self::slice_mut(self, RAWSXP, |x| unsafe { RAW(x) })
}
fn coerce<T>(
rval: Self,
code: u32,
get_ptr: impl Fn(SEXP) -> *mut T,
pc: &mut Pc,
) -> Result<(Self, &'static mut [T]), &'static str> {
let ft = unsafe { TYPEOF(rval.0) } as u32;
if ft == REALSXP || ft == INTSXP || ft == LGLSXP || ft == STRSXP || ft == NILSXP {
let rval = if ft != code {
let sexp = pc.protect(unsafe { Rf_coerceVector(rval.0, code) });
Self(sexp)
} else {
rval
};
let len = rval.len();
let slice = unsafe { std::slice::from_raw_parts_mut(get_ptr(rval.0), len) };
Ok((rval, slice))
} else {
Err("Object is not of the asserted type")
}
}
pub fn coerce_double(self, pc: &mut Pc) -> Result<(Self, &'static mut [f64]), &'static str> {
Self::coerce(self, REALSXP, |x| unsafe { REAL(x) }, pc)
}
pub fn coerce_integer(self, pc: &mut Pc) -> Result<(Self, &'static mut [i32]), &'static str> {
Self::coerce(self, INTSXP, |x| unsafe { INTEGER(x) }, pc)
}
pub fn coerce_logical(self, pc: &mut Pc) -> Result<(Self, &'static mut [i32]), &'static str> {
Self::coerce(self, LGLSXP, |x| unsafe { LOGICAL(x) }, pc)
}
pub fn coerce_raw(self, pc: &mut Pc) -> Result<(Self, &'static mut [u8]), &'static str> {
Self::coerce(self, RAWSXP, |x| unsafe { RAW(x) }, pc)
}
pub fn coerce_character(self, pc: &mut Pc) -> Result<Self, &'static str> {
let ft = unsafe { TYPEOF(self.0) } as u32;
if ft == REALSXP || ft == INTSXP || ft == LGLSXP || ft == STRSXP || ft == NILSXP {
let rval = if ft != STRSXP {
let sexp = pc.protect(unsafe { Rf_coerceVector(self.0, STRSXP) });
Self(sexp)
} else {
self
};
Ok(rval)
} else {
Err("object is not of the asserted type")
}
}
pub unsafe fn call0_unsafe(self, pc: &mut Pc) -> Self {
let sexp = pc.protect(Rf_lang1(self.0));
let sexp = pc.protect(Rf_eval(sexp, R_GetCurrentEnv()));
Self(sexp)
}
pub unsafe fn call1_unsafe(self, x1: Self, pc: &mut Pc) -> Self {
let sexp = pc.protect(Rf_lang2(self.0, x1.0));
let sexp = pc.protect(Rf_eval(sexp, R_GetCurrentEnv()));
Self(sexp)
}
pub unsafe fn call2_unsafe(self, x1: Self, x2: Self, pc: &mut Pc) -> Self {
let sexp = pc.protect(Rf_lang3(self.0, x1.0, x2.0));
let sexp = pc.protect(Rf_eval(sexp, R_GetCurrentEnv()));
Self(sexp)
}
pub unsafe fn call3_unsafe(self, x1: Self, x2: Self, x3: Self, pc: &mut Pc) -> Self {
let sexp = pc.protect(Rf_lang4(self.0, x1.0, x2.0, x3.0));
let sexp = pc.protect(Rf_eval(sexp, R_GetCurrentEnv()));
Self(sexp)
}
pub unsafe fn call4_unsafe(self, x1: Self, x2: Self, x3: Self, x4: Self, pc: &mut Pc) -> Self {
let sexp = pc.protect(Rf_lang5(self.0, x1.0, x2.0, x3.0, x4.0));
let sexp = pc.protect(Rf_eval(sexp, R_GetCurrentEnv()));
Self(sexp)
}
pub unsafe fn call5_unsafe(
self,
x1: Self,
x2: Self,
x3: Self,
x4: Self,
x5: Self,
pc: &mut Pc,
) -> Self {
let sexp = pc.protect(Rf_lang6(self.0, x1.0, x2.0, x3.0, x4.0, x5.0));
let sexp = pc.protect(Rf_eval(sexp, R_GetCurrentEnv()));
Self(sexp)
}
pub fn eval(self, environment: Self, pc: &mut Pc) -> Result<Self, i32> {
let mut p_out_error: i32 = 0;
let sexp = unsafe { R_tryEval(self.0, environment.0, &mut p_out_error as *mut i32) };
match p_out_error {
0 => Ok(Self(pc.protect(sexp))),
e => Err(e),
}
}
pub fn call0(self, pc: &mut Pc) -> Result<Self, i32> {
unsafe {
let sexp = pc.protect(Rf_lang1(self.0));
Self(sexp).eval(Self(R_GetCurrentEnv()), pc)
}
}
pub fn call1(self, x1: Self, pc: &mut Pc) -> Result<Self, i32> {
unsafe {
let sexp = pc.protect(Rf_lang2(self.0, x1.0));
Self(sexp).eval(Self(R_GetCurrentEnv()), pc)
}
}
pub fn call2(self, x1: Self, x2: Self, pc: &mut Pc) -> Result<Self, i32> {
unsafe {
let sexp = pc.protect(Rf_lang3(self.0, x1.0, x2.0));
Self(sexp).eval(Self(R_GetCurrentEnv()), pc)
}
}
pub fn call3(self, x1: Self, x2: Self, x3: Self, pc: &mut Pc) -> Result<Self, i32> {
unsafe {
let sexp = pc.protect(Rf_lang4(self.0, x1.0, x2.0, x3.0));
Self(sexp).eval(Self(R_GetCurrentEnv()), pc)
}
}
pub fn call4(self, x1: Self, x2: Self, x3: Self, x4: Self, pc: &mut Pc) -> Result<Self, i32> {
unsafe {
let sexp = pc.protect(Rf_lang5(self.0, x1.0, x2.0, x3.0, x4.0));
Self(sexp).eval(Self(R_GetCurrentEnv()), pc)
}
}
pub fn call5(
self,
x1: Self,
x2: Self,
x3: Self,
x4: Self,
x5: Self,
pc: &mut Pc,
) -> Result<Self, i32> {
unsafe {
let sexp = pc.protect(Rf_lang6(self.0, x1.0, x2.0, x3.0, x4.0, x5.0));
Self(sexp).eval(Self(R_GetCurrentEnv()), pc)
}
}
}
pub trait NewProtected<T> {
fn new(_: T, _: &mut Pc) -> Self;
}
pub trait TryNewProtected<T>: Sized {
type Error;
fn try_new(_: T, _: &mut Pc) -> Result<Self, Self::Error>;
}
impl From<Rval> for f64 {
fn from(x: Rval) -> f64 {
unsafe { Rf_asReal(x.0) }
}
}
impl NewProtected<f64> for Rval {
fn new(x: f64, pc: &mut Pc) -> Self {
Self(pc.protect(unsafe { Rf_ScalarReal(x) }))
}
}
impl From<Rval> for i32 {
fn from(x: Rval) -> i32 {
unsafe { Rf_asInteger(x.0) }
}
}
impl NewProtected<i32> for Rval {
fn new(x: i32, pc: &mut Pc) -> Self {
Self(pc.protect(unsafe { Rf_ScalarInteger(x) }))
}
}
impl TryFrom<Rval> for bool {
type Error = &'static str;
fn try_from(x: Rval) -> Result<bool, Self::Error> {
match unsafe { Rf_asLogical(x.0) } {
x if x == Rboolean_TRUE.try_into().unwrap() => Ok(true),
x if x == Rboolean_FALSE.try_into().unwrap() => Ok(false),
_ => Err("Logical value is NA"),
}
}
}
impl NewProtected<bool> for Rval {
fn new(x: bool, pc: &mut Pc) -> Self {
Rval(pc.protect(unsafe { Rf_ScalarLogical(x.into()) }))
}
}
impl TryFrom<Rval> for usize {
type Error = TryFromIntError;
fn try_from(x: Rval) -> Result<usize, Self::Error> {
usize::try_from(i32::from(x))
}
}
impl TryNewProtected<usize> for Rval {
type Error = TryFromIntError;
fn try_new(x: usize, pc: &mut Pc) -> Result<Self, Self::Error> {
match i32::try_from(x) {
Ok(z) => Ok(Rval::new(z, pc)),
Err(e) => Err(e),
}
}
}
impl TryFrom<Rval> for &[f64] {
type Error = &'static str;
fn try_from(x: Rval) -> Result<&'static [f64], &'static str> {
x.slice_double()
}
}
impl TryFrom<Rval> for &mut [f64] {
type Error = &'static str;
fn try_from(x: Rval) -> Result<&'static mut [f64], &'static str> {
x.slice_mut_double()
}
}
impl NewProtected<&[f64]> for Rval {
fn new(x: &[f64], pc: &mut Pc) -> Self {
let (rval, slice) = Rval::new_vector_double(x.len(), pc);
slice.copy_from_slice(x);
rval
}
}
impl NewProtected<&mut [f64]> for Rval {
fn new(x: &mut [f64], pc: &mut Pc) -> Self {
let (rval, slice) = Rval::new_vector_double(x.len(), pc);
slice.copy_from_slice(x);
rval
}
}
impl TryFrom<Rval> for &[i32] {
type Error = &'static str;
fn try_from(x: Rval) -> Result<&'static [i32], &'static str> {
x.slice_integer()
}
}
impl TryFrom<Rval> for &mut [i32] {
type Error = &'static str;
fn try_from(x: Rval) -> Result<&'static mut [i32], &'static str> {
x.slice_mut_integer()
}
}
impl NewProtected<&[i32]> for Rval {
fn new(x: &[i32], pc: &mut Pc) -> Self {
let (rval, slice) = Rval::new_vector_integer(x.len(), pc);
slice.copy_from_slice(x);
rval
}
}
impl NewProtected<&mut [i32]> for Rval {
fn new(x: &mut [i32], pc: &mut Pc) -> Self {
let (rval, slice) = Rval::new_vector_integer(x.len(), pc);
slice.copy_from_slice(x);
rval
}
}
impl TryNewProtected<&[usize]> for Rval {
type Error = TryFromIntError;
fn try_new(x: &[usize], pc: &mut Pc) -> Result<Self, Self::Error> {
let (rval, slice) = Rval::new_vector_integer(x.len(), pc);
for (r, s) in slice.iter_mut().zip(x) {
match i32::try_from(*s) {
Ok(z) => *r = z,
Err(e) => return Err(e),
}
}
Ok(rval)
}
}
impl TryNewProtected<&mut [usize]> for Rval {
type Error = TryFromIntError;
fn try_new(x: &mut [usize], pc: &mut Pc) -> Result<Self, Self::Error> {
let (rval, slice) = Rval::new_vector_integer(x.len(), pc);
for (r, s) in slice.iter_mut().zip(x) {
match i32::try_from(*s) {
Ok(z) => *r = z,
Err(e) => return Err(e),
}
}
Ok(rval)
}
}
impl TryFrom<Rval> for &[u8] {
type Error = &'static str;
fn try_from(x: Rval) -> Result<&'static [u8], &'static str> {
x.slice_raw()
}
}
impl TryFrom<Rval> for &mut [u8] {
type Error = &'static str;
fn try_from(x: Rval) -> Result<&'static mut [u8], &'static str> {
x.slice_mut_raw()
}
}
impl NewProtected<&[u8]> for Rval {
fn new(x: &[u8], pc: &mut Pc) -> Rval {
let (rval, slice) = Rval::new_vector_raw(x.len(), pc);
slice.copy_from_slice(x);
rval
}
}
impl NewProtected<&mut [u8]> for Rval {
fn new(x: &mut [u8], pc: &mut Pc) -> Rval {
let (rval, slice) = Rval::new_vector_raw(x.len(), pc);
slice.copy_from_slice(x);
rval
}
}
impl<const N: usize> NewProtected<[f64; N]> for Rval {
fn new(x: [f64; N], pc: &mut Pc) -> Self {
Self::new(&x[..], pc)
}
}
impl<const N: usize> NewProtected<[i32; N]> for Rval {
fn new(x: [i32; N], pc: &mut Pc) -> Self {
Self::new(&x[..], pc)
}
}
impl<const N: usize> NewProtected<[u8; N]> for Rval {
fn new(x: [u8; N], pc: &mut Pc) -> Self {
Self::new(&x[..], pc)
}
}
impl TryFrom<Rval> for *const f64 {
type Error = &'static str;
fn try_from(x: Rval) -> Result<*const f64, &'static str> {
let ft = unsafe { TYPEOF(x.0) } as u32;
if ft != REALSXP {
Err("Object is not of storage mode `double`")
} else {
Ok(unsafe { REAL(x.0) })
}
}
}
impl TryFrom<Rval> for *mut f64 {
type Error = &'static str;
fn try_from(x: Rval) -> Result<*mut f64, &'static str> {
let ft = unsafe { TYPEOF(x.0) } as u32;
if ft != REALSXP {
Err("Object is not of storage mode `double`")
} else {
Ok(unsafe { REAL(x.0) })
}
}
}
impl TryFrom<Rval> for *const i32 {
type Error = &'static str;
fn try_from(x: Rval) -> Result<*const i32, &'static str> {
let ft = unsafe { TYPEOF(x.0) } as u32;
if ft != INTSXP || ft != LGLSXP {
Err("Object is not of storage mode `integer`")
} else if ft == INTSXP {
Ok(unsafe { INTEGER(x.0) })
} else {
Ok(unsafe { LOGICAL(x.0) })
}
}
}
impl TryFrom<Rval> for *mut i32 {
type Error = &'static str;
fn try_from(x: Rval) -> Result<*mut i32, &'static str> {
let ft = unsafe { TYPEOF(x.0) } as u32;
if ft != INTSXP || ft != LGLSXP {
Err("Object is not of storage mode `integer`")
} else if ft == INTSXP {
Ok(unsafe { INTEGER(x.0) })
} else {
Ok(unsafe { LOGICAL(x.0) })
}
}
}
impl TryFrom<Rval> for *const u8 {
type Error = &'static str;
fn try_from(x: Rval) -> Result<*const u8, &'static str> {
let ft = unsafe { TYPEOF(x.0) } as u32;
if ft != RAWSXP {
Err("Object is not of storage mode `raw`")
} else {
Ok(unsafe { RAW(x.0) })
}
}
}
impl TryFrom<Rval> for *mut u8 {
type Error = &'static str;
fn try_from(x: Rval) -> Result<*mut u8, &'static str> {
let ft = unsafe { TYPEOF(x.0) } as u32;
if ft != RAWSXP {
Err("Object is not of storage mode `raw`")
} else {
Ok(unsafe { RAW(x.0) })
}
}
}
impl NewProtected<&str> for Rval {
fn new(x: &str, pc: &mut Pc) -> Self {
let sexp = Self::new_character(x, pc).0;
Self(pc.protect(unsafe { Rf_ScalarString(sexp) }))
}
}
impl NewProtected<&String> for Rval {
fn new(x: &String, pc: &mut Pc) -> Self {
Self::new(&x[..], pc)
}
}
impl NewProtected<String> for Rval {
fn new(x: String, pc: &mut Pc) -> Self {
Self::new(&x[..], pc)
}
}
impl<const LENGTH: usize> NewProtected<[&str; LENGTH]> for Rval {
fn new(x: [&str; LENGTH], pc: &mut Pc) -> Self {
let y = Rval::new_vector_character(LENGTH, pc);
for (i, x) in x.iter().enumerate() {
unsafe { SET_STRING_ELT(y.0, i.try_into().unwrap(), Self::new_character(*x, pc).0) };
}
y
}
}
impl NewProtected<&[&str]> for Rval {
fn new(x: &[&str], pc: &mut Pc) -> Self {
let len = x.len();
let y = Rval::new_vector_character(len, pc);
for (i, x) in x.iter().enumerate() {
unsafe { SET_STRING_ELT(y.0, i.try_into().unwrap(), Self::new_character(*x, pc).0) };
}
y
}
}
impl TryFrom<Rval> for &str {
type Error = &'static str;
fn try_from(x: Rval) -> Result<&'static str, &'static str> {
let sexp = if x.is_character() {
if x.is_empty() {
return Err("Length must be at least one");
}
x.get_character_element(0).0
} else {
x.0
};
if unsafe { TYPEOF(sexp) != CHARSXP.try_into().unwrap() } {
return Err("Object is not of storage model `character`");
}
let a = unsafe { R_CHAR(sexp) as *const c_char };
let c_str = unsafe { CStr::from_ptr(a) };
match c_str.to_str() {
Ok(x) => Ok(x),
Err(_) => Err("Could not convert to UTF-8"),
}
}
}
pub struct Pc {
counter: i32,
}
impl Pc {
pub fn new() -> Self {
Self { counter: 0 }
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn protect(&mut self, sexp: SEXP) -> SEXP {
unsafe { Rf_protect(sexp) };
self.counter += 1;
sexp
}
}
impl Default for Pc {
fn default() -> Self {
Self::new()
}
}
impl Drop for Pc {
fn drop(&mut self) {
if self.counter > 0 {
unsafe { Rf_unprotect(self.counter) };
}
}
}
#[doc(hidden)]
#[no_mangle]
pub extern "C" fn set_custom_panic_hook() -> SEXP {
std::panic::set_hook(Box::new(|panic_info| {
let (filename, line, column) = if let Some(location) = panic_info.location() {
(
location.file().to_string(),
location.line(),
location.column(),
)
} else {
("".to_string(), 0, 0)
};
let message = if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
s.to_string()
} else if let Some(s) = panic_info.payload().downcast_ref::<String>() {
s.to_string()
} else {
"".to_string()
};
use crate::r;
reprintln!(
"Error in file '{}' at line {}, column {} : {}",
filename,
line,
column,
message
);
}));
unsafe { R_NilValue }
}