#[cfg(use_r_altlist)]
use std::error::Error;
use extendr_api::prelude::*;
use extendr_engine::with_r;
#[test]
fn test_altinteger() {
test! {
#[derive(Debug, Clone)]
struct MyCompactIntRange {
start: i32,
len: i32,
step: i32,
missing_index: usize, }
impl AltrepImpl for MyCompactIntRange {
fn length(&self) -> usize {
self.len as usize
}
}
impl AltIntegerImpl for MyCompactIntRange {
fn elt(&self, index: usize) -> Rint {
if index == self.missing_index {
Rint::na()
} else {
Rint::from(self.start + self.step * index as i32)
}
}
}
let mystate = MyCompactIntRange { start: 0, len: 10, step: 1, missing_index: usize::MAX };
let class = Altrep::make_altinteger_class::<MyCompactIntRange>("cir", "mypkg");
let obj = Altrep::from_state_and_class(mystate, class.clone(), false);
assert_eq!(obj.len(), 10);
assert_eq!(obj.as_robj().as_integer_slice().unwrap(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
let mystate_w_missing = MyCompactIntRange { start: 0, len: 10, step: 1, missing_index: 5 };
let obj_w_missing = Altrep::from_state_and_class(mystate_w_missing, class, false);
let robj_w_missing = Robj::from(obj_w_missing);
let integers_w_missing: Integers = robj_w_missing.try_into()?;
assert_eq!(integers_w_missing.elt(9), Rint::from(9));
assert!(integers_w_missing.elt(5).is_na());
let mut dest = [0.into(); 2];
integers_w_missing.get_region(2, &mut dest);
assert_eq!(dest, [2, 3]);
}
}
#[test]
fn test_altreal() {
test! {
#[derive(Debug, Clone)]
struct MyCompactRealRange {
start: f64,
len: usize,
step: f64,
missing_index: usize, }
impl AltrepImpl for MyCompactRealRange {
fn length(&self) -> usize {
self.len
}
}
impl AltRealImpl for MyCompactRealRange {
fn elt(&self, index: usize) -> Rfloat {
if index == self.missing_index {
Rfloat::na()
} else {
Rfloat::from(self.start + self.step * index as f64)
}
}
}
let mystate = MyCompactRealRange { start: 0.0, len: 10, step: 1.0, missing_index: usize::MAX };
let class = Altrep::make_altreal_class::<MyCompactRealRange>("crr", "mypkg");
let obj = Altrep::from_state_and_class(mystate, class.clone(), false);
assert_eq!(obj.len(), 10);
assert_eq!(obj.as_robj().as_real_slice().unwrap(), [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]);
let mystate_w_missing = MyCompactRealRange { start: 0.0, len: 10, step: 1.0, missing_index: 5 };
let obj_w_missing = Altrep::from_state_and_class(mystate_w_missing, class, false);
let robj_w_missing = Robj::from(obj_w_missing);
let doubles_w_missing: Doubles = robj_w_missing.try_into()?;
assert_eq!(doubles_w_missing.elt(9), Rfloat::from(9.0));
if cfg!(not(target_arch = "x86")) {
assert!(doubles_w_missing.elt(5).is_na());
}
let mut dest = [0.0.into(); 2];
doubles_w_missing.get_region(2, &mut dest);
assert_eq!(dest, [2.0, 3.0]);
}
}
#[test]
fn test_altlogical() {
test! {
#[derive(Debug, Clone)]
struct IsEven {
len: usize,
}
impl AltrepImpl for IsEven {
fn length(&self) -> usize {
self.len
}
}
impl AltLogicalImpl for IsEven {
fn elt(&self, index: usize) -> Rbool {
(index % 2 == 1).into()
}
}
let mystate = IsEven { len: 10 };
let class = Altrep::make_altlogical_class::<IsEven>("iseven", "mypkg");
let obj = Altrep::from_state_and_class(mystate, class, false);
assert_eq!(obj.len(), 10);
assert_eq!(obj.as_robj().as_logical_slice().unwrap(), [FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE]);
}
}
#[test]
fn test_altraw() {
test! {
#[derive(Debug, Clone)]
struct MyCompactRawRange {
start: i32,
len: i32,
step: i32,
}
impl AltrepImpl for MyCompactRawRange {
fn length(&self) -> usize {
self.len as usize
}
}
impl AltRawImpl for MyCompactRawRange {
fn elt(&self, index: usize) -> u8 {
(self.start + self.step * index as i32) as u8
}
}
let mystate = MyCompactRawRange { start: 0, len: 10, step: 1 };
let class = Altrep::make_altraw_class::<MyCompactRawRange>("cir", "mypkg");
let obj = Altrep::from_state_and_class(mystate, class, false);
assert_eq!(obj.len(), 10);
assert_eq!(obj.as_robj().as_raw_slice().unwrap(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
}
}
#[test]
fn test_altcomplex() {
test! {
#[derive(Debug, Clone)]
struct MyCompactComplexRange {
start: f64,
len: usize,
step: f64,
}
impl AltrepImpl for MyCompactComplexRange {
fn length(&self) -> usize {
self.len
}
}
impl AltComplexImpl for MyCompactComplexRange {
fn elt(&self, index: usize) -> Rcplx {
Rcplx::from(c64::new(self.start + self.step * index as f64, self.start + self.step * index as f64))
}
}
let mystate = MyCompactComplexRange { start: 0.0, len: 10, step: 1.0 };
let class = Altrep::make_altcomplex_class::<MyCompactComplexRange>("ccr", "mypkg");
let obj = Altrep::from_state_and_class(mystate, class, false);
assert_eq!(obj.len(), 10);
}
}
#[test]
fn test_altstring() {
test! {
#[derive(Debug, Clone)]
struct StringInts {
len: usize
}
impl AltrepImpl for StringInts {
fn length(&self) -> usize {
self.len
}
}
impl AltStringImpl for StringInts {
fn elt(&self, index: usize) -> Rstr {
format!("{}", index).into()
}
}
let mystate = StringInts { len: 10 };
let class = Altrep::make_altstring_class::<StringInts>("si", "mypkg");
let obj = Altrep::from_state_and_class(mystate, class, false);
assert!(obj.is_altstring());
assert_eq!(obj.len(), 10);
assert_eq!(Robj::from(obj), r!(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]));
}
}
#[test]
#[cfg(use_r_altlist)]
fn test_altlist() -> std::result::Result<(), Box<dyn Error>> {
use extendr_api::AltListImpl;
with_r(|| {
#[derive(Debug, Clone)]
#[extendr]
pub struct VecUsize(pub Vec<Option<usize>>);
#[extendr]
impl VecUsize {}
impl AltrepImpl for VecUsize {
fn length(&self) -> usize {
self.0.len()
}
}
impl AltListImpl for VecUsize {
fn elt(&self, index: usize) -> Robj {
let v = vec![self.0[index]];
Self(v).into_robj()
}
}
let vu = VecUsize(vec![Some(1), None, Some(10)]);
let class = Altrep::make_altlist_class::<VecUsize>("li", "mypkg");
let obj = Altrep::from_state_and_class(vu, class, false);
assert!(obj.is_altlist());
assert_eq!(obj.len(), 3);
let l = List::try_from(obj.into_robj()).unwrap();
let li = l.elt(1).unwrap();
assert!(li.inherits("VecUsize"));
Ok(())
})
}