Skip to main content

miniextendr_api/altrep_data/iter/
sparse.rs

1//! Sparse iterator-backed ALTREP with skipping support.
2//!
3//! Provides `SparseIterState<I, T>` which uses `Iterator::nth()` to skip elements
4//! efficiently, and wrapper types for each ALTREP family.
5
6use std::cell::RefCell;
7use std::collections::BTreeMap;
8
9use crate::altrep_data::{
10    AltComplexData, AltIntegerData, AltLogicalData, AltRawData, AltRealData, AltrepLen, InferBase,
11    Logical, fill_region,
12};
13
14/// Core state for sparse iterator-backed ALTREP vectors.
15///
16/// Unlike [`super::IterState`], this variant uses `Iterator::nth()` to skip elements
17/// efficiently, only caching the elements that are actually accessed.
18///
19/// # Type Parameters
20///
21/// - `I`: The iterator type
22/// - `T`: The element type produced by the iterator
23///
24/// # Design
25///
26/// - **Sparse:** Only accessed elements are cached (uses `BTreeMap`)
27/// - **Skipping:** Uses `nth()` to skip directly to requested indices
28/// - **Trade-off:** Skipped elements are gone forever (iterator is consumed)
29/// - **Best for:** Large iterators where only a small subset of elements are accessed
30///
31/// # Comparison with `IterState`
32///
33/// | Feature | `IterState` | `SparseIterState` |
34/// |---------|-------------|-------------------|
35/// | Cache storage | Contiguous `Vec<T>` | Sparse `BTreeMap<usize, T>` |
36/// | Access pattern | Prefix (0..=i) cached | Only accessed indices cached |
37/// | Skipped elements | All cached | Gone forever (return NA) |
38/// | Memory for sparse access | O(max_index) | O(num_accessed) |
39/// | `as_slice()` support | Yes (after full materialization) | No (sparse) |
40///
41/// # Example
42///
43/// ```ignore
44/// use miniextendr_api::altrep_data::SparseIterIntData;
45///
46/// // Create from an infinite-ish iterator
47/// let data = SparseIterIntData::from_iter((0..).map(|x| x * 2), 1_000_000);
48///
49/// // Access only element 999_999 - skips directly there
50/// let last = data.elt(999_999);  // Only this element is generated
51///
52/// // Element 0 was skipped and is now inaccessible
53/// let first = data.elt(0);  // Returns NA_INTEGER
54/// ```
55pub struct SparseIterState<I, T> {
56    /// Vector length
57    len: usize,
58    /// Iterator state: (iterator, next index the iterator will produce)
59    iter: RefCell<Option<(I, usize)>>,
60    /// Sparse cache of accessed elements
61    cache: RefCell<BTreeMap<usize, T>>,
62}
63
64impl<I, T> SparseIterState<I, T>
65where
66    I: Iterator<Item = T>,
67{
68    /// Create a new sparse iterator state with an explicit length.
69    ///
70    /// # Arguments
71    ///
72    /// - `iter`: The iterator to wrap
73    /// - `len`: The expected number of elements
74    pub fn new(iter: I, len: usize) -> Self {
75        Self {
76            len,
77            iter: RefCell::new(Some((iter, 0))),
78            cache: RefCell::new(BTreeMap::new()),
79        }
80    }
81
82    /// Get an element, skipping intermediate elements if needed.
83    ///
84    /// Uses `Iterator::nth()` to skip efficiently. Skipped elements are
85    /// consumed from the iterator and cannot be retrieved later.
86    ///
87    /// # Returns
88    ///
89    /// - `Some(T)` if element exists and is accessible
90    /// - `None` if:
91    ///   - Index is out of bounds
92    ///   - Element was already skipped (iterator advanced past it)
93    ///   - Iterator exhausted before reaching the index
94    pub fn get_element(&self, i: usize) -> Option<T>
95    where
96        T: Copy,
97    {
98        // Check bounds
99        if i >= self.len {
100            return None;
101        }
102
103        // Check cache first
104        {
105            let cache = self.cache.borrow();
106            if let Some(&val) = cache.get(&i) {
107                return Some(val);
108            }
109        }
110
111        // Need to get from iterator
112        let mut iter_opt = self.iter.borrow_mut();
113        let (iter, pos) = iter_opt.as_mut()?;
114
115        // Element already passed? It was skipped.
116        if i < *pos {
117            return None;
118        }
119
120        // Skip to element i using nth()
121        let skip_count = i - *pos;
122        let elem = iter.nth(skip_count)?;
123        *pos = i + 1;
124
125        // Cache the element
126        drop(iter_opt);
127        self.cache.borrow_mut().insert(i, elem);
128
129        Some(elem)
130    }
131
132    /// Get the current iterator position (next index to be produced).
133    ///
134    /// Returns `None` if the iterator has been exhausted.
135    pub fn iterator_position(&self) -> Option<usize> {
136        self.iter.borrow().as_ref().map(|(_, pos)| *pos)
137    }
138
139    /// Check if an element has been cached.
140    pub fn is_cached(&self, i: usize) -> bool {
141        self.cache.borrow().contains_key(&i)
142    }
143
144    /// Get the number of cached elements.
145    pub fn cached_count(&self) -> usize {
146        self.cache.borrow().len()
147    }
148
149    /// Get the current length.
150    pub fn len(&self) -> usize {
151        self.len
152    }
153
154    /// Check if the vector is empty.
155    pub fn is_empty(&self) -> bool {
156        self.len == 0
157    }
158}
159
160impl<I, T> SparseIterState<I, T>
161where
162    I: ExactSizeIterator<Item = T>,
163{
164    /// Create a new sparse iterator state from an `ExactSizeIterator`.
165    pub fn from_exact_size(iter: I) -> Self {
166        let len = iter.len();
167        Self::new(iter, len)
168    }
169}
170
171/// Sparse iterator-backed integer vector data.
172///
173/// Uses `Iterator::nth()` to skip directly to requested indices.
174/// Only accessed elements are cached; skipped elements return `NA_INTEGER`.
175///
176/// # Example
177///
178/// ```ignore
179/// use miniextendr_api::altrep_data::SparseIterIntData;
180///
181/// // Access only specific elements from a large range
182/// let data = SparseIterIntData::from_iter(0..1_000_000, 1_000_000);
183/// let elem = data.elt(500_000);  // Skips 0..499_999
184/// ```
185pub struct SparseIterIntData<I: Iterator<Item = i32>> {
186    state: SparseIterState<I, i32>,
187}
188
189impl<I: Iterator<Item = i32>> SparseIterIntData<I> {
190    /// Create from an iterator with explicit length.
191    pub fn from_iter(iter: I, len: usize) -> Self {
192        Self {
193            state: SparseIterState::new(iter, len),
194        }
195    }
196}
197
198impl<I: ExactSizeIterator<Item = i32>> SparseIterIntData<I> {
199    /// Create from an ExactSizeIterator (length auto-detected).
200    pub fn from_exact_iter(iter: I) -> Self {
201        Self {
202            state: SparseIterState::from_exact_size(iter),
203        }
204    }
205}
206
207impl<I: Iterator<Item = i32>> AltrepLen for SparseIterIntData<I> {
208    fn len(&self) -> usize {
209        self.state.len()
210    }
211}
212
213impl<I: Iterator<Item = i32>> AltIntegerData for SparseIterIntData<I> {
214    fn elt(&self, i: usize) -> i32 {
215        self.state
216            .get_element(i)
217            .unwrap_or(crate::altrep_traits::NA_INTEGER)
218    }
219
220    fn as_slice(&self) -> Option<&[i32]> {
221        // Sparse storage cannot provide contiguous slice
222        None
223    }
224
225    fn get_region(&self, start: usize, len: usize, buf: &mut [i32]) -> usize {
226        fill_region(start, len, self.len(), buf, |idx| self.elt(idx))
227    }
228}
229
230impl<I: Iterator<Item = i32> + 'static> crate::externalptr::TypedExternal for SparseIterIntData<I> {
231    const TYPE_NAME: &'static str = "SparseIterIntData";
232    const TYPE_NAME_CSTR: &'static [u8] = b"SparseIterIntData\0";
233    const TYPE_ID_CSTR: &'static [u8] = b"miniextendr_api::altrep::SparseIterIntData\0";
234}
235
236impl<I: Iterator<Item = i32> + 'static> InferBase for SparseIterIntData<I> {
237    const BASE: crate::altrep::RBase = crate::altrep::RBase::Int;
238
239    unsafe fn make_class(
240        class_name: *const i8,
241        pkg_name: *const i8,
242    ) -> crate::ffi::altrep::R_altrep_class_t {
243        unsafe {
244            crate::ffi::altrep::R_make_altinteger_class(class_name, pkg_name, core::ptr::null_mut())
245        }
246    }
247
248    unsafe fn install_methods(cls: crate::ffi::altrep::R_altrep_class_t) {
249        unsafe { crate::altrep_bridge::install_base::<Self>(cls) };
250        unsafe { crate::altrep_bridge::install_vec::<Self>(cls) };
251        unsafe { crate::altrep_bridge::install_int::<Self>(cls) };
252    }
253}
254
255impl<I: Iterator<Item = i32> + 'static> crate::altrep_traits::Altrep for SparseIterIntData<I> {
256    fn length(x: crate::ffi::SEXP) -> crate::ffi::R_xlen_t {
257        let data = unsafe { <Self as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
258        data.len() as crate::ffi::R_xlen_t
259    }
260}
261
262impl<I: Iterator<Item = i32> + 'static> crate::altrep_traits::AltVec for SparseIterIntData<I> {}
263
264impl<I: Iterator<Item = i32> + 'static> crate::altrep_traits::AltInteger for SparseIterIntData<I> {
265    const HAS_ELT: bool = true;
266
267    fn elt(x: crate::ffi::SEXP, i: crate::ffi::R_xlen_t) -> i32 {
268        let data = unsafe { <Self as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
269        AltIntegerData::elt(data, i as usize)
270    }
271
272    const HAS_GET_REGION: bool = true;
273
274    fn get_region(
275        x: crate::ffi::SEXP,
276        start: crate::ffi::R_xlen_t,
277        len: crate::ffi::R_xlen_t,
278        buf: &mut [i32],
279    ) -> crate::ffi::R_xlen_t {
280        let data = unsafe { <Self as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
281        AltIntegerData::get_region(data, start as usize, len as usize, buf) as crate::ffi::R_xlen_t
282    }
283}
284
285/// Sparse iterator-backed real (f64) vector data.
286///
287/// Uses `Iterator::nth()` to skip directly to requested indices.
288/// Only accessed elements are cached; skipped elements return `NaN`.
289pub struct SparseIterRealData<I: Iterator<Item = f64>> {
290    state: SparseIterState<I, f64>,
291}
292
293impl<I: Iterator<Item = f64>> SparseIterRealData<I> {
294    /// Create from an iterator with explicit length.
295    pub fn from_iter(iter: I, len: usize) -> Self {
296        Self {
297            state: SparseIterState::new(iter, len),
298        }
299    }
300}
301
302impl<I: ExactSizeIterator<Item = f64>> SparseIterRealData<I> {
303    /// Create from an ExactSizeIterator (length auto-detected).
304    pub fn from_exact_iter(iter: I) -> Self {
305        Self {
306            state: SparseIterState::from_exact_size(iter),
307        }
308    }
309}
310
311impl<I: Iterator<Item = f64>> AltrepLen for SparseIterRealData<I> {
312    fn len(&self) -> usize {
313        self.state.len()
314    }
315}
316
317impl<I: Iterator<Item = f64>> AltRealData for SparseIterRealData<I> {
318    fn elt(&self, i: usize) -> f64 {
319        self.state.get_element(i).unwrap_or(f64::NAN)
320    }
321
322    fn as_slice(&self) -> Option<&[f64]> {
323        None
324    }
325
326    fn get_region(&self, start: usize, len: usize, buf: &mut [f64]) -> usize {
327        fill_region(start, len, self.len(), buf, |idx| self.elt(idx))
328    }
329}
330
331impl<I: Iterator<Item = f64> + 'static> crate::externalptr::TypedExternal
332    for SparseIterRealData<I>
333{
334    const TYPE_NAME: &'static str = "SparseIterRealData";
335    const TYPE_NAME_CSTR: &'static [u8] = b"SparseIterRealData\0";
336    const TYPE_ID_CSTR: &'static [u8] = b"miniextendr_api::altrep::SparseIterRealData\0";
337}
338
339impl<I: Iterator<Item = f64> + 'static> InferBase for SparseIterRealData<I> {
340    const BASE: crate::altrep::RBase = crate::altrep::RBase::Real;
341
342    unsafe fn make_class(
343        class_name: *const i8,
344        pkg_name: *const i8,
345    ) -> crate::ffi::altrep::R_altrep_class_t {
346        unsafe {
347            crate::ffi::altrep::R_make_altreal_class(class_name, pkg_name, core::ptr::null_mut())
348        }
349    }
350
351    unsafe fn install_methods(cls: crate::ffi::altrep::R_altrep_class_t) {
352        unsafe { crate::altrep_bridge::install_base::<Self>(cls) };
353        unsafe { crate::altrep_bridge::install_vec::<Self>(cls) };
354        unsafe { crate::altrep_bridge::install_real::<Self>(cls) };
355    }
356}
357
358impl<I: Iterator<Item = f64> + 'static> crate::altrep_traits::Altrep for SparseIterRealData<I> {
359    fn length(x: crate::ffi::SEXP) -> crate::ffi::R_xlen_t {
360        let data = unsafe { <Self as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
361        data.len() as crate::ffi::R_xlen_t
362    }
363}
364
365impl<I: Iterator<Item = f64> + 'static> crate::altrep_traits::AltVec for SparseIterRealData<I> {}
366
367impl<I: Iterator<Item = f64> + 'static> crate::altrep_traits::AltReal for SparseIterRealData<I> {
368    const HAS_ELT: bool = true;
369
370    fn elt(x: crate::ffi::SEXP, i: crate::ffi::R_xlen_t) -> f64 {
371        let data = unsafe { <Self as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
372        AltRealData::elt(data, i as usize)
373    }
374
375    const HAS_GET_REGION: bool = true;
376
377    fn get_region(
378        x: crate::ffi::SEXP,
379        start: crate::ffi::R_xlen_t,
380        len: crate::ffi::R_xlen_t,
381        buf: &mut [f64],
382    ) -> crate::ffi::R_xlen_t {
383        let data = unsafe { <Self as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
384        AltRealData::get_region(data, start as usize, len as usize, buf) as crate::ffi::R_xlen_t
385    }
386}
387
388/// Sparse iterator-backed logical vector data.
389pub struct SparseIterLogicalData<I: Iterator<Item = bool>> {
390    state: SparseIterState<I, bool>,
391}
392
393impl<I: Iterator<Item = bool>> SparseIterLogicalData<I> {
394    /// Create from an iterator with explicit length.
395    pub fn from_iter(iter: I, len: usize) -> Self {
396        Self {
397            state: SparseIterState::new(iter, len),
398        }
399    }
400}
401
402impl<I: ExactSizeIterator<Item = bool>> SparseIterLogicalData<I> {
403    /// Create from an ExactSizeIterator (length auto-detected).
404    pub fn from_exact_iter(iter: I) -> Self {
405        Self {
406            state: SparseIterState::from_exact_size(iter),
407        }
408    }
409}
410
411impl<I: Iterator<Item = bool>> AltrepLen for SparseIterLogicalData<I> {
412    fn len(&self) -> usize {
413        self.state.len()
414    }
415}
416
417impl<I: Iterator<Item = bool>> AltLogicalData for SparseIterLogicalData<I> {
418    fn elt(&self, i: usize) -> Logical {
419        self.state
420            .get_element(i)
421            .map(Logical::from_bool)
422            .unwrap_or(Logical::Na)
423    }
424
425    fn get_region(&self, start: usize, len: usize, buf: &mut [i32]) -> usize {
426        fill_region(start, len, self.len(), buf, |idx| self.elt(idx).to_r_int())
427    }
428}
429
430impl<I: Iterator<Item = bool> + 'static> crate::externalptr::TypedExternal
431    for SparseIterLogicalData<I>
432{
433    const TYPE_NAME: &'static str = "SparseIterLogicalData";
434    const TYPE_NAME_CSTR: &'static [u8] = b"SparseIterLogicalData\0";
435    const TYPE_ID_CSTR: &'static [u8] = b"miniextendr_api::altrep::SparseIterLogicalData\0";
436}
437
438impl<I: Iterator<Item = bool> + 'static> InferBase for SparseIterLogicalData<I> {
439    const BASE: crate::altrep::RBase = crate::altrep::RBase::Logical;
440
441    unsafe fn make_class(
442        class_name: *const i8,
443        pkg_name: *const i8,
444    ) -> crate::ffi::altrep::R_altrep_class_t {
445        unsafe {
446            crate::ffi::altrep::R_make_altlogical_class(class_name, pkg_name, core::ptr::null_mut())
447        }
448    }
449
450    unsafe fn install_methods(cls: crate::ffi::altrep::R_altrep_class_t) {
451        unsafe { crate::altrep_bridge::install_base::<Self>(cls) };
452        unsafe { crate::altrep_bridge::install_vec::<Self>(cls) };
453        unsafe { crate::altrep_bridge::install_lgl::<Self>(cls) };
454    }
455}
456
457impl<I: Iterator<Item = bool> + 'static> crate::altrep_traits::Altrep for SparseIterLogicalData<I> {
458    fn length(x: crate::ffi::SEXP) -> crate::ffi::R_xlen_t {
459        let data = unsafe { <Self as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
460        data.len() as crate::ffi::R_xlen_t
461    }
462}
463
464impl<I: Iterator<Item = bool> + 'static> crate::altrep_traits::AltVec for SparseIterLogicalData<I> {}
465
466impl<I: Iterator<Item = bool> + 'static> crate::altrep_traits::AltLogical
467    for SparseIterLogicalData<I>
468{
469    const HAS_ELT: bool = true;
470
471    fn elt(x: crate::ffi::SEXP, i: crate::ffi::R_xlen_t) -> i32 {
472        let data = unsafe { <Self as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
473        AltLogicalData::elt(data, i as usize).to_r_int()
474    }
475
476    const HAS_GET_REGION: bool = true;
477
478    fn get_region(
479        x: crate::ffi::SEXP,
480        start: crate::ffi::R_xlen_t,
481        len: crate::ffi::R_xlen_t,
482        buf: &mut [i32],
483    ) -> crate::ffi::R_xlen_t {
484        let data = unsafe { <Self as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
485        AltLogicalData::get_region(data, start as usize, len as usize, buf) as crate::ffi::R_xlen_t
486    }
487}
488
489/// Sparse iterator-backed raw (u8) vector data.
490pub struct SparseIterRawData<I: Iterator<Item = u8>> {
491    state: SparseIterState<I, u8>,
492}
493
494impl<I: Iterator<Item = u8>> SparseIterRawData<I> {
495    /// Create from an iterator with explicit length.
496    pub fn from_iter(iter: I, len: usize) -> Self {
497        Self {
498            state: SparseIterState::new(iter, len),
499        }
500    }
501}
502
503impl<I: ExactSizeIterator<Item = u8>> SparseIterRawData<I> {
504    /// Create from an ExactSizeIterator (length auto-detected).
505    pub fn from_exact_iter(iter: I) -> Self {
506        Self {
507            state: SparseIterState::from_exact_size(iter),
508        }
509    }
510}
511
512impl<I: Iterator<Item = u8>> AltrepLen for SparseIterRawData<I> {
513    fn len(&self) -> usize {
514        self.state.len()
515    }
516}
517
518impl<I: Iterator<Item = u8>> AltRawData for SparseIterRawData<I> {
519    fn elt(&self, i: usize) -> u8 {
520        self.state.get_element(i).unwrap_or(0)
521    }
522
523    fn as_slice(&self) -> Option<&[u8]> {
524        None
525    }
526
527    fn get_region(&self, start: usize, len: usize, buf: &mut [u8]) -> usize {
528        fill_region(start, len, self.len(), buf, |idx| self.elt(idx))
529    }
530}
531
532impl<I: Iterator<Item = u8> + 'static> crate::externalptr::TypedExternal for SparseIterRawData<I> {
533    const TYPE_NAME: &'static str = "SparseIterRawData";
534    const TYPE_NAME_CSTR: &'static [u8] = b"SparseIterRawData\0";
535    const TYPE_ID_CSTR: &'static [u8] = b"miniextendr_api::altrep::SparseIterRawData\0";
536}
537
538impl<I: Iterator<Item = u8> + 'static> InferBase for SparseIterRawData<I> {
539    const BASE: crate::altrep::RBase = crate::altrep::RBase::Raw;
540
541    unsafe fn make_class(
542        class_name: *const i8,
543        pkg_name: *const i8,
544    ) -> crate::ffi::altrep::R_altrep_class_t {
545        unsafe {
546            crate::ffi::altrep::R_make_altraw_class(class_name, pkg_name, core::ptr::null_mut())
547        }
548    }
549
550    unsafe fn install_methods(cls: crate::ffi::altrep::R_altrep_class_t) {
551        unsafe { crate::altrep_bridge::install_base::<Self>(cls) };
552        unsafe { crate::altrep_bridge::install_vec::<Self>(cls) };
553        unsafe { crate::altrep_bridge::install_raw::<Self>(cls) };
554    }
555}
556
557impl<I: Iterator<Item = u8> + 'static> crate::altrep_traits::Altrep for SparseIterRawData<I> {
558    fn length(x: crate::ffi::SEXP) -> crate::ffi::R_xlen_t {
559        let data = unsafe { <Self as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
560        data.len() as crate::ffi::R_xlen_t
561    }
562}
563
564impl<I: Iterator<Item = u8> + 'static> crate::altrep_traits::AltVec for SparseIterRawData<I> {}
565
566impl<I: Iterator<Item = u8> + 'static> crate::altrep_traits::AltRaw for SparseIterRawData<I> {
567    const HAS_ELT: bool = true;
568
569    fn elt(x: crate::ffi::SEXP, i: crate::ffi::R_xlen_t) -> u8 {
570        let data = unsafe { <Self as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
571        AltRawData::elt(data, i as usize)
572    }
573
574    const HAS_GET_REGION: bool = true;
575
576    fn get_region(
577        x: crate::ffi::SEXP,
578        start: crate::ffi::R_xlen_t,
579        len: crate::ffi::R_xlen_t,
580        buf: &mut [u8],
581    ) -> crate::ffi::R_xlen_t {
582        let data = unsafe { <Self as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
583        AltRawData::get_region(data, start as usize, len as usize, buf) as crate::ffi::R_xlen_t
584    }
585}
586
587/// Sparse iterator-backed complex number vector.
588pub struct SparseIterComplexData<I>
589where
590    I: Iterator<Item = crate::ffi::Rcomplex>,
591{
592    state: SparseIterState<I, crate::ffi::Rcomplex>,
593}
594
595impl<I> SparseIterComplexData<I>
596where
597    I: Iterator<Item = crate::ffi::Rcomplex>,
598{
599    /// Create from an iterator with explicit length.
600    pub fn from_iter(iter: I, len: usize) -> Self {
601        Self {
602            state: SparseIterState::new(iter, len),
603        }
604    }
605}
606
607impl<I> SparseIterComplexData<I>
608where
609    I: ExactSizeIterator<Item = crate::ffi::Rcomplex>,
610{
611    /// Create from an ExactSizeIterator (length auto-detected).
612    pub fn from_exact_iter(iter: I) -> Self {
613        Self {
614            state: SparseIterState::from_exact_size(iter),
615        }
616    }
617}
618
619impl<I> AltrepLen for SparseIterComplexData<I>
620where
621    I: Iterator<Item = crate::ffi::Rcomplex>,
622{
623    fn len(&self) -> usize {
624        self.state.len()
625    }
626}
627
628impl<I> AltComplexData for SparseIterComplexData<I>
629where
630    I: Iterator<Item = crate::ffi::Rcomplex>,
631{
632    fn elt(&self, i: usize) -> crate::ffi::Rcomplex {
633        self.state.get_element(i).unwrap_or(crate::ffi::Rcomplex {
634            r: f64::NAN,
635            i: f64::NAN,
636        })
637    }
638
639    fn as_slice(&self) -> Option<&[crate::ffi::Rcomplex]> {
640        None
641    }
642
643    fn get_region(&self, start: usize, len: usize, buf: &mut [crate::ffi::Rcomplex]) -> usize {
644        fill_region(start, len, self.len(), buf, |idx| self.elt(idx))
645    }
646}
647
648impl<I: Iterator<Item = crate::ffi::Rcomplex> + 'static> crate::externalptr::TypedExternal
649    for SparseIterComplexData<I>
650{
651    const TYPE_NAME: &'static str = "SparseIterComplexData";
652    const TYPE_NAME_CSTR: &'static [u8] = b"SparseIterComplexData\0";
653    const TYPE_ID_CSTR: &'static [u8] = b"miniextendr_api::altrep::SparseIterComplexData\0";
654}
655
656impl<I: Iterator<Item = crate::ffi::Rcomplex> + 'static> InferBase for SparseIterComplexData<I> {
657    const BASE: crate::altrep::RBase = crate::altrep::RBase::Complex;
658
659    unsafe fn make_class(
660        class_name: *const i8,
661        pkg_name: *const i8,
662    ) -> crate::ffi::altrep::R_altrep_class_t {
663        unsafe {
664            crate::ffi::altrep::R_make_altcomplex_class(class_name, pkg_name, core::ptr::null_mut())
665        }
666    }
667
668    unsafe fn install_methods(cls: crate::ffi::altrep::R_altrep_class_t) {
669        unsafe { crate::altrep_bridge::install_base::<Self>(cls) };
670        unsafe { crate::altrep_bridge::install_vec::<Self>(cls) };
671        unsafe { crate::altrep_bridge::install_cplx::<Self>(cls) };
672    }
673}
674
675impl<I: Iterator<Item = crate::ffi::Rcomplex> + 'static> crate::altrep_traits::Altrep
676    for SparseIterComplexData<I>
677{
678    fn length(x: crate::ffi::SEXP) -> crate::ffi::R_xlen_t {
679        let data = unsafe { <Self as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
680        data.len() as crate::ffi::R_xlen_t
681    }
682}
683
684impl<I: Iterator<Item = crate::ffi::Rcomplex> + 'static> crate::altrep_traits::AltVec
685    for SparseIterComplexData<I>
686{
687}
688
689impl<I: Iterator<Item = crate::ffi::Rcomplex> + 'static> crate::altrep_traits::AltComplex
690    for SparseIterComplexData<I>
691{
692    const HAS_ELT: bool = true;
693
694    fn elt(x: crate::ffi::SEXP, i: crate::ffi::R_xlen_t) -> crate::ffi::Rcomplex {
695        let data = unsafe { <Self as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
696        AltComplexData::elt(data, i as usize)
697    }
698
699    const HAS_GET_REGION: bool = true;
700
701    fn get_region(
702        x: crate::ffi::SEXP,
703        start: crate::ffi::R_xlen_t,
704        len: crate::ffi::R_xlen_t,
705        buf: &mut [crate::ffi::Rcomplex],
706    ) -> crate::ffi::R_xlen_t {
707        let data = unsafe { <Self as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
708        AltComplexData::get_region(data, start as usize, len as usize, buf) as crate::ffi::R_xlen_t
709    }
710}
711// endregion