#[doc(hidden)]
use crate::*;
#[doc(hidden)]
use libR_sys::*;
#[derive(Debug, PartialEq, Clone)]
pub struct Symbol<'a>(pub &'a str);
#[derive(Debug, PartialEq, Clone)]
pub struct Character<'a>(pub &'a str);
#[derive(Debug, PartialEq, Clone)]
pub struct Raw<'a>(pub &'a [u8]);
#[derive(Debug, PartialEq, Clone)]
pub struct Lang<T>(pub T);
#[derive(Debug, PartialEq, Clone)]
pub struct Pairlist<NV> {
pub names_and_values: NV,
}
#[derive(Debug, PartialEq, Clone)]
pub struct List<T>(pub T);
#[derive(Debug, PartialEq, Clone)]
pub struct Expr<T>(pub T);
#[derive(Debug, PartialEq, Clone)]
pub struct Env<P, NV> {
pub parent: P,
pub names_and_values: NV,
}
#[derive(Debug, PartialEq, Clone)]
pub struct Func<F, B, E> {
pub formals: F,
pub body: B,
pub env: E,
}
#[derive(Debug, PartialEq, Clone)]
pub struct Promise<C, E, V> {
pub code: C,
pub env: E,
pub value: V,
pub seen: bool,
}
#[derive(Debug, PartialEq, Clone)]
pub struct Primitive<'a>(pub &'a str);
#[derive(Debug, PartialEq, Clone)]
pub enum Nullable<T> {
NotNull(T),
Null,
}
impl<T> From<List<T>> for Robj
where
T: IntoIterator,
T::IntoIter: ExactSizeIterator,
T::Item: Into<Robj>,
{
fn from(val: List<T>) -> Self {
make_vector(VECSXP, val.0)
}
}
impl<T> From<Expr<T>> for Robj
where
T: IntoIterator,
T::IntoIter: ExactSizeIterator,
T::Item: Into<Robj>,
{
fn from(val: Expr<T>) -> Self {
make_vector(EXPRSXP, val.0)
}
}
impl<'a> From<Raw<'a>> for Robj {
fn from(val: Raw<'a>) -> Self {
single_threaded(|| unsafe {
let val = val.0;
let sexp = Rf_allocVector(RAWSXP, val.len() as R_xlen_t);
ownership::protect(sexp);
let ptr = RAW(sexp);
for (i, &v) in val.iter().enumerate() {
*ptr.offset(i as isize) = v;
}
Robj::Owned(sexp)
})
}
}
impl<'a> From<Symbol<'a>> for Robj {
fn from(name: Symbol) -> Self {
single_threaded(|| unsafe { new_owned(make_symbol(name.0)) })
}
}
impl<'a> From<Primitive<'a>> for Robj {
fn from(name: Primitive) -> Self {
single_threaded(|| unsafe {
let sym = make_symbol(name.0);
let symvalue = new_sys(SYMVALUE(sym));
if symvalue.is_primitive() {
symvalue
} else {
r!(NULL)
}
})
}
}
impl<T> From<Lang<T>> for Robj
where
T: IntoIterator,
T::IntoIter: DoubleEndedIterator,
T::Item: Into<Robj>,
{
fn from(val: Lang<T>) -> Self {
single_threaded(|| unsafe {
let mut res = R_NilValue;
let mut num_protected = 0;
for val in val.0.into_iter().rev() {
let val = Rf_protect(val.into().get());
res = Rf_protect(Rf_lcons(val, res));
num_protected += 2;
}
let res = new_owned(res);
Rf_unprotect(num_protected);
res
})
}
}
impl<'a, P, NV> From<Env<P, NV>> for Robj
where
P: Into<Robj>,
NV: IntoIterator + 'a,
NV::Item: SymPair,
{
fn from(val: Env<P, NV>) -> Self {
single_threaded(|| {
let (parent, names_and_values) = (val.parent, val.names_and_values);
let dict_len = 29;
let res = call!("new.env", TRUE, parent.into(), dict_len).unwrap();
for nv in names_and_values {
let (n, v) = nv.sym_pair();
unsafe { Rf_defineVar(n.get(), v.get(), res.get()) }
}
res
})
}
}
impl<'a, NV> From<Pairlist<NV>> for Robj
where
NV: IntoIterator + 'a,
NV::Item: SymPair,
{
fn from(val: Pairlist<NV>) -> Self {
single_threaded(|| unsafe {
let names_and_values = val.names_and_values;
let mut num_protects = 0;
let mut res = R_NilValue;
let names_and_values: Vec<_> = names_and_values.into_iter().collect();
for nv in names_and_values.into_iter().rev() {
let (name, val) = nv.sym_pair();
let val = Rf_protect(val.get());
res = Rf_protect(Rf_cons(val, res));
num_protects += 2;
if !name.is_na() {
SET_TAG(res, name.get());
}
}
let res = new_owned(res);
Rf_unprotect(num_protects as i32);
res
})
}
}
fn make_symbol(name: &str) -> SEXP {
let mut bytes = Vec::with_capacity(name.len() + 1);
bytes.extend(name.bytes());
bytes.push(0);
unsafe { Rf_install(bytes.as_ptr() as *const i8) }
}
fn make_vector<T>(sexptype: u32, values: T) -> Robj
where
T: IntoIterator,
T::IntoIter: ExactSizeIterator,
T::Item: Into<Robj>,
{
single_threaded(|| unsafe {
let values = values.into_iter();
let sexp = Rf_allocVector(sexptype, values.len() as R_xlen_t);
ownership::protect(sexp);
for (i, val) in values.enumerate() {
SET_VECTOR_ELT(sexp, i as R_xlen_t, val.into().get());
}
Robj::Owned(sexp)
})
}
impl<'a> From<&'a str> for Symbol<'a> {
fn from(val: &'a str) -> Self {
Self(val)
}
}
impl Robj {
pub fn as_symbol(&self) -> Option<Symbol> {
if self.is_symbol() {
unsafe {
let printname = PRINTNAME(self.get());
if TYPEOF(printname) as u32 == CHARSXP {
Some(Symbol(to_str(R_CHAR(printname) as *const u8)))
} else {
None
}
}
} else {
None
}
}
pub fn as_character(&self) -> Option<Character> {
if self.sexptype() == CHARSXP {
Some(Character(unsafe {
to_str(R_CHAR(self.get()) as *const u8)
}))
} else {
None
}
}
pub fn as_raw(&self) -> Option<Raw> {
if self.sexptype() == RAWSXP {
Some(Raw(self.as_raw_slice().unwrap()))
} else {
None
}
}
pub fn as_lang(&self) -> Option<Lang<PairlistIter>> {
if self.sexptype() == LANGSXP {
Some(Lang(self.as_pairlist_iter().unwrap()))
} else {
None
}
}
pub fn as_pairlist(&self) -> Option<Pairlist<Vec<(&str, Robj)>>> {
if self.sexptype() == LISTSXP {
let names = self.as_pairlist_tag_iter().unwrap();
let values = self.as_pairlist_iter().unwrap();
let names_and_values: Vec<_> = names.zip(values).collect();
Some(Pairlist { names_and_values })
} else {
None
}
}
pub fn as_list(&self) -> Option<List<ListIter>> {
self.as_list_iter().map(|l| List(l))
}
pub fn as_expr(&self) -> Option<Expr<Vec<Robj>>> {
if self.sexptype() == EXPRSXP {
let res: Vec<_> = self
.as_list_iter()
.unwrap()
.map(|robj| robj.to_owned())
.collect();
Some(Expr(res))
} else {
None
}
}
pub fn as_environment(&self) -> Option<Env<Robj, EnvIter>> {
if self.is_environment() {
Some(Env {
parent: self.parent().unwrap(),
names_and_values: self.as_env_iter().unwrap(),
})
} else {
None
}
}
pub fn as_func(&self) -> Option<Func<Robj, Robj, Robj>> {
if self.sexptype() == CLOSXP {
unsafe {
let sexp = self.get();
let formals = new_owned(FORMALS(sexp));
let body = new_owned(BODY(sexp));
let env = new_owned(CLOENV(sexp));
Some(Func { formals, body, env })
}
} else {
None
}
}
pub fn as_promise(&self) -> Option<Promise<Robj, Robj, Robj>> {
if self.is_promise() {
unsafe {
let sexp = self.get();
Some(Promise {
code: new_owned(PRCODE(sexp)),
env: new_owned(PRENV(sexp)),
value: new_owned(PRVALUE(sexp)),
seen: PRSEEN(sexp) != 0,
})
}
} else {
None
}
}
}
pub trait SymPair {
fn sym_pair(self) -> (Robj, Robj);
}
impl<S, R> SymPair for (S, R)
where
S: AsRef<str>,
R: Into<Robj>,
{
fn sym_pair(self) -> (Robj, Robj) {
(r!(Symbol(self.0.as_ref())), self.1.into())
}
}
impl<'a, T> FromRobj<'a> for Nullable<T>
where
T: FromRobj<'a>,
{
fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
if robj.is_null() {
Ok(Nullable::Null)
} else {
Ok(Nullable::NotNull(<T>::from_robj(robj)?))
}
}
}
impl<T> From<Nullable<T>> for Robj
where
T: Into<Robj>,
{
fn from(val: Nullable<T>) -> Self {
match val {
Nullable::NotNull(t) => t.into(),
Nullable::Null => r!(NULL),
}
}
}