use crate::robj::{GetSexp, Rinternals};
use crate::*;
use libR_sys::*;
pub mod altrep;
pub mod complexes;
pub mod dataframe;
pub mod doubles;
pub mod environment;
pub mod expr;
pub mod externalptr;
pub mod function;
pub mod integers;
pub mod lang;
pub mod list;
pub mod logicals;
mod macros;
pub mod matrix;
pub mod nullable;
pub mod pairlist;
pub mod primitive;
pub mod promise;
pub mod raw;
pub mod rstr;
pub mod s4;
pub mod strings;
pub mod symbol;
pub use self::rstr::Rstr;
pub use altrep::{
AltComplexImpl, AltIntegerImpl, AltLogicalImpl, AltRawImpl, AltRealImpl, AltStringImpl, Altrep,
AltrepImpl,
};
pub use complexes::Complexes;
pub use dataframe::{Dataframe, IntoDataFrameRow};
pub use doubles::Doubles;
pub use environment::{EnvIter, Environment};
pub use expr::Expressions;
pub use externalptr::ExternalPtr;
pub use function::Function;
pub use integers::Integers;
pub use lang::Language;
pub use list::{FromList, List, ListIter};
pub use logicals::Logicals;
pub use matrix::{MatrixConversions, RArray, RColumn, RMatrix, RMatrix3D};
pub use nullable::Nullable;
pub use pairlist::{Pairlist, PairlistIter};
pub use primitive::Primitive;
pub use promise::Promise;
pub use raw::Raw;
pub use s4::S4;
pub use strings::Strings;
pub use symbol::Symbol;
pub(crate) 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 ::std::os::raw::c_char) }
}
pub(crate) 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 res = Robj::alloc_vector(sexptype, values.len());
let sexp = res.get();
for (i, val) in values.enumerate() {
SET_VECTOR_ELT(sexp, i as R_xlen_t, val.into().get());
}
res
})
}
macro_rules! make_conversions {
($typename: ident, $errname: ident, $isfunc: ident, $errstr: expr) => {
impl<'a> FromRobj<'a> for $typename {
fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
if let Ok(f) = $typename::try_from(robj.clone()) {
Ok(f)
} else {
Err($errstr)
}
}
}
impl From<$typename> for Robj {
fn from(val: $typename) -> Self {
val.robj
}
}
impl From<&$typename> for Robj {
fn from(val: &$typename) -> Self {
val.robj.to_owned()
}
}
impl TryFrom<&Robj> for $typename {
type Error = crate::Error;
fn try_from(robj: &Robj) -> Result<Self> {
if robj.$isfunc() {
Ok($typename { robj: robj.clone() })
} else {
Err(Error::$errname(robj.clone()))
}
}
}
impl TryFrom<Robj> for $typename {
type Error = crate::Error;
fn try_from(robj: Robj) -> Result<Self> {
<$typename>::try_from(&robj)
}
}
make_getsexp!($typename, impl);
};
}
macro_rules! make_getsexp {
($typename: ty, $($impl : tt)*) => {
$($impl)* GetSexp for $typename {
unsafe fn get(&self) -> SEXP {
self.robj.get()
}
fn as_robj(&self) -> &Robj {
&self.robj
}
fn as_robj_mut(&mut self) -> &mut Robj {
&mut self.robj
}
}
$($impl)* Length for $typename {}
$($impl)* Types for $typename {}
$($impl)* Conversions for $typename {}
$($impl)* Rinternals for $typename {}
$($impl)* Slices for $typename {}
$($impl)* Operators for $typename {}
};
}
make_conversions!(Pairlist, ExpectedPairlist, is_pairlist, "Not a pairlist");
make_conversions!(
Function,
ExpectedFunction,
is_function,
"Not a function or primitive."
);
make_conversions!(Raw, ExpectedRaw, is_raw, "Not a raw object");
make_conversions!(Rstr, ExpectedRstr, is_char, "Not a character object");
make_conversions!(
Environment,
ExpectedEnvironment,
is_environment,
"Not an Environment"
);
make_conversions!(List, ExpectedList, is_list, "Not a List");
make_conversions!(
Expressions,
ExpectedExpression,
is_expressions,
"Not an Expression"
);
make_conversions!(
Language,
ExpectedLanguage,
is_language,
"Not a Language object"
);
make_conversions!(Symbol, ExpectedSymbol, is_symbol, "Not a Symbol object");
make_conversions!(
Primitive,
ExpectedPrimitive,
is_primitive,
"Not a Primitive object"
);
make_conversions!(Promise, ExpectedPromise, is_promise, "Not a Promise object");
make_conversions!(Altrep, ExpectedAltrep, is_altrep, "Not an Altrep type");
make_conversions!(S4, ExpectedS4, is_s4, "Not a S4 type");
make_conversions!(Integers, ExpectedInteger, is_integer, "Not an integer type");
make_conversions!(Logicals, ExpectedLogical, is_logical, "Not a logical type");
make_conversions!(Doubles, ExpectedReal, is_real, "Not a floating point type");
make_conversions!(
Complexes,
ExpectedComplex,
is_complex,
"Not a complex number or vector"
);
make_conversions!(Strings, ExpectedString, is_string, "Not a string vector");
make_getsexp!(Dataframe<T>, impl<T>);
pub trait Conversions: GetSexp {
fn as_symbol(&self) -> Option<Symbol> {
Symbol::try_from(self.as_robj().clone()).ok()
}
fn as_char(&self) -> Option<Rstr> {
Rstr::try_from(self.as_robj().clone()).ok()
}
fn as_raw(&self) -> Option<Raw> {
Raw::try_from(self.as_robj().clone()).ok()
}
fn as_language(&self) -> Option<Language> {
Language::try_from(self.as_robj().clone()).ok()
}
fn as_pairlist(&self) -> Option<Pairlist> {
Pairlist::try_from(self.as_robj().clone()).ok()
}
fn as_list(&self) -> Option<List> {
List::try_from(self.as_robj().clone()).ok()
}
fn as_expressions(&self) -> Option<Expressions> {
Expressions::try_from(self.as_robj().clone()).ok()
}
fn as_environment(&self) -> Option<Environment> {
Environment::try_from(self.as_robj().clone()).ok()
}
fn as_function(&self) -> Option<Function> {
Function::try_from(self.as_robj().clone()).ok()
}
fn as_promise(&self) -> Option<Promise> {
Promise::try_from(self.as_robj().clone()).ok()
}
}
impl Conversions for Robj {}
pub trait SymPair {
fn sym_pair(self) -> (Option<Robj>, Robj);
}
impl<S, R> SymPair for (S, R)
where
S: AsRef<str>,
R: Into<Robj>,
{
fn sym_pair(self) -> (Option<Robj>, Robj) {
let val = self.0.as_ref();
let nm = if val.is_empty() {
None
} else {
Some(r!(Symbol::from_string(val)))
};
(nm, self.1.into())
}
}
impl<S, R> SymPair for &(S, R)
where
S: AsRef<str>,
R: Into<Robj>,
R: Clone,
{
fn sym_pair(self) -> (Option<Robj>, Robj) {
let val = self.0.as_ref();
let nm = if val.is_empty() {
None
} else {
Some(r!(Symbol::from_string(val)))
};
(nm, self.1.clone().into())
}
}