extendr_api/wrapper/
altrep.rs

1use super::*;
2use extendr_ffi::*;
3use prelude::{Rbool, Rcplx, Rfloat, Rint, Scalar};
4
5macro_rules! make_from_iterator_impl {
6    ($impl : ident, $scalar_type : ident) => {
7        impl<Iter: ExactSizeIterator + std::fmt::Debug + Clone> $impl for Iter
8        where
9            Iter::Item: Into<$scalar_type>,
10        {
11            fn elt(&self, index: usize) -> $scalar_type {
12                $scalar_type::from(self.clone().nth(index).unwrap().into())
13            }
14
15            fn get_region(&self, index: usize, data: &mut [$scalar_type]) -> usize {
16                let len = self.len();
17                if index > len {
18                    0
19                } else {
20                    let mut iter = self.clone().skip(index);
21                    let num_elems = data.len().min(len - index);
22                    let dest = &mut data[0..num_elems];
23                    for d in dest.iter_mut() {
24                        *d = $scalar_type::from(iter.next().unwrap().into());
25                    }
26                    num_elems
27                }
28            }
29        }
30    };
31}
32
33macro_rules! make_from_iterator {
34    ($fn_name : ident, $make_class : ident, $impl : ident, $scalar_type : ident, $prim_type : ty) => {
35        pub fn $fn_name<Iter>(iter: Iter) -> Altrep
36        where
37            Iter: ExactSizeIterator + std::fmt::Debug + Clone + 'static + std::any::Any,
38            Iter::Item: Into<$scalar_type>,
39        {
40            let class = Altrep::$make_class::<Iter>(std::any::type_name::<Iter>(), "extendr");
41            let robj: Robj = Altrep::from_state_and_class(iter, class, false).into();
42            Altrep { robj }
43        }
44    };
45}
46
47#[derive(PartialEq, Clone)]
48pub struct Altrep {
49    pub(crate) robj: Robj,
50}
51
52/// Rust trait for implementing ALTREP.
53/// Implement one or more of these methods to generate an Altrep class.
54/// This is likely to be unstable for a while.
55pub trait AltrepImpl: Clone + std::fmt::Debug {
56    #[cfg(feature = "non-api")]
57    /// Constructor that is called when loading an Altrep object from a file.
58    ///
59    /// # Safety
60    ///
61    /// Access to a raw SEXP pointer can cause undefined behaviour and is not thread safe.
62    /// Note that we use a thread lock to ensure this doesn't occur.
63    unsafe fn unserialize_ex(
64        class: Robj,
65        state: Robj,
66        attributes: Robj,
67        obj_flags: i32,
68        levels: i32,
69    ) -> Robj {
70        use extendr_ffi::{SETLEVELS, SET_ATTRIB, SET_OBJECT};
71        let res = Self::unserialize(class, state);
72        if !res.is_null() {
73            single_threaded(|| unsafe {
74                let val = res.get();
75                SET_ATTRIB(val, attributes.get());
76                SET_OBJECT(val, obj_flags);
77                SETLEVELS(val, levels);
78            })
79        }
80        res
81    }
82
83    /// Simplified constructor that is called when loading an Altrep object from a file.
84    fn unserialize(_class: Robj, _state: Robj) -> Robj {
85        // We plan to hadle this via Serde by November.
86        ().into()
87    }
88
89    /// Fetch the state of this object when writing to a file.
90    fn serialized_state(_x: SEXP) -> Robj {
91        // We plan to hadle this via Serde by November.
92        ().into()
93    }
94
95    /// Duplicate this object, possibly duplicating attributes.
96    /// Currently this manifests the array but preserves the original object.
97    fn duplicate_ex(x: SEXP, deep: bool) -> Robj {
98        Self::duplicate(x, deep)
99    }
100
101    /// Duplicate this object. Called by Rf_duplicate.
102    /// Currently this manifests the array but preserves the original object.
103    fn duplicate(x: SEXP, _deep: bool) -> Robj {
104        unsafe { Robj::from_sexp(manifest(x)) }
105    }
106
107    /// Coerce this object into some other type, if possible.
108    fn coerce(_x: SEXP, _ty: Rtype) -> Robj {
109        ().into()
110    }
111
112    /// Print the text for .Internal(inspect(obj))
113    fn inspect(
114        &self,
115        _pre: i32,
116        _deep: bool,
117        _pvec: i32, // _inspect_subtree: fn(robj: Robj, pre: i32, deep: i32, pvec: i32),
118    ) -> bool {
119        rprintln!("{:?}", self);
120        true
121    }
122
123    /// Get the virtual length of the vector.
124    /// For example for a compact range, return end - start + 1.
125    fn length(&self) -> usize;
126
127    /// Get the data pointer for this vector, possibly expanding the
128    /// compact representation into a full R vector.
129    ///
130    /// # Safety
131    ///
132    /// This function dereferences a raw SEXP pointer.
133    /// The caller must ensure that `x` is a valid SEXP pointer.
134    unsafe fn dataptr(x: SEXP, _writeable: bool) -> *mut u8 {
135        single_threaded(|| unsafe {
136            let data2 = R_altrep_data2(x);
137            if data2 == R_NilValue || TYPEOF(data2) != TYPEOF(x) {
138                let data2 = manifest(x);
139                R_set_altrep_data2(x, data2);
140                dataptr(data2) as *mut u8
141            } else {
142                dataptr(data2) as *mut u8
143            }
144        })
145    }
146
147    /// Get the data pointer for this vector, returning NULL
148    /// if the object is unmaterialized.
149    ///
150    /// # Safety
151    ///
152    /// This function dereferences a raw SEXP pointer.
153    /// The caller must ensure that `x` is a valid SEXP pointer.
154    unsafe fn dataptr_or_null(x: SEXP) -> *const u8 {
155        unsafe {
156            let data2 = R_altrep_data2(x);
157            if data2 == R_NilValue || TYPEOF(data2) != TYPEOF(x) {
158                std::ptr::null()
159            } else {
160                dataptr(data2) as *const u8
161            }
162        }
163    }
164
165    /// Implement subsetting (eg. `x[10:19]`) for this Altrep vector.
166    fn extract_subset(_x: Robj, _indx: Robj, _call: Robj) -> Robj {
167        // only available in later versions of R.
168        // x.extract_subset(indx, call)
169        Robj::from(())
170    }
171}
172
173// Manifest a vector by storing the "elt" values to memory.
174// Return the new vector.
175fn manifest(x: SEXP) -> SEXP {
176    single_threaded(|| unsafe {
177        Rf_protect(x);
178        let len = XLENGTH(x);
179        let data2 = Rf_allocVector(TYPEOF(x), len as R_xlen_t);
180        Rf_protect(data2);
181        match TYPEOF(x) {
182            SEXPTYPE::INTSXP => {
183                INTEGER_GET_REGION(x, 0, len as R_xlen_t, INTEGER(data2));
184            }
185            SEXPTYPE::LGLSXP => {
186                LOGICAL_GET_REGION(x, 0, len as R_xlen_t, LOGICAL(data2));
187            }
188            SEXPTYPE::REALSXP => {
189                REAL_GET_REGION(x, 0, len as R_xlen_t, REAL(data2));
190            }
191            SEXPTYPE::RAWSXP => {
192                RAW_GET_REGION(x, 0, len as R_xlen_t, RAW(data2));
193            }
194            SEXPTYPE::CPLXSXP => {
195                COMPLEX_GET_REGION(x, 0, len as R_xlen_t, COMPLEX(data2));
196            }
197            _ => {
198                Rf_unprotect(2);
199                panic!("unsupported ALTREP type.")
200            }
201        };
202        Rf_unprotect(2);
203        data2
204    })
205}
206
207pub trait AltIntegerImpl: AltrepImpl {
208    fn tot_min_max_nas(&self) -> (i64, i32, i32, usize, usize) {
209        let len = self.length();
210        let mut tot = 0;
211        let mut nas = 0;
212        let mut min = i32::MAX;
213        let mut max = i32::MIN;
214        for i in 0..len {
215            let val = self.elt(i);
216            if !val.is_na() {
217                tot += val.inner() as i64;
218                min = min.min(val.inner());
219                max = max.max(val.inner());
220                nas += 1;
221            }
222        }
223        (tot, min, max, len - nas, len)
224    }
225
226    /// Get a single element from this vector.
227    fn elt(&self, _index: usize) -> Rint;
228
229    /// Get a multiple elements from this vector.
230    fn get_region(&self, index: usize, data: &mut [Rint]) -> usize {
231        let len = self.length();
232        if index > len {
233            0
234        } else {
235            let num_elems = data.len().min(len - index);
236            let dest = &mut data[0..num_elems];
237            for (i, d) in dest.iter_mut().enumerate() {
238                *d = self.elt(i + index);
239            }
240            num_elems
241        }
242    }
243
244    /// Return TRUE if this vector is sorted, FALSE if not and Rbool::na() if unknown.
245    fn is_sorted(&self) -> Rbool {
246        Rbool::na()
247    }
248
249    /// Return true if this vector does not contain NAs.
250    fn no_na(&self) -> bool {
251        false
252    }
253
254    /// Return the sum of the elements in this vector.
255    /// If remove_nas is true, skip and NA values.
256    fn sum(&self, remove_nas: bool) -> Robj {
257        let (tot, _min, _max, nas, _len) = self.tot_min_max_nas();
258        if !remove_nas && nas != 0 {
259            NA_INTEGER.into()
260        } else {
261            tot.into()
262        }
263    }
264
265    /// Return the minimum of the elements in this vector.
266    /// If remove_nas is true, skip and NA values.
267    fn min(&self, remove_nas: bool) -> Robj {
268        let (_tot, min, _max, nas, len) = self.tot_min_max_nas();
269        if !remove_nas && nas != 0 || remove_nas && nas == len {
270            NA_INTEGER.into()
271        } else {
272            min.into()
273        }
274    }
275
276    /// Return the maximum of the elements in this vector.
277    /// If remove_nas is true, skip and NA values.
278    fn max(&self, remove_nas: bool) -> Robj {
279        let (_tot, _min, max, nas, len) = self.tot_min_max_nas();
280        if !remove_nas && nas != 0 || remove_nas && nas == len {
281            NA_INTEGER.into()
282        } else {
283            max.into()
284        }
285    }
286}
287
288pub trait AltRealImpl: AltrepImpl {
289    fn tot_min_max_nas(&self) -> (f64, f64, f64, usize, usize) {
290        let len = self.length();
291        let mut tot = 0.0;
292        let mut nas = 0;
293        let mut min = f64::MAX;
294        let mut max = f64::MIN;
295        for i in 0..len {
296            let val = self.elt(i);
297            if !val.is_na() {
298                tot += val.inner();
299                min = min.min(val.inner());
300                max = max.max(val.inner());
301                nas += 1;
302            }
303        }
304        (tot, min, max, len - nas, len)
305    }
306
307    /// Get a single element from this vector.
308    fn elt(&self, _index: usize) -> Rfloat;
309
310    /// Get a multiple elements from this vector.
311    fn get_region(&self, index: usize, data: &mut [Rfloat]) -> usize {
312        let len = self.length();
313        if index > len {
314            0
315        } else {
316            let num_elems = data.len().min(len - index);
317            let dest = &mut data[0..num_elems];
318            for (i, d) in dest.iter_mut().enumerate() {
319                *d = self.elt(i + index);
320            }
321            num_elems
322        }
323    }
324
325    /// Return TRUE if this vector is sorted, FALSE if not and Rbool::na() if unknown.
326    fn is_sorted(&self) -> Rbool {
327        Rbool::na()
328    }
329
330    /// Return true if this vector does not contain NAs.
331    fn no_na(&self) -> bool {
332        false
333    }
334
335    /// Return the sum of the elements in this vector.
336    /// If remove_nas is true, skip and NA values.
337    fn sum(&self, remove_nas: bool) -> Robj {
338        let (tot, _min, _max, nas, _len) = self.tot_min_max_nas();
339        if !remove_nas && nas != 0 {
340            NA_REAL.into()
341        } else {
342            tot.into()
343        }
344    }
345
346    /// Return the minimum of the elements in this vector.
347    /// If remove_nas is true, skip and NA values.
348    fn min(&self, remove_nas: bool) -> Robj {
349        let (_tot, min, _max, nas, len) = self.tot_min_max_nas();
350        if !remove_nas && nas != 0 || remove_nas && nas == len {
351            NA_REAL.into()
352        } else {
353            min.into()
354        }
355    }
356
357    /// Return the maximum of the elements in this vector.
358    /// If remove_nas is true, skip and NA values.
359    fn max(&self, remove_nas: bool) -> Robj {
360        let (_tot, _min, max, nas, len) = self.tot_min_max_nas();
361        if !remove_nas && nas != 0 || remove_nas && nas == len {
362            NA_REAL.into()
363        } else {
364            max.into()
365        }
366    }
367}
368
369pub trait AltLogicalImpl: AltrepImpl {
370    fn tot_min_max_nas(&self) -> (i64, i32, i32, usize, usize) {
371        let len = self.length();
372        let mut tot = 0;
373        let mut nas = 0;
374        for i in 0..len {
375            let val = self.elt(i);
376            if !val.is_na() {
377                tot += val.inner() as i64;
378                nas += 1;
379            }
380        }
381        (tot, 0, 0, len - nas, len)
382    }
383
384    /// Get a single element from this vector.
385    fn elt(&self, _index: usize) -> Rbool;
386
387    /// Get a multiple elements from this vector.
388    fn get_region(&self, index: usize, data: &mut [Rbool]) -> usize {
389        let len = self.length();
390        if index > len {
391            0
392        } else {
393            let num_elems = data.len().min(len - index);
394            let dest = &mut data[0..num_elems];
395            for (i, d) in dest.iter_mut().enumerate() {
396                *d = self.elt(i + index);
397            }
398            num_elems
399        }
400    }
401
402    /// Return TRUE if this vector is sorted, FALSE if not and Rbool::na() if unknown.
403    fn is_sorted(&self) -> Rbool {
404        Rbool::na()
405    }
406
407    /// Return true if this vector does not contain NAs.
408    fn no_na(&self) -> bool {
409        false
410    }
411
412    /// Return the sum of the elements in this vector.
413    /// If remove_nas is true, skip and NA values.
414    fn sum(&self, remove_nas: bool) -> Robj {
415        let (tot, _min, _max, nas, len) = self.tot_min_max_nas();
416        if !remove_nas && nas != 0 || remove_nas && nas == len {
417            Rbool::na().into()
418        } else {
419            tot.into()
420        }
421    }
422}
423
424pub trait AltRawImpl: AltrepImpl {
425    /// Get a single element from this vector.
426    fn elt(&self, _index: usize) -> u8;
427
428    /// Get a multiple elements from this vector.
429    fn get_region(&self, index: usize, data: &mut [u8]) -> usize {
430        let len = self.length();
431        if index > len {
432            0
433        } else {
434            let num_elems = data.len().min(len - index);
435            let dest = &mut data[0..num_elems];
436            for (i, d) in dest.iter_mut().enumerate() {
437                *d = self.elt(i + index);
438            }
439            num_elems
440        }
441    }
442}
443
444pub trait AltComplexImpl: AltrepImpl {
445    /// Get a single element from this vector.
446    fn elt(&self, _index: usize) -> Rcplx;
447
448    /// Get a multiple elements from this vector.
449    fn get_region(&self, index: usize, data: &mut [Rcplx]) -> usize {
450        let len = self.length();
451        if index > len {
452            0
453        } else {
454            let num_elems = data.len().min(len - index);
455            let dest = &mut data[0..num_elems];
456            for (i, d) in dest.iter_mut().enumerate() {
457                *d = self.elt(i + index);
458            }
459            num_elems
460        }
461    }
462}
463
464// Implement the trait methods for iterators
465make_from_iterator_impl!(AltIntegerImpl, Rint);
466make_from_iterator_impl!(AltLogicalImpl, Rbool);
467make_from_iterator_impl!(AltRealImpl, Rfloat);
468make_from_iterator_impl!(AltComplexImpl, Rcplx);
469
470pub trait AltStringImpl {
471    /// Get a single element from this vector.
472    fn elt(&self, _index: usize) -> Rstr;
473
474    /// Set a single element in this vector.
475    fn set_elt(&mut self, _index: usize, _value: Rstr) {}
476
477    /// Return TRUE if this vector is sorted, FALSE if not and Rbool::na() if unknown.
478    fn is_sorted(&self) -> Rbool {
479        Rbool::na()
480    }
481
482    /// Return true if this vector does not contain NAs.
483    fn no_na(&self) -> bool {
484        false
485    }
486}
487
488#[cfg(use_r_altlist)]
489pub trait AltListImpl {
490    /// Get a single element from this vector
491    /// a single element of a list can be any Robj
492    fn elt(&self, _index: usize) -> Robj;
493
494    /// Set a single element in this list.
495    fn set_elt(&mut self, _index: usize, _value: Robj) {}
496}
497
498impl Altrep {
499    /// Safely implement R_altrep_data1, R_altrep_data2.
500    /// When implementing Altrep classes, this gets the metadata.
501    pub fn data(&self) -> (Robj, Robj) {
502        unsafe {
503            (
504                Robj::from_sexp(R_altrep_data1(self.robj.get())),
505                Robj::from_sexp(R_altrep_data1(self.robj.get())),
506            )
507        }
508    }
509
510    /// Safely (relatively!) implement R_set_altrep_data1, R_set_altrep_data2.
511    /// When implementing Altrep classes, this sets the metadata.
512    pub fn set_data(&mut self, values: (Robj, Robj)) {
513        unsafe {
514            R_set_altrep_data1(self.robj.get(), values.0.get());
515            R_set_altrep_data2(self.robj.get(), values.1.get());
516        }
517    }
518
519    /// Safely implement ALTREP_CLASS.
520    pub fn class(&self) -> Robj {
521        single_threaded(|| unsafe { Robj::from_sexp(ALTREP_CLASS(self.robj.get())) })
522    }
523
524    pub fn from_state_and_class<StateType: 'static>(
525        state: StateType,
526        class: Robj,
527        mutable: bool,
528    ) -> Altrep {
529        single_threaded(|| unsafe {
530            use std::os::raw::c_void;
531
532            unsafe extern "C" fn finalizer<StateType: 'static>(x: SEXP) {
533                let state = R_ExternalPtrAddr(x);
534                let ptr = state as *mut StateType;
535                drop(Box::from_raw(ptr));
536            }
537
538            let ptr: *mut StateType = Box::into_raw(Box::new(state));
539            let tag = R_NilValue;
540            let prot = R_NilValue;
541            let state = R_MakeExternalPtr(ptr as *mut c_void, tag, prot);
542
543            // Use R_RegisterCFinalizerEx() and set onexit to 1 (TRUE) to invoke
544            // the finalizer on a shutdown of the R session as well.
545            R_RegisterCFinalizerEx(state, Some(finalizer::<StateType>), Rboolean::TRUE);
546
547            let class_ptr = R_altrep_class_t { ptr: class.get() };
548            let sexp = R_new_altrep(class_ptr, state, R_NilValue);
549
550            if !mutable {
551                MARK_NOT_MUTABLE(sexp);
552            }
553
554            Altrep {
555                robj: Robj::from_sexp(sexp),
556            }
557        })
558    }
559
560    /// Return true if the ALTREP object has been manifested (copied into memory).
561    pub fn is_manifest(&self) -> bool {
562        unsafe { !DATAPTR_OR_NULL(self.get()).is_null() }
563    }
564
565    #[allow(dead_code)]
566    pub(crate) fn get_state<StateType>(x: SEXP) -> &'static StateType {
567        unsafe {
568            let state_ptr = R_ExternalPtrAddr(R_altrep_data1(x));
569            &*(state_ptr as *const StateType)
570        }
571    }
572
573    #[allow(dead_code)]
574    pub(crate) fn get_state_mut<StateType>(x: SEXP) -> &'static mut StateType {
575        unsafe {
576            let state_ptr = R_ExternalPtrAddr(R_altrep_data1(x));
577            &mut *(state_ptr as *mut StateType)
578        }
579    }
580
581    fn altrep_class<StateType: AltrepImpl + 'static>(ty: Rtype, name: &str, base: &str) -> Robj {
582        #![allow(non_snake_case)]
583        #![allow(unused_variables)]
584        use std::os::raw::c_int;
585        use std::os::raw::c_void;
586
587        #[cfg(feature = "non-api")]
588        unsafe extern "C" fn altrep_UnserializeEX<StateType: AltrepImpl>(
589            class: SEXP,
590            state: SEXP,
591            attr: SEXP,
592            objf: c_int,
593            levs: c_int,
594        ) -> SEXP {
595            <StateType>::unserialize_ex(
596                Robj::from_sexp(class),
597                Robj::from_sexp(state),
598                Robj::from_sexp(attr),
599                objf,
600                levs,
601            )
602            .get()
603        }
604
605        unsafe extern "C" fn altrep_Unserialize<StateType: AltrepImpl + 'static>(
606            class: SEXP,
607            state: SEXP,
608        ) -> SEXP {
609            <StateType>::unserialize(Robj::from_sexp(class), Robj::from_sexp(state)).get()
610        }
611
612        unsafe extern "C" fn altrep_Serialized_state<StateType: AltrepImpl + 'static>(
613            x: SEXP,
614        ) -> SEXP {
615            <StateType>::serialized_state(x).get()
616        }
617
618        unsafe extern "C" fn altrep_Coerce<StateType: AltrepImpl + 'static>(
619            x: SEXP,
620            ty: SEXPTYPE,
621        ) -> SEXP {
622            <StateType>::coerce(x, sxp_to_rtype(ty)).get()
623        }
624
625        unsafe extern "C" fn altrep_Duplicate<StateType: AltrepImpl + 'static>(
626            x: SEXP,
627            deep: Rboolean,
628        ) -> SEXP {
629            <StateType>::duplicate(x, deep == Rboolean::TRUE).get()
630        }
631
632        unsafe extern "C" fn altrep_DuplicateEX<StateType: AltrepImpl + 'static>(
633            x: SEXP,
634            deep: Rboolean,
635        ) -> SEXP {
636            <StateType>::duplicate_ex(x, deep == Rboolean::TRUE).get()
637        }
638
639        unsafe extern "C" fn altrep_Inspect<StateType: AltrepImpl + 'static>(
640            x: SEXP,
641            pre: c_int,
642            deep: c_int,
643            pvec: c_int,
644            func: Option<unsafe extern "C" fn(arg1: SEXP, arg2: c_int, arg3: c_int, arg4: c_int)>,
645        ) -> Rboolean {
646            Altrep::get_state::<StateType>(x)
647                .inspect(pre, deep == 1, pvec)
648                .into()
649        }
650
651        unsafe extern "C" fn altrep_Length<StateType: AltrepImpl + 'static>(x: SEXP) -> R_xlen_t {
652            Altrep::get_state::<StateType>(x).length() as R_xlen_t
653        }
654
655        unsafe extern "C" fn altvec_Dataptr<StateType: AltrepImpl + 'static>(
656            x: SEXP,
657            writeable: Rboolean,
658        ) -> *mut c_void {
659            <StateType>::dataptr(x, writeable != Rboolean::FALSE) as *mut c_void
660        }
661
662        unsafe extern "C" fn altvec_Dataptr_or_null<StateType: AltrepImpl + 'static>(
663            x: SEXP,
664        ) -> *const c_void {
665            <StateType>::dataptr_or_null(x) as *mut c_void
666        }
667
668        unsafe extern "C" fn altvec_Extract_subset<StateType: AltrepImpl + 'static>(
669            x: SEXP,
670            indx: SEXP,
671            call: SEXP,
672        ) -> SEXP {
673            <StateType>::extract_subset(
674                Robj::from_sexp(x),
675                Robj::from_sexp(indx),
676                Robj::from_sexp(call),
677            )
678            .get()
679        }
680
681        unsafe {
682            let csname = std::ffi::CString::new(name).unwrap();
683            let csbase = std::ffi::CString::new(base).unwrap();
684
685            let class_ptr = match ty {
686                Rtype::Integers => {
687                    R_make_altinteger_class(csname.as_ptr(), csbase.as_ptr(), std::ptr::null_mut())
688                }
689                Rtype::Doubles => {
690                    R_make_altreal_class(csname.as_ptr(), csbase.as_ptr(), std::ptr::null_mut())
691                }
692                Rtype::Logicals => {
693                    R_make_altlogical_class(csname.as_ptr(), csbase.as_ptr(), std::ptr::null_mut())
694                }
695                Rtype::Raw => {
696                    R_make_altraw_class(csname.as_ptr(), csbase.as_ptr(), std::ptr::null_mut())
697                }
698                Rtype::Complexes => {
699                    R_make_altcomplex_class(csname.as_ptr(), csbase.as_ptr(), std::ptr::null_mut())
700                }
701                Rtype::Strings => {
702                    R_make_altstring_class(csname.as_ptr(), csbase.as_ptr(), std::ptr::null_mut())
703                }
704                #[cfg(use_r_altlist)]
705                Rtype::List => {
706                    R_make_altlist_class(csname.as_ptr(), csbase.as_ptr(), std::ptr::null_mut())
707                }
708                _ => panic!("expected Altvec compatible type"),
709            };
710
711            #[cfg(feature = "non-api")]
712            R_set_altrep_UnserializeEX_method(class_ptr, Some(altrep_UnserializeEX::<StateType>));
713            R_set_altrep_Unserialize_method(class_ptr, Some(altrep_Unserialize::<StateType>));
714            R_set_altrep_Serialized_state_method(
715                class_ptr,
716                Some(altrep_Serialized_state::<StateType>),
717            );
718            R_set_altrep_DuplicateEX_method(class_ptr, Some(altrep_DuplicateEX::<StateType>));
719            R_set_altrep_Duplicate_method(class_ptr, Some(altrep_Duplicate::<StateType>));
720            R_set_altrep_Coerce_method(class_ptr, Some(altrep_Coerce::<StateType>));
721            R_set_altrep_Inspect_method(class_ptr, Some(altrep_Inspect::<StateType>));
722            R_set_altrep_Length_method(class_ptr, Some(altrep_Length::<StateType>));
723
724            R_set_altvec_Dataptr_method(class_ptr, Some(altvec_Dataptr::<StateType>));
725            R_set_altvec_Dataptr_or_null_method(
726                class_ptr,
727                Some(altvec_Dataptr_or_null::<StateType>),
728            );
729            R_set_altvec_Extract_subset_method(class_ptr, Some(altvec_Extract_subset::<StateType>));
730
731            Robj::from_sexp(class_ptr.ptr)
732        }
733    }
734
735    /// Make an integer ALTREP class that can be used to make vectors.
736    pub fn make_altinteger_class<StateType: AltrepImpl + AltIntegerImpl + 'static>(
737        name: &str,
738        base: &str,
739    ) -> Robj {
740        #![allow(non_snake_case)]
741        use std::os::raw::c_int;
742
743        single_threaded(|| unsafe {
744            let class = Altrep::altrep_class::<StateType>(Rtype::Integers, name, base);
745            let class_ptr = R_altrep_class_t { ptr: class.get() };
746
747            unsafe extern "C" fn altinteger_Elt<StateType: AltIntegerImpl + 'static>(
748                x: SEXP,
749                i: R_xlen_t,
750            ) -> c_int {
751                Altrep::get_state::<StateType>(x).elt(i as usize).inner() as c_int
752            }
753
754            unsafe extern "C" fn altinteger_Get_region<StateType: AltIntegerImpl + 'static>(
755                x: SEXP,
756                i: R_xlen_t,
757                n: R_xlen_t,
758                buf: *mut c_int,
759            ) -> R_xlen_t {
760                let slice = std::slice::from_raw_parts_mut(buf as *mut Rint, n as usize);
761                Altrep::get_state::<StateType>(x).get_region(i as usize, slice) as R_xlen_t
762            }
763
764            unsafe extern "C" fn altinteger_Is_sorted<StateType: AltIntegerImpl + 'static>(
765                x: SEXP,
766            ) -> c_int {
767                Altrep::get_state::<StateType>(x).is_sorted().inner() as c_int
768            }
769
770            unsafe extern "C" fn altinteger_No_NA<StateType: AltIntegerImpl + 'static>(
771                x: SEXP,
772            ) -> c_int {
773                i32::from(Altrep::get_state::<StateType>(x).no_na())
774            }
775
776            unsafe extern "C" fn altinteger_Sum<StateType: AltIntegerImpl + 'static>(
777                x: SEXP,
778                narm: Rboolean,
779            ) -> SEXP {
780                Altrep::get_state::<StateType>(x)
781                    .sum(narm == Rboolean::TRUE)
782                    .get()
783            }
784
785            unsafe extern "C" fn altinteger_Min<StateType: AltIntegerImpl + 'static>(
786                x: SEXP,
787                narm: Rboolean,
788            ) -> SEXP {
789                Altrep::get_state::<StateType>(x)
790                    .min(narm == Rboolean::TRUE)
791                    .get()
792            }
793
794            unsafe extern "C" fn altinteger_Max<StateType: AltIntegerImpl + 'static>(
795                x: SEXP,
796                narm: Rboolean,
797            ) -> SEXP {
798                Altrep::get_state::<StateType>(x)
799                    .max(narm == Rboolean::TRUE)
800                    .get()
801            }
802
803            R_set_altinteger_Elt_method(class_ptr, Some(altinteger_Elt::<StateType>));
804            R_set_altinteger_Get_region_method(class_ptr, Some(altinteger_Get_region::<StateType>));
805            R_set_altinteger_Is_sorted_method(class_ptr, Some(altinteger_Is_sorted::<StateType>));
806            R_set_altinteger_No_NA_method(class_ptr, Some(altinteger_No_NA::<StateType>));
807            R_set_altinteger_Sum_method(class_ptr, Some(altinteger_Sum::<StateType>));
808            R_set_altinteger_Min_method(class_ptr, Some(altinteger_Min::<StateType>));
809            R_set_altinteger_Max_method(class_ptr, Some(altinteger_Max::<StateType>));
810
811            class
812        })
813    }
814
815    /// Make a real ALTREP class that can be used to make vectors.
816    pub fn make_altreal_class<StateType: AltrepImpl + AltRealImpl + 'static>(
817        name: &str,
818        base: &str,
819    ) -> Robj {
820        #![allow(non_snake_case)]
821        use std::os::raw::c_int;
822
823        single_threaded(|| unsafe {
824            let class = Altrep::altrep_class::<StateType>(Rtype::Doubles, name, base);
825            let class_ptr = R_altrep_class_t { ptr: class.get() };
826
827            unsafe extern "C" fn altreal_Elt<StateType: AltRealImpl + 'static>(
828                x: SEXP,
829                i: R_xlen_t,
830            ) -> f64 {
831                Altrep::get_state::<StateType>(x).elt(i as usize).inner()
832            }
833
834            unsafe extern "C" fn altreal_Get_region<StateType: AltRealImpl + 'static>(
835                x: SEXP,
836                i: R_xlen_t,
837                n: R_xlen_t,
838                buf: *mut f64,
839            ) -> R_xlen_t {
840                let slice = std::slice::from_raw_parts_mut(buf as *mut Rfloat, n as usize);
841                Altrep::get_state::<StateType>(x).get_region(i as usize, slice) as R_xlen_t
842            }
843
844            unsafe extern "C" fn altreal_Is_sorted<StateType: AltRealImpl + 'static>(
845                x: SEXP,
846            ) -> c_int {
847                Altrep::get_state::<StateType>(x).is_sorted().inner() as c_int
848            }
849
850            unsafe extern "C" fn altreal_No_NA<StateType: AltRealImpl + 'static>(x: SEXP) -> c_int {
851                i32::from(Altrep::get_state::<StateType>(x).no_na())
852            }
853
854            unsafe extern "C" fn altreal_Sum<StateType: AltRealImpl + 'static>(
855                x: SEXP,
856                narm: Rboolean,
857            ) -> SEXP {
858                Altrep::get_state::<StateType>(x)
859                    .sum(narm == Rboolean::TRUE)
860                    .get()
861            }
862
863            unsafe extern "C" fn altreal_Min<StateType: AltRealImpl + 'static>(
864                x: SEXP,
865                narm: Rboolean,
866            ) -> SEXP {
867                Altrep::get_state::<StateType>(x)
868                    .min(narm == Rboolean::TRUE)
869                    .get()
870            }
871
872            unsafe extern "C" fn altreal_Max<StateType: AltRealImpl + 'static>(
873                x: SEXP,
874                narm: Rboolean,
875            ) -> SEXP {
876                Altrep::get_state::<StateType>(x)
877                    .max(narm == Rboolean::TRUE)
878                    .get()
879            }
880
881            R_set_altreal_Elt_method(class_ptr, Some(altreal_Elt::<StateType>));
882            R_set_altreal_Get_region_method(class_ptr, Some(altreal_Get_region::<StateType>));
883            R_set_altreal_Is_sorted_method(class_ptr, Some(altreal_Is_sorted::<StateType>));
884            R_set_altreal_No_NA_method(class_ptr, Some(altreal_No_NA::<StateType>));
885            R_set_altreal_Sum_method(class_ptr, Some(altreal_Sum::<StateType>));
886            R_set_altreal_Min_method(class_ptr, Some(altreal_Min::<StateType>));
887            R_set_altreal_Max_method(class_ptr, Some(altreal_Max::<StateType>));
888            class
889        })
890    }
891
892    /// Make a logical ALTREP class that can be used to make vectors.
893    pub fn make_altlogical_class<StateType: AltrepImpl + AltLogicalImpl + 'static>(
894        name: &str,
895        base: &str,
896    ) -> Robj {
897        #![allow(non_snake_case)]
898        use std::os::raw::c_int;
899
900        single_threaded(|| unsafe {
901            let class = Altrep::altrep_class::<StateType>(Rtype::Logicals, name, base);
902            let class_ptr = R_altrep_class_t { ptr: class.get() };
903
904            unsafe extern "C" fn altlogical_Elt<StateType: AltLogicalImpl + 'static>(
905                x: SEXP,
906                i: R_xlen_t,
907            ) -> c_int {
908                Altrep::get_state::<StateType>(x).elt(i as usize).inner() as c_int
909            }
910
911            unsafe extern "C" fn altlogical_Get_region<StateType: AltLogicalImpl + 'static>(
912                x: SEXP,
913                i: R_xlen_t,
914                n: R_xlen_t,
915                buf: *mut c_int,
916            ) -> R_xlen_t {
917                let slice = std::slice::from_raw_parts_mut(buf as *mut Rbool, n as usize);
918                Altrep::get_state::<StateType>(x).get_region(i as usize, slice) as R_xlen_t
919            }
920
921            unsafe extern "C" fn altlogical_Is_sorted<StateType: AltLogicalImpl + 'static>(
922                x: SEXP,
923            ) -> c_int {
924                Altrep::get_state::<StateType>(x).is_sorted().inner() as c_int
925            }
926
927            unsafe extern "C" fn altlogical_No_NA<StateType: AltLogicalImpl + 'static>(
928                x: SEXP,
929            ) -> c_int {
930                i32::from(Altrep::get_state::<StateType>(x).no_na())
931            }
932
933            unsafe extern "C" fn altlogical_Sum<StateType: AltLogicalImpl + 'static>(
934                x: SEXP,
935                narm: Rboolean,
936            ) -> SEXP {
937                Altrep::get_state::<StateType>(x)
938                    .sum(narm == Rboolean::TRUE)
939                    .get()
940            }
941
942            R_set_altlogical_Elt_method(class_ptr, Some(altlogical_Elt::<StateType>));
943            R_set_altlogical_Get_region_method(class_ptr, Some(altlogical_Get_region::<StateType>));
944            R_set_altlogical_Is_sorted_method(class_ptr, Some(altlogical_Is_sorted::<StateType>));
945            R_set_altlogical_No_NA_method(class_ptr, Some(altlogical_No_NA::<StateType>));
946            R_set_altlogical_Sum_method(class_ptr, Some(altlogical_Sum::<StateType>));
947
948            class
949        })
950    }
951
952    /// Make a raw ALTREP class that can be used to make vectors.
953    pub fn make_altraw_class<StateType: AltrepImpl + AltRawImpl + 'static>(
954        name: &str,
955        base: &str,
956    ) -> Robj {
957        #![allow(non_snake_case)]
958
959        single_threaded(|| unsafe {
960            let class = Altrep::altrep_class::<StateType>(Rtype::Raw, name, base);
961            let class_ptr = R_altrep_class_t { ptr: class.get() };
962
963            unsafe extern "C" fn altraw_Elt<StateType: AltRawImpl + 'static>(
964                x: SEXP,
965                i: R_xlen_t,
966            ) -> Rbyte {
967                Altrep::get_state::<StateType>(x).elt(i as usize) as Rbyte
968            }
969
970            unsafe extern "C" fn altraw_Get_region<StateType: AltRawImpl + 'static>(
971                x: SEXP,
972                i: R_xlen_t,
973                n: R_xlen_t,
974                buf: *mut u8,
975            ) -> R_xlen_t {
976                let slice = std::slice::from_raw_parts_mut(buf, n as usize);
977                Altrep::get_state::<StateType>(x).get_region(i as usize, slice) as R_xlen_t
978            }
979
980            R_set_altraw_Elt_method(class_ptr, Some(altraw_Elt::<StateType>));
981            R_set_altraw_Get_region_method(class_ptr, Some(altraw_Get_region::<StateType>));
982
983            class
984        })
985    }
986
987    /// Make a complex ALTREP class that can be used to make vectors.
988    pub fn make_altcomplex_class<StateType: AltrepImpl + AltComplexImpl + 'static>(
989        name: &str,
990        base: &str,
991    ) -> Robj {
992        #![allow(non_snake_case)]
993
994        single_threaded(|| unsafe {
995            let class = Altrep::altrep_class::<StateType>(Rtype::Complexes, name, base);
996            let class_ptr = R_altrep_class_t { ptr: class.get() };
997
998            unsafe extern "C" fn altcomplex_Elt<StateType: AltComplexImpl + 'static>(
999                x: SEXP,
1000                i: R_xlen_t,
1001            ) -> Rcomplex {
1002                std::mem::transmute(Altrep::get_state::<StateType>(x).elt(i as usize))
1003            }
1004
1005            unsafe extern "C" fn altcomplex_Get_region<StateType: AltComplexImpl + 'static>(
1006                x: SEXP,
1007                i: R_xlen_t,
1008                n: R_xlen_t,
1009                buf: *mut Rcomplex,
1010            ) -> R_xlen_t {
1011                let slice = std::slice::from_raw_parts_mut(buf as *mut Rcplx, n as usize);
1012                Altrep::get_state::<StateType>(x).get_region(i as usize, slice) as R_xlen_t
1013            }
1014
1015            R_set_altcomplex_Elt_method(class_ptr, Some(altcomplex_Elt::<StateType>));
1016            R_set_altcomplex_Get_region_method(class_ptr, Some(altcomplex_Get_region::<StateType>));
1017
1018            class
1019        })
1020    }
1021
1022    /// Make a string ALTREP class that can be used to make vectors.
1023    pub fn make_altstring_class<StateType: AltrepImpl + AltStringImpl + 'static>(
1024        name: &str,
1025        base: &str,
1026    ) -> Robj {
1027        #![allow(non_snake_case)]
1028        use std::os::raw::c_int;
1029
1030        single_threaded(|| unsafe {
1031            let class = Altrep::altrep_class::<StateType>(Rtype::Strings, name, base);
1032            let class_ptr = R_altrep_class_t { ptr: class.get() };
1033
1034            unsafe extern "C" fn altstring_Elt<StateType: AltStringImpl + 'static>(
1035                x: SEXP,
1036                i: R_xlen_t,
1037            ) -> SEXP {
1038                Altrep::get_state::<StateType>(x).elt(i as usize).get()
1039            }
1040
1041            unsafe extern "C" fn altstring_Set_elt<StateType: AltStringImpl + 'static>(
1042                x: SEXP,
1043                i: R_xlen_t,
1044                v: SEXP,
1045            ) {
1046                Altrep::get_state_mut::<StateType>(x)
1047                    .set_elt(i as usize, Robj::from_sexp(v).try_into().unwrap())
1048            }
1049
1050            unsafe extern "C" fn altstring_Is_sorted<StateType: AltStringImpl + 'static>(
1051                x: SEXP,
1052            ) -> c_int {
1053                Altrep::get_state::<StateType>(x).is_sorted().inner() as c_int
1054            }
1055
1056            unsafe extern "C" fn altstring_No_NA<StateType: AltStringImpl + 'static>(
1057                x: SEXP,
1058            ) -> c_int {
1059                i32::from(Altrep::get_state::<StateType>(x).no_na())
1060            }
1061
1062            R_set_altstring_Elt_method(class_ptr, Some(altstring_Elt::<StateType>));
1063            R_set_altstring_Set_elt_method(class_ptr, Some(altstring_Set_elt::<StateType>));
1064            R_set_altstring_Is_sorted_method(class_ptr, Some(altstring_Is_sorted::<StateType>));
1065            R_set_altstring_No_NA_method(class_ptr, Some(altstring_No_NA::<StateType>));
1066
1067            class
1068        })
1069    }
1070
1071    #[cfg(use_r_altlist)]
1072    pub fn make_altlist_class<StateType: AltrepImpl + AltListImpl + 'static>(
1073        name: &str,
1074        base: &str,
1075    ) -> Robj {
1076        #![allow(non_snake_case)]
1077
1078        single_threaded(|| unsafe {
1079            let class = Altrep::altrep_class::<StateType>(Rtype::List, name, base);
1080            let class_ptr = R_altrep_class_t { ptr: class.get() };
1081
1082            unsafe extern "C" fn altlist_Elt<StateType: AltListImpl + 'static>(
1083                x: SEXP,
1084                i: R_xlen_t,
1085            ) -> SEXP {
1086                Altrep::get_state::<StateType>(x).elt(i as usize).get()
1087            }
1088
1089            unsafe extern "C" fn altlist_Set_elt<StateType: AltListImpl + 'static>(
1090                x: SEXP,
1091                i: R_xlen_t,
1092                v: SEXP,
1093            ) {
1094                Altrep::get_state_mut::<StateType>(x).set_elt(i as usize, Robj::from_sexp(v))
1095            }
1096
1097            R_set_altlist_Elt_method(class_ptr, Some(altlist_Elt::<StateType>));
1098            R_set_altlist_Set_elt_method(class_ptr, Some(altlist_Set_elt::<StateType>));
1099            class
1100        })
1101    }
1102
1103    make_from_iterator!(
1104        make_altinteger_from_iterator,
1105        make_altinteger_class,
1106        AltIntegerImpl,
1107        Rint,
1108        i32
1109    );
1110    make_from_iterator!(
1111        make_altlogical_from_iterator,
1112        make_altlogical_class,
1113        AltLogicalImpl,
1114        Rbool,
1115        i32
1116    );
1117    make_from_iterator!(
1118        make_altreal_from_iterator,
1119        make_altreal_class,
1120        AltRealImpl,
1121        Rfloat,
1122        f64
1123    );
1124    make_from_iterator!(
1125        make_altcomplex_from_iterator,
1126        make_altcomplex_class,
1127        AltComplexImpl,
1128        Rcplx,
1129        c64
1130    );
1131}
1132
1133impl<Iter: ExactSizeIterator + std::fmt::Debug + Clone> AltrepImpl for Iter {
1134    fn length(&self) -> usize {
1135        self.len()
1136    }
1137}