miniextendr_api/altrep_data/iter/
state.rs1use super::macros::define_iter_data;
17use std::cell::RefCell;
18use std::sync::OnceLock;
19
20use crate::altrep_data::{
21 AltIntegerData, AltLogicalData, AltRawData, AltRealData, AltrepLen, Logical,
22};
23
24#[derive(#[automatically_derived]
impl<I: ::core::clone::Clone, T: ::core::clone::Clone> ::core::clone::Clone
for IterState<I, T> {
#[inline]
fn clone(&self) -> Self {
IterState {
len: ::core::clone::Clone::clone(&self.len),
iter: ::core::clone::Clone::clone(&self.iter),
cache: ::core::clone::Clone::clone(&self.cache),
materialized: ::core::clone::Clone::clone(&self.materialized),
}
}
}Clone)]
41pub struct IterState<I, T> {
42 len: usize,
44 iter: RefCell<Option<I>>,
46 cache: RefCell<Vec<T>>,
48 materialized: OnceLock<Vec<T>>,
50}
51
52impl<I, T> IterState<I, T>
53where
54 I: Iterator<Item = T>,
55{
56 pub fn new(iter: I, len: usize) -> Self {
69 Self {
70 len,
71 iter: RefCell::new(Some(iter)),
72 cache: RefCell::new(Vec::with_capacity(len.min(1024))),
73 materialized: OnceLock::new(),
74 }
75 }
76
77 pub fn from_values(values: Vec<T>) -> Self {
82 Self {
83 len: values.len(),
84 iter: RefCell::new(None),
85 cache: RefCell::new(Vec::new()),
86 materialized: OnceLock::from(values),
87 }
88 }
89
90 pub fn get_element(&self, i: usize) -> Option<T>
99 where
100 T: Copy,
101 {
102 if i >= self.len {
104 return None;
105 }
106
107 if let Some(vec) = self.materialized.get() {
109 return vec.get(i).copied();
110 }
111
112 let mut cache = self.cache.borrow_mut();
114
115 if i < cache.len() {
117 return Some(cache[i]);
118 }
119
120 let mut iter_opt = self.iter.borrow_mut();
122 while cache.len() <= i {
126 match iter_opt.as_mut()?.next() {
127 Some(value) => cache.push(value),
128 None => {
129 iter_opt.take();
130 return None;
131 }
132 }
133 }
134
135 let value = cache[i];
136
137 if cache.len() == self.len {
140 iter_opt.take();
141
142 let vec = std::mem::take(&mut *cache);
143 drop(cache);
144 drop(iter_opt);
145
146 let _ = self.materialized.set(vec);
147 }
148
149 Some(value)
150 }
151
152 pub fn materialize_all(&self) -> &[T] {
164 match self.try_materialize_all() {
165 Ok(vec) => vec,
166 Err(cached) => {
::core::panicking::panic_fmt(format_args!("ALTREP iterator ended before element {0} of its declared length {1}",
cached + 1, self.len));
}panic!(
167 "ALTREP iterator ended before element {} of its declared length {}",
168 cached + 1,
169 self.len
170 ),
171 }
172 }
173
174 pub fn try_materialize_all(&self) -> Result<&[T], usize> {
177 if let Some(vec) = self.materialized.get() {
178 return Ok(vec);
179 }
180
181 let mut cache = self.cache.borrow_mut();
182 let mut iter_opt = self.iter.borrow_mut();
183 if let Some(mut iter) = iter_opt.take() {
184 while cache.len() < self.len {
185 let Some(value) = iter.next() else {
186 break;
187 };
188 cache.push(value);
189 }
190 }
191 if cache.len() != self.len {
192 return Err(cache.len());
193 }
194
195 let vec = std::mem::take(&mut *cache);
196 drop(cache);
197 drop(iter_opt);
198 Ok(self.materialized.get_or_init(|| vec))
199 }
200
201 pub fn as_materialized(&self) -> Option<&[T]> {
205 self.materialized.get().map(|v| v.as_slice())
206 }
207
208 pub fn len(&self) -> usize {
210 self.len
211 }
212
213 pub fn is_empty(&self) -> bool {
215 self.len == 0
216 }
217}
218
219impl<I, T> IterState<I, T>
220where
221 I: ExactSizeIterator<Item = T>,
222{
223 pub fn from_exact_size(iter: I) -> Self {
227 let len = iter.len();
228 Self::new(iter, len)
229 }
230}
231
232#[doc = r" Iterator-backed integer vector data adaptor."]
#[doc = r""]
#[doc =
r" Wraps an iterator producing `i32` values and implements the data-level"]
#[doc =
r" traits ([`AltrepLen`] + [`AltIntegerData`]) for backing an ALTREP integer"]
#[doc =
r" vector. To expose it to R, wrap it in a `#[derive(AltrepInteger)]` +"]
#[doc =
r" `#[altrep(manual)]` struct (see the iterator module documentation)."]
#[doc = r""]
#[doc = r" # Example"]
#[doc = r""]
#[doc = r" ```ignore"]
#[doc = r" use miniextendr_api::altrep_data::IterIntData;"]
#[doc = r""]
#[doc = r" // Create from an iterator"]
#[doc = r" let data = IterIntData::from_iter((1..=10).map(|x| x * 2), 10);"]
#[doc = r" ```"]
pub struct IterIntData<I: Iterator<Item = i32>> {
state: super::IterState<I, i32>,
}
#[automatically_derived]
impl<I: ::core::clone::Clone + Iterator<Item = i32>> ::core::clone::Clone for
IterIntData<I> {
#[inline]
fn clone(&self) -> Self {
IterIntData { state: ::core::clone::Clone::clone(&self.state) }
}
}
impl<I: Iterator<Item = i32>> IterIntData<I> {
pub fn from_iter(iter: I, len: usize) -> Self {
Self { state: super::IterState::new(iter, len) }
}
}
impl<I: Iterator<Item = i32>> crate::altrep_data::AltrepSerialize for
IterIntData<I> {
fn serialized_state(&self) -> crate::SEXP {
match self.state.try_materialize_all() {
Ok(values) => crate::IntoR::into_sexp(values.to_vec()),
Err(_) => crate::SEXP::null(),
}
}
fn unserialize(state: crate::SEXP) -> Option<Self> {
let values =
<Vec<i32> as crate::TryFromSexp>::try_from_sexp(state).ok()?;
Some(Self { state: super::IterState::from_values(values) })
}
}
impl<I: ExactSizeIterator<Item = i32>> IterIntData<I> {
pub fn from_exact_iter(iter: I) -> Self {
let len = iter.len();
Self::from_iter(iter, len)
}
}
impl<I: Iterator<Item = i32>> crate::altrep_data::AltrepLen for IterIntData<I>
{
fn altrep_len(&self) -> usize { self.state.len() }
}define_iter_data! {
233IterIntData, i32
249}
250
251impl<I: Iterator<Item = i32>> AltIntegerData for IterIntData<I> {
252 fn elt(&self, i: usize) -> i32 {
253 self.state
254 .get_element(i)
255 .unwrap_or(crate::altrep_traits::NA_INTEGER)
256 }
257
258 fn as_slice(&self) -> Option<&[i32]> {
259 self.state.as_materialized()
260 }
261}
262
263#[doc = r" Iterator-backed real (f64) vector data adaptor."]
#[doc = r""]
#[doc =
r" Wraps an iterator producing `f64` values and implements the data-level"]
#[doc =
r" traits ([`AltrepLen`] + [`AltRealData`]) for backing an ALTREP real vector."]
#[doc = r" To expose it to R, wrap it in a `#[derive(AltrepReal)]` +"]
#[doc =
r" `#[altrep(manual)]` struct (see the iterator module documentation)."]
pub struct IterRealData<I: Iterator<Item = f64>> {
state: super::IterState<I, f64>,
}
#[automatically_derived]
impl<I: ::core::clone::Clone + Iterator<Item = f64>> ::core::clone::Clone for
IterRealData<I> {
#[inline]
fn clone(&self) -> Self {
IterRealData { state: ::core::clone::Clone::clone(&self.state) }
}
}
impl<I: Iterator<Item = f64>> IterRealData<I> {
pub fn from_iter(iter: I, len: usize) -> Self {
Self { state: super::IterState::new(iter, len) }
}
}
impl<I: Iterator<Item = f64>> crate::altrep_data::AltrepSerialize for
IterRealData<I> {
fn serialized_state(&self) -> crate::SEXP {
match self.state.try_materialize_all() {
Ok(values) => crate::IntoR::into_sexp(values.to_vec()),
Err(_) => crate::SEXP::null(),
}
}
fn unserialize(state: crate::SEXP) -> Option<Self> {
let values =
<Vec<f64> as crate::TryFromSexp>::try_from_sexp(state).ok()?;
Some(Self { state: super::IterState::from_values(values) })
}
}
impl<I: ExactSizeIterator<Item = f64>> IterRealData<I> {
pub fn from_exact_iter(iter: I) -> Self {
let len = iter.len();
Self::from_iter(iter, len)
}
}
impl<I: Iterator<Item = f64>> crate::altrep_data::AltrepLen for
IterRealData<I> {
fn altrep_len(&self) -> usize { self.state.len() }
}define_iter_data! {
264IterRealData, f64
271}
272
273impl<I: Iterator<Item = f64>> AltRealData for IterRealData<I> {
274 fn elt(&self, i: usize) -> f64 {
275 self.state
276 .get_element(i)
277 .unwrap_or(crate::altrep_traits::NA_REAL)
278 }
279
280 fn as_slice(&self) -> Option<&[f64]> {
281 self.state.as_materialized()
282 }
283}
284
285#[doc = r" Iterator-backed logical vector data adaptor."]
#[doc = r""]
#[doc =
r" Wraps an iterator producing `bool` values and implements the data-level"]
#[doc =
r" traits ([`AltrepLen`] + [`AltLogicalData`]) for backing an ALTREP logical"]
#[doc =
r" vector. To expose it to R, wrap it in a `#[derive(AltrepLogical)]` +"]
#[doc =
r" `#[altrep(manual)]` struct (see the iterator module documentation)."]
pub struct IterLogicalData<I: Iterator<Item = bool>> {
state: super::IterState<I, bool>,
}
#[automatically_derived]
impl<I: ::core::clone::Clone + Iterator<Item = bool>> ::core::clone::Clone for
IterLogicalData<I> {
#[inline]
fn clone(&self) -> Self {
IterLogicalData { state: ::core::clone::Clone::clone(&self.state) }
}
}
impl<I: Iterator<Item = bool>> IterLogicalData<I> {
pub fn from_iter(iter: I, len: usize) -> Self {
Self { state: super::IterState::new(iter, len) }
}
}
impl<I: Iterator<Item = bool>> crate::altrep_data::AltrepSerialize for
IterLogicalData<I> {
fn serialized_state(&self) -> crate::SEXP {
match self.state.try_materialize_all() {
Ok(values) => crate::IntoR::into_sexp(values.to_vec()),
Err(_) => crate::SEXP::null(),
}
}
fn unserialize(state: crate::SEXP) -> Option<Self> {
let values =
<Vec<bool> as crate::TryFromSexp>::try_from_sexp(state).ok()?;
Some(Self { state: super::IterState::from_values(values) })
}
}
impl<I: ExactSizeIterator<Item = bool>> IterLogicalData<I> {
pub fn from_exact_iter(iter: I) -> Self {
let len = iter.len();
Self::from_iter(iter, len)
}
}
impl<I: Iterator<Item = bool>> crate::altrep_data::AltrepLen for
IterLogicalData<I> {
fn altrep_len(&self) -> usize { self.state.len() }
}define_iter_data! {
286IterLogicalData, bool
293}
294
295impl<I: Iterator<Item = bool>> AltLogicalData for IterLogicalData<I> {
296 fn elt(&self, i: usize) -> Logical {
297 self.state
298 .get_element(i)
299 .map(Logical::from_bool)
300 .unwrap_or(Logical::Na)
301 }
302}
303
304#[doc = r" Iterator-backed raw (u8) vector data adaptor."]
#[doc = r""]
#[doc =
r" Wraps an iterator producing `u8` values and implements the data-level"]
#[doc =
r" traits ([`AltrepLen`] + [`AltRawData`]) for backing an ALTREP raw vector."]
#[doc = r" To expose it to R, wrap it in a `#[derive(AltrepRaw)]` +"]
#[doc =
r" `#[altrep(manual)]` struct (see the iterator module documentation)."]
pub struct IterRawData<I: Iterator<Item = u8>> {
state: super::IterState<I, u8>,
}
#[automatically_derived]
impl<I: ::core::clone::Clone + Iterator<Item = u8>> ::core::clone::Clone for
IterRawData<I> {
#[inline]
fn clone(&self) -> Self {
IterRawData { state: ::core::clone::Clone::clone(&self.state) }
}
}
impl<I: Iterator<Item = u8>> IterRawData<I> {
pub fn from_iter(iter: I, len: usize) -> Self {
Self { state: super::IterState::new(iter, len) }
}
}
impl<I: Iterator<Item = u8>> crate::altrep_data::AltrepSerialize for
IterRawData<I> {
fn serialized_state(&self) -> crate::SEXP {
match self.state.try_materialize_all() {
Ok(values) => crate::IntoR::into_sexp(values.to_vec()),
Err(_) => crate::SEXP::null(),
}
}
fn unserialize(state: crate::SEXP) -> Option<Self> {
let values =
<Vec<u8> as crate::TryFromSexp>::try_from_sexp(state).ok()?;
Some(Self { state: super::IterState::from_values(values) })
}
}
impl<I: ExactSizeIterator<Item = u8>> IterRawData<I> {
pub fn from_exact_iter(iter: I) -> Self {
let len = iter.len();
Self::from_iter(iter, len)
}
}
impl<I: Iterator<Item = u8>> crate::altrep_data::AltrepLen for IterRawData<I>
{
fn altrep_len(&self) -> usize { self.state.len() }
}define_iter_data! {
305IterRawData, u8
312}
313
314impl<I: Iterator<Item = u8>> AltRawData for IterRawData<I> {
315 fn elt(&self, i: usize) -> u8 {
316 self.state.get_element(i).unwrap_or(0)
317 }
318
319 fn as_slice(&self) -> Option<&[u8]> {
320 self.state.as_materialized()
321 }
322}
323
324#[doc =
r" Iterator-backed logical data retaining R's native logical bit patterns."]
pub struct IterRLogicalData<I: Iterator<Item = crate::RLogical>> {
state: super::IterState<I, crate::RLogical>,
}
#[automatically_derived]
impl<I: ::core::clone::Clone + Iterator<Item = crate::RLogical>>
::core::clone::Clone for IterRLogicalData<I> {
#[inline]
fn clone(&self) -> Self {
IterRLogicalData { state: ::core::clone::Clone::clone(&self.state) }
}
}
impl<I: Iterator<Item = crate::RLogical>> IterRLogicalData<I> {
pub fn from_iter(iter: I, len: usize) -> Self {
Self { state: super::IterState::new(iter, len) }
}
}
impl<I: Iterator<Item = crate::RLogical>> crate::altrep_data::AltrepSerialize
for IterRLogicalData<I> {
fn serialized_state(&self) -> crate::SEXP {
match self.state.try_materialize_all() {
Ok(values) => crate::IntoR::into_sexp(values.to_vec()),
Err(_) => crate::SEXP::null(),
}
}
fn unserialize(state: crate::SEXP) -> Option<Self> {
let values =
<Vec<crate::RLogical> as
crate::TryFromSexp>::try_from_sexp(state).ok()?;
Some(Self { state: super::IterState::from_values(values) })
}
}
impl<I: ExactSizeIterator<Item = crate::RLogical>> IterRLogicalData<I> {
pub fn from_exact_iter(iter: I) -> Self {
let len = iter.len();
Self::from_iter(iter, len)
}
}
impl<I: Iterator<Item = crate::RLogical>> crate::altrep_data::AltrepLen for
IterRLogicalData<I> {
fn altrep_len(&self) -> usize { self.state.len() }
}define_iter_data! {
325IterRLogicalData, crate::RLogical
327}
328
329impl<I: Iterator<Item = crate::RLogical>> AltLogicalData for IterRLogicalData<I> {
330 fn elt(&self, i: usize) -> Logical {
331 self.state
332 .get_element(i)
333 .map(Logical::from)
334 .unwrap_or(Logical::Na)
335 }
336
337 fn as_r_slice(&self) -> Option<&[i32]> {
338 let values = self.state.as_materialized()?;
339 Some(unsafe { std::slice::from_raw_parts(values.as_ptr().cast(), values.len()) })
341 }
342
343 fn get_region(&self, start: usize, len: usize, out: &mut [i32]) -> usize {
344 crate::altrep_data::fill_region(start, len, self.altrep_len(), out, |i| {
345 self.state
346 .get_element(i)
347 .unwrap_or(crate::RLogical::NA)
348 .to_i32()
349 })
350 }
351}
352
353#[cfg(test)]
354mod tests {
355 use super::IterState;
356 use std::panic::{AssertUnwindSafe, catch_unwind};
357
358 #[test]
359 fn materialization_never_probes_past_the_declared_prefix() {
360 for len in [0, 3] {
361 let source = (0..len)
362 .map(|i| i.to_string())
363 .chain(std::iter::once_with(|| panic!("read beyond the prefix")));
364 let state = IterState::new(source, len);
365 let expected: Vec<_> = (0..len).map(|i| i.to_string()).collect();
366 assert_eq!(state.materialize_all(), expected);
367 assert_eq!(state.materialize_all(), expected);
368 }
369 }
370
371 #[test]
372 fn materialization_continues_after_a_cached_prefix() {
373 let source = (0..4).chain(std::iter::once_with(|| panic!("read beyond the prefix")));
374 let state = IterState::new(source, 4);
375 assert_eq!(state.get_element(1), Some(1));
376 assert_eq!(state.materialize_all(), [0, 1, 2, 3]);
377 }
378
379 #[test]
380 fn an_exhausted_source_is_never_polled_again() {
381 struct Flaky(u8);
383 impl Iterator for Flaky {
384 type Item = i32;
385 fn next(&mut self) -> Option<i32> {
386 self.0 += 1;
387 match self.0 {
388 1 => Some(0),
389 3 => Some(1),
390 _ => None,
391 }
392 }
393 }
394 let state = IterState::new(Flaky(0), 2);
395 assert_eq!(state.get_element(1), None);
396 assert_eq!(state.get_element(1), None);
397 assert_eq!(state.get_element(0), Some(0));
398 }
399
400 #[test]
401 fn early_exhaustion_never_publishes_a_partial_buffer() {
402 let state = IterState::new(0..2, 3);
403 for _ in 0..2 {
404 assert!(catch_unwind(AssertUnwindSafe(|| state.materialize_all())).is_err());
405 assert!(state.as_materialized().is_none());
406 assert_eq!(state.get_element(0), Some(0));
407 assert_eq!(state.get_element(2), None);
408 }
409 assert_eq!(state.try_materialize_all(), Err(2));
410 }
411
412 #[test]
413 fn clone_preserves_a_partial_prefix_without_advancing_the_source() {
414 let original = IterState::new(10..20i32, 6);
415 assert_eq!(original.get_element(2), Some(12));
416 let cloned = original.clone();
417 assert!(original.as_materialized().is_none());
418 assert!(cloned.as_materialized().is_none());
419 assert_eq!(cloned.materialize_all(), &[10, 11, 12, 13, 14, 15]);
420 assert!(original.as_materialized().is_none());
421 assert_eq!(original.get_element(3), Some(13));
422 assert_eq!(original.materialize_all(), cloned.materialize_all());
423 }
424
425 #[test]
426 fn restored_values_need_no_iterator_constructor() {
427 type Source = std::iter::Take<std::iter::Repeat<i32>>;
428 let restored = IterState::<Source, i32>::from_values(vec![4, 5, 6]);
429 assert_eq!(restored.len(), 3);
430 assert_eq!(restored.get_element(1), Some(5));
431 assert_eq!(restored.materialize_all(), &[4, 5, 6]);
432 }
433}