extendr_api/wrapper/
altrep.rs

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