extendr_api/
iter.rs
1use crate::*;
2
3use extendr_ffi::{R_NaString, R_NilValue, Rf_isFactor, INTEGER, STRING_ELT, TYPEOF};
4use wrapper::symbol::levels_symbol;
5pub type NamedListIter = std::iter::Zip<StrIter, ListIter>;
7
8#[derive(Clone)]
24pub struct StrIter {
25 vector: Robj,
26 i: usize,
27 len: usize,
28 levels: SEXP,
29}
30
31impl Default for StrIter {
32 fn default() -> Self {
33 StrIter::new(0)
34 }
35}
36
37impl StrIter {
38 pub fn new(len: usize) -> Self {
40 let vector = if len == 0 { nil_value() } else { na_string() };
41 unsafe {
42 Self {
43 vector,
44 i: 0,
45 len,
46 levels: R_NilValue,
47 }
48 }
49 }
50
51 pub fn na_iter(len: usize) -> StrIter {
52 Self {
53 len,
54 ..Default::default()
55 }
56 }
57}
58
59pub(crate) fn str_from_strsxp<'a>(sexp: SEXP, index: usize) -> Option<&'a str> {
61 single_threaded(|| unsafe {
62 let charsxp = STRING_ELT(sexp, index as _);
63 rstr::charsxp_to_str(charsxp)
64 })
65}
66
67impl Iterator for StrIter {
68 type Item = &'static str;
69
70 fn size_hint(&self) -> (usize, Option<usize>) {
71 (self.len, Some(self.len))
72 }
73
74 fn next(&mut self) -> Option<Self::Item> {
75 unsafe {
76 let i = self.i;
77 self.i += 1;
78 let vector = self.vector.get();
79 if i >= self.len {
80 None
81 } else if TYPEOF(vector) == SEXPTYPE::NILSXP {
82 None
83 } else if TYPEOF(vector) == SEXPTYPE::STRSXP {
84 str_from_strsxp(vector, i)
85 } else if vector == R_NaString {
86 Some(<&str>::na())
87 } else if TYPEOF(vector) == SEXPTYPE::CHARSXP {
88 rstr::charsxp_to_str(vector)
89 } else if Rf_isFactor(vector).into() {
90 let level_index = std::slice::from_raw_parts(INTEGER(vector), self.len as _);
93 let level_index = level_index.get(i)?;
94 let level_index = level_index
95 .checked_sub(1)
96 .expect("the factor integer has an invalid value in it");
97 str_from_strsxp(self.levels, level_index as _)
98 } else {
99 None
100 }
101 }
102 }
103
104 fn nth(&mut self, n: usize) -> Option<Self::Item> {
105 self.i += n;
106 self.next()
107 }
108}
109
110impl ExactSizeIterator for StrIter {
111 fn len(&self) -> usize {
112 self.len - self.i
113 }
114}
115
116macro_rules! impl_iter_debug {
117 ($name: ty) => {
118 impl std::fmt::Debug for $name {
119 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120 write!(f, "[")?;
121 let mut comma = "";
122 for s in self.clone() {
123 write!(f, "{}{:?}", comma, s)?;
124 comma = ", ";
125 }
126 write!(f, "]")
127 }
128 }
129 };
130}
131
132impl_iter_debug!(ListIter);
133impl_iter_debug!(PairlistIter);
134impl_iter_debug!(StrIter);
135impl_iter_debug!(EnvIter);
136
137impl TryFrom<&Robj> for StrIter {
139 type Error = Error;
140
141 fn try_from(value: &Robj) -> Result<Self> {
142 value
143 .as_str_iter()
144 .ok_or_else(|| Error::ExpectedString(value.clone()))
145 }
146}
147
148impl TryFrom<Robj> for StrIter {
149 type Error = Error;
150
151 fn try_from(value: Robj) -> Result<Self> {
152 (&value).try_into()
153 }
154}
155
156pub trait AsStrIter: GetSexp + Types + Length + Attributes + Rinternals {
157 fn as_str_iter(&self) -> Option<StrIter> {
185 let i = 0;
186 let len = self.len();
187 if self.sexptype() == SEXPTYPE::STRSXP {
188 unsafe {
189 Some(StrIter {
190 vector: self.as_robj().clone(),
191 i,
192 len,
193 levels: R_NilValue,
194 })
195 }
196 } else if self.sexptype() == SEXPTYPE::CHARSXP {
197 let len = 1;
198 unsafe {
199 Some(StrIter {
200 vector: self.as_robj().clone(),
201 i,
202 len,
203 levels: R_NilValue,
204 })
205 }
206 } else if self.is_factor() {
207 let levels = self.get_attrib(levels_symbol()).unwrap();
208 unsafe {
209 Some(StrIter {
210 vector: self.as_robj().clone(),
211 i,
212 len,
213 levels: levels.get(),
214 })
215 }
216 } else {
217 None
218 }
219 }
220}
221
222impl AsStrIter for Robj {}
223
224#[cfg(test)]
225mod tests {
226 use extendr_engine::with_r;
227
228 use super::*;
229
230 #[test]
231 fn single_charsxp_iterator() {
232 with_r(|| {
233 let single_charsxp = blank_string();
234 let s1: Vec<_> = single_charsxp.as_str_iter().unwrap().collect();
235 let single_charsxp = blank_scalar_string();
236 let s2: Vec<_> = single_charsxp.as_str_iter().unwrap().collect();
237 assert_eq!(s1, s2);
238 assert_eq!(s1.len(), 1);
239 assert_eq!(s2.len(), 1);
240 });
241 }
242
243 #[test]
244 fn test_new_constructor() {
245 with_r(|| {
246 let str_iter = StrIter::new(10);
247 assert_eq!(str_iter.collect::<Vec<_>>().len(), 10);
248 let str_iter = StrIter::new(0);
249 let str_iter_collect = str_iter.collect::<Vec<_>>();
250 assert_eq!(str_iter_collect.len(), 0);
251 assert!(str_iter_collect.is_empty());
252 let mut str_iter = StrIter::new(0);
253 assert!(str_iter.next().is_none());
254 });
255 }
256}