use crate::*;
#[derive(Clone)]
pub struct ListIter {
vector: Robj,
i: usize,
len: usize,
}
impl ListIter {
pub fn new() -> Self {
ListIter {
vector: ().into(),
i: 0,
len: 0,
}
}
}
impl Iterator for ListIter {
type Item = Robj;
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
fn next(&mut self) -> Option<Self::Item> {
let i = self.i;
self.i += 1;
if i >= self.len {
return None;
} else {
Some(unsafe { new_owned(VECTOR_ELT(self.vector.get(), i as isize)) })
}
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.i += n;
self.next()
}
}
pub struct SliceIter<T> {
#[allow(dead_code)]
vector: Robj,
i: usize,
len: usize,
ptr: *const T,
}
impl<T> SliceIter<T> {
pub fn new() -> Self {
SliceIter {
vector: ().into(),
i: 0,
len: 0,
ptr: std::ptr::null(),
}
}
pub fn from_slice(vector: Robj, slice: &[T]) -> Self {
SliceIter {
vector,
i: 0,
len: slice.len(),
ptr: slice.as_ptr(),
}
}
}
impl<T: Copy> Iterator for SliceIter<T> {
type Item = T;
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
fn next(&mut self) -> Option<Self::Item> {
let i = self.i;
self.i += 1;
if i >= self.len {
self.i = self.len;
None
} else {
unsafe { Some(*self.ptr.offset(i as isize)) }
}
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.i += n;
self.next()
}
}
pub type NamedListIter = std::iter::Zip<StrIter, ListIter>;
pub type Int = SliceIter<i32>;
pub type Real = SliceIter<f64>;
pub type Logical = SliceIter<Bool>;
#[derive(Clone)]
pub struct PairlistIter {
root_obj: Robj,
list_elem: SEXP,
}
impl PairlistIter {
pub fn new() -> Self {
unsafe {
Self {
root_obj: ().into(),
list_elem: R_NilValue,
}
}
}
}
impl Iterator for PairlistIter {
type Item = Robj;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
let sexp = self.list_elem;
if sexp == R_NilValue {
None
} else {
self.list_elem = CDR(sexp);
Some(new_owned(CAR(sexp)))
}
}
}
}
#[derive(Clone)]
pub struct PairlistTagIter {
root_obj: Robj,
list_elem: SEXP,
}
impl PairlistTagIter {
pub fn new() -> Self {
unsafe {
Self {
root_obj: ().into(),
list_elem: R_NilValue,
}
}
}
}
impl Iterator for PairlistTagIter {
type Item = &'static str;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
let sexp = self.list_elem;
if sexp == R_NilValue {
None
} else {
self.list_elem = CDR(sexp);
if let Some(symbol) = new_owned(TAG(sexp)).as_symbol() {
Some(std::mem::transmute(symbol.0))
} else {
Some(na_str())
}
}
}
}
}
#[derive(Clone)]
pub struct StrIter {
vector: Robj,
i: usize,
len: usize,
levels: SEXP,
}
impl StrIter {
pub fn new() -> Self {
unsafe {
Self {
vector: ().into(),
i: 0,
len: 0,
levels: R_NilValue,
}
}
}
}
fn str_from_strsxp<'a>(sexp: SEXP, index: isize) -> &'a str {
unsafe {
if index < 0 || index >= Rf_xlength(sexp) {
na_str()
} else {
let charsxp = STRING_ELT(sexp, index);
if charsxp == R_NaString {
na_str()
} else if TYPEOF(charsxp) == CHARSXP as i32 {
let ptr = R_CHAR(charsxp) as *const u8;
let slice = std::slice::from_raw_parts(ptr, Rf_xlength(charsxp) as usize);
std::str::from_utf8_unchecked(slice)
} else {
na_str()
}
}
}
}
impl Iterator for StrIter {
type Item = &'static str;
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
fn next(&mut self) -> Option<Self::Item> {
unsafe {
let i = self.i;
self.i += 1;
let vector = self.vector.get();
if i >= self.len {
return None;
} else if TYPEOF(vector) as u32 == STRSXP {
Some(str_from_strsxp(vector, i as isize))
} else if TYPEOF(vector) as u32 == INTSXP && TYPEOF(self.levels) as u32 == STRSXP {
let j = *(INTEGER(vector).offset(i as isize));
Some(str_from_strsxp(self.levels, j as isize - 1))
} else {
return None;
}
}
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.i += n;
self.next()
}
}
macro_rules! impl_iter_debug {
($name: ty) => {
impl std::fmt::Debug for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[")?;
let mut comma = "";
for s in self.clone() {
write!(f, "{}{:?}", comma, s)?;
comma = ", ";
}
write!(f, "]")
}
}
};
}
#[derive(Clone)]
pub struct EnvIter {
hash_table: ListIter,
pairlist: PairlistIter,
pairlisttags: PairlistTagIter,
}
impl Iterator for EnvIter {
type Item = (&'static str, Robj);
fn next(&mut self) -> Option<Self::Item> {
loop {
loop {
match (self.pairlisttags.next(), self.pairlist.next()) {
(Some(key), Some(value)) => {
if !key.is_na() && !value.is_unbound_value() {
println!("value: {:?}", (&key, &value));
return Some((key, value));
}
}
_ => break,
}
}
loop {
if let Some(obj) = self.hash_table.next() {
if !obj.is_null() && obj.is_pairlist() {
self.pairlisttags = obj.as_pairlist_tag_iter().unwrap();
self.pairlist = obj.as_pairlist_iter().unwrap();
break;
}
} else {
return None;
}
}
}
}
}
impl_iter_debug!(ListIter);
impl_iter_debug!(PairlistIter);
impl_iter_debug!(PairlistTagIter);
impl_iter_debug!(StrIter);
impl_iter_debug!(EnvIter);
impl Robj {
pub fn as_pairlist_iter(&self) -> Option<PairlistIter> {
match self.sexptype() {
LISTSXP | LANGSXP | DOTSXP => unsafe {
Some(PairlistIter {
root_obj: self.into(),
list_elem: self.get(),
})
},
_ => None,
}
}
pub fn as_pairlist_tag_iter(&self) -> Option<PairlistTagIter> {
match self.sexptype() {
LISTSXP | LANGSXP | DOTSXP => unsafe {
Some(PairlistTagIter {
root_obj: self.into(),
list_elem: self.get(),
})
},
_ => None,
}
}
pub fn as_list_iter(&self) -> Option<ListIter> {
match self.sexptype() {
VECSXP | EXPRSXP | WEAKREFSXP => Some(ListIter {
vector: self.into(),
i: 0,
len: self.len(),
}),
_ => None,
}
}
pub fn as_str_iter(&self) -> Option<StrIter> {
let i = 0;
let len = self.len();
match self.sexptype() {
STRSXP => unsafe {
Some(StrIter {
vector: self.into(),
i,
len,
levels: R_NilValue,
})
},
INTSXP => unsafe {
if let Some(levels) = self.get_attrib(levels_symbol()) {
if self.is_factor() && levels.sexptype() == STRSXP {
Some(StrIter {
vector: self.into(),
i,
len,
levels: levels.get(),
})
} else {
None
}
} else {
None
}
},
_ => None,
}
}
pub fn as_env_iter(&self) -> Option<EnvIter> {
if self.is_environment() {
unsafe {
let hashtab = new_owned(HASHTAB(self.get()));
let frame = new_owned(FRAME(self.get()));
if hashtab.is_null() && frame.is_pairlist() {
Some(EnvIter {
hash_table: ListIter::new(),
pairlisttags: frame.as_pairlist_tag_iter().unwrap(),
pairlist: frame.as_pairlist_iter().unwrap(),
})
} else if hashtab.is_list() {
Some(EnvIter {
hash_table: hashtab.as_list_iter().unwrap(),
pairlist: PairlistIter::new(),
pairlisttags: PairlistTagIter::new(),
})
} else {
None
}
}
} else {
None
}
}
}