#![cfg_attr(not(feature = "std"), no_std)]
#![allow(internal_features)]
#![feature(lang_items)]
#![feature(panic_info_message)]
macro_rules! syntax_group {
($($tt:tt)*) => { $($tt)* };
}
use core::{ffi::c_void, slice};
#[allow(non_snake_case)]
mod libR;
use libR::{
R_xlen_t as int, Rf_allocVector, Rf_isInteger, Rf_isLogical, Rf_isReal, Rf_protect,
Rf_unprotect_ptr, Rf_xlength, Rprintf, DATAPTR, DATAPTR_RO, INTSXP, LGLSXP, REALSXP, SEXP, SEXPTYPE
};
#[cfg(not(feature = "std"))]
syntax_group!{
#[lang = "eh_personality"]
pub extern "C" fn rust_eh_personality() {}
macro_rules! println{
($($tt:tt)*) => {
#[allow(unused_unsafe)]
unsafe{
let mut x=alloc::string::String::new();
core::fmt::write(&mut x, format_args!($($tt)*)).and_then(|_|core::fmt::write(&mut x, format_args!("\n\0"))).expect("failed to write string");
Rprintf(x.as_ptr() as *const core::ffi::c_char);
}}
}
extern crate alloc;
use libR::{R_chk_calloc, R_chk_free, R_chk_realloc, Rf_error};
struct SimpleAllocator();
#[global_allocator]
static ALLOCATOR: SimpleAllocator = SimpleAllocator();
unsafe impl Sync for SimpleAllocator {}
unsafe impl alloc::alloc::GlobalAlloc for SimpleAllocator {
unsafe fn alloc(&self, layout: alloc::alloc::Layout) -> *mut u8 {
unsafe { R_chk_calloc(layout.size().div_euclid(layout.align()), layout.align()) as *mut u8 }
}
unsafe fn alloc_zeroed(&self, layout: alloc::alloc::Layout) -> *mut u8 {
unsafe { R_chk_calloc(layout.size().div_euclid(layout.align()), layout.align()) as *mut u8 }
}
unsafe fn dealloc(&self, ptr: *mut u8, _layout: alloc::alloc::Layout) {
unsafe { R_chk_free(ptr as *mut core::ffi::c_void) }
}
unsafe fn realloc(
&self,
ptr: *mut u8,
_layout: alloc::alloc::Layout,
new_size: usize,
) -> *mut u8 {
unsafe { R_chk_realloc(ptr as *mut core::ffi::c_void, new_size) as *mut u8 }
}
}
use alloc::string::String;
#[panic_handler]
fn panic_handler(info: &core::panic::PanicInfo) -> ! {
let mut x = String::new();
if let Some(s) = info.payload().downcast_ref::<&str>() {
println!("panic occurred: {s:?}");
} else {
println!("panic occurred");
}
info.message().map(|i| {
core::fmt::write(&mut x, *i)
.and_then(|_| core::fmt::write(&mut x, format_args!("\n")))
.expect("failed to write string")
});
info.location().map(|i| {
core::fmt::write(&mut x, format_args!("{:?}\n\0", i)).expect("failed to write string")
});
unsafe {
Rprintf(x.as_ptr() as *const core::ffi::c_char);
Rf_error("the program is paniced\0".as_ptr() as *const core::ffi::c_char)
}
}
}
#[repr(transparent)]
pub struct Owned(SEXP);
#[repr(transparent)]
pub struct Protected(Owned);
pub trait SExt where Self: Sized {
fn as_sexp(&self) -> SEXP;
#[inline(always)]
fn len(&self) -> usize {
unsafe { Rf_xlength(self.as_sexp()) as usize }
}
#[inline(always)]
unsafe fn data(self) -> *const c_void {
unsafe { DATAPTR_RO(self.as_sexp()) }
}
#[inline(always)]
unsafe fn data_mut(self) -> *mut c_void {
unsafe { DATAPTR(self.as_sexp()) }
}
#[inline(always)]
fn is_real(self) -> bool {
unsafe { Rf_isReal(self.as_sexp()) == 1 }
}
#[inline(always)]
unsafe fn unsafe_fast_compare_is_int(self) -> bool {
unsafe { Rf_isReal(self.as_sexp()) != 1 }
}
#[inline(always)]
fn could_be_integer(self) -> bool {
let robj = self.as_sexp();
unsafe { Rf_isInteger(robj) == 1 || Rf_isLogical(robj) == 1 }
}
#[inline(always)]
unsafe fn as_real_slice_unchecked(&self) -> &[f64] {
let sexp: SEXP = self.as_sexp();
unsafe { slice::from_raw_parts(sexp.data() as *const f64, sexp.len()) }
}
#[inline(always)]
unsafe fn as_int_slice_unchecked(&self) -> &[i32] {
let sexp: SEXP = self.as_sexp();
unsafe { slice::from_raw_parts(sexp.data() as *const i32, sexp.len()) }
}
}
pub trait MutableSEXP : SExt where Self: Sized {
unsafe fn new_type(len: int, ty:SEXPTYPE)->Self;
#[inline(always)]
fn new_real(len: int) -> Self {
unsafe { MutableSEXP::new_type(len, REALSXP) }
}
#[inline(always)]
fn new_int(len: int) -> Self {
unsafe { MutableSEXP::new_type(len, INTSXP) }
}
#[inline(always)]
fn new_bool(len: int) -> Self {
unsafe { MutableSEXP::new_type(len, LGLSXP) }
}
#[inline(always)]
unsafe fn as_mut_real_slice_unchecked(&mut self) -> &mut [f64] {
let sexp: SEXP = self.as_sexp();
unsafe { slice::from_raw_parts_mut(sexp.data_mut() as *mut f64, sexp.len()) }
}
#[inline(always)]
unsafe fn as_mut_int_slice_unchecked(&mut self) -> &mut [i32] {
let sexp: SEXP = self.as_sexp();
unsafe { slice::from_raw_parts_mut(sexp.data_mut() as *mut i32, sexp.len()) }
}
}
impl SExt for SEXP {
fn as_sexp(&self) -> SEXP {
*self
}
}
impl SExt for Owned {
fn as_sexp(&self) -> SEXP {
self.0
}
}
impl SExt for Protected {
fn as_sexp(&self) -> SEXP {
self.0 .0
}
}
impl MutableSEXP for Owned {
#[inline(always)]
unsafe fn new_type(len: int, ty:SEXPTYPE) -> Self {
unsafe { Self(Rf_allocVector(ty, len)) }
}
}
impl MutableSEXP for Protected {
#[inline(always)]
unsafe fn new_type(len: int, ty:SEXPTYPE) -> Self {
unsafe { Self(Owned(Rf_protect(Rf_allocVector(ty, len)))) }
}
}
impl From<Owned> for Protected {
#[inline(always)]
fn from(s: Owned) -> Self {
Self(unsafe { Owned(Rf_protect(s.0)) })
}
}
impl From<Protected> for Owned {
#[inline(always)]
fn from(s: Protected) -> Self {
unsafe {
let s = core::mem::transmute::<Protected, Owned>(s);
Rf_unprotect_ptr(s.0);
s
}
}
}
impl From<Protected> for SEXP {
#[inline(always)]
fn from(s: Protected) -> Self {
s.0 .0
}
}
impl From<Owned> for SEXP {
#[inline(always)]
fn from(s: Owned) -> Self {
s.0
}
}
impl Drop for Protected {
#[inline(always)]
fn drop(&mut self) {
unsafe { Rf_unprotect_ptr(self.0 .0) }
}
}
pub mod prelude {
pub use crate::{SExt, MutableSEXP};
pub type SEXP=crate::SEXP;
pub type Owned=crate::Owned;
pub type Protected=crate::Protected;
}