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
52pub trait AltrepImpl: Clone + std::fmt::Debug {
56 #[cfg(feature = "non-api")]
57 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 fn unserialize(_class: Robj, _state: Robj) -> Robj {
85 ().into()
87 }
88
89 fn serialized_state(_x: SEXP) -> Robj {
91 ().into()
93 }
94
95 fn duplicate_ex(x: SEXP, deep: bool) -> Robj {
98 Self::duplicate(x, deep)
99 }
100
101 fn duplicate(x: SEXP, _deep: bool) -> Robj {
104 Robj::from_sexp(manifest(x))
105 }
106
107 fn coerce(_x: SEXP, _ty: Rtype) -> Robj {
109 ().into()
110 }
111
112 fn inspect(
114 &self,
115 _pre: i32,
116 _deep: bool,
117 _pvec: i32, ) -> bool {
119 rprintln!("{:?}", self);
120 true
121 }
122
123 fn length(&self) -> usize;
126
127 #[allow(clippy::not_unsafe_ptr_arg_deref)]
136 fn dataptr(x: SEXP, _writeable: bool) -> *mut u8 {
137 single_threaded(|| unsafe {
138 let data2 = R_altrep_data2(x);
139 if data2 == R_NilValue || TYPEOF(data2) != TYPEOF(x) {
140 let data2 = manifest(x);
141 R_set_altrep_data2(x, data2);
142 dataptr(data2) as *mut u8
143 } else {
144 dataptr(data2) as *mut u8
145 }
146 })
147 }
148
149 #[allow(clippy::not_unsafe_ptr_arg_deref)]
158 fn dataptr_or_null(x: SEXP) -> *const u8 {
159 unsafe {
160 let data2 = R_altrep_data2(x);
161 if data2 == R_NilValue || TYPEOF(data2) != TYPEOF(x) {
162 std::ptr::null()
163 } else {
164 dataptr(data2) as *const u8
165 }
166 }
167 }
168
169 fn extract_subset(_x: Robj, _indx: Robj, _call: Robj) -> Robj {
171 Robj::from(())
174 }
175}
176
177fn manifest(x: SEXP) -> SEXP {
180 single_threaded(|| unsafe {
181 Rf_protect(x);
182 let len = XLENGTH(x);
183 let data2 = Rf_allocVector(TYPEOF(x), len as R_xlen_t);
184 Rf_protect(data2);
185 match TYPEOF(x) {
186 SEXPTYPE::INTSXP => {
187 INTEGER_GET_REGION(x, 0, len as R_xlen_t, INTEGER(data2));
188 }
189 SEXPTYPE::LGLSXP => {
190 LOGICAL_GET_REGION(x, 0, len as R_xlen_t, LOGICAL(data2));
191 }
192 SEXPTYPE::REALSXP => {
193 REAL_GET_REGION(x, 0, len as R_xlen_t, REAL(data2));
194 }
195 SEXPTYPE::RAWSXP => {
196 RAW_GET_REGION(x, 0, len as R_xlen_t, RAW(data2));
197 }
198 SEXPTYPE::CPLXSXP => {
199 COMPLEX_GET_REGION(x, 0, len as R_xlen_t, COMPLEX(data2));
200 }
201 _ => {
202 Rf_unprotect(2);
203 panic!("unsupported ALTREP type.")
204 }
205 };
206 Rf_unprotect(2);
207 data2
208 })
209}
210
211pub trait AltIntegerImpl: AltrepImpl {
212 fn tot_min_max_nas(&self) -> (i64, i32, i32, usize, usize) {
213 let len = self.length();
214 let mut tot = 0;
215 let mut nas = 0;
216 let mut min = i32::MAX;
217 let mut max = i32::MIN;
218 for i in 0..len {
219 let val = self.elt(i);
220 if !val.is_na() {
221 tot += val.inner() as i64;
222 min = min.min(val.inner());
223 max = max.max(val.inner());
224 nas += 1;
225 }
226 }
227 (tot, min, max, len - nas, len)
228 }
229
230 fn elt(&self, _index: usize) -> Rint;
232
233 fn get_region(&self, index: usize, data: &mut [Rint]) -> usize {
235 let len = self.length();
236 if index > len {
237 0
238 } else {
239 let num_elems = data.len().min(len - index);
240 let dest = &mut data[0..num_elems];
241 for (i, d) in dest.iter_mut().enumerate() {
242 *d = self.elt(i + index);
243 }
244 num_elems
245 }
246 }
247
248 fn is_sorted(&self) -> Rbool {
250 Rbool::na()
251 }
252
253 fn no_na(&self) -> bool {
255 false
256 }
257
258 fn sum(&self, remove_nas: bool) -> Robj {
261 let (tot, _min, _max, nas, _len) = self.tot_min_max_nas();
262 if !remove_nas && nas != 0 {
263 NA_INTEGER.into()
264 } else {
265 tot.into()
266 }
267 }
268
269 fn min(&self, remove_nas: bool) -> Robj {
272 let (_tot, min, _max, nas, len) = self.tot_min_max_nas();
273 if !remove_nas && nas != 0 || remove_nas && nas == len {
274 NA_INTEGER.into()
275 } else {
276 min.into()
277 }
278 }
279
280 fn max(&self, remove_nas: bool) -> Robj {
283 let (_tot, _min, max, nas, len) = self.tot_min_max_nas();
284 if !remove_nas && nas != 0 || remove_nas && nas == len {
285 NA_INTEGER.into()
286 } else {
287 max.into()
288 }
289 }
290}
291
292pub trait AltRealImpl: AltrepImpl {
293 fn tot_min_max_nas(&self) -> (f64, f64, f64, usize, usize) {
294 let len = self.length();
295 let mut tot = 0.0;
296 let mut nas = 0;
297 let mut min = f64::MAX;
298 let mut max = f64::MIN;
299 for i in 0..len {
300 let val = self.elt(i);
301 if !val.is_na() {
302 tot += val.inner();
303 min = min.min(val.inner());
304 max = max.max(val.inner());
305 nas += 1;
306 }
307 }
308 (tot, min, max, len - nas, len)
309 }
310
311 fn elt(&self, _index: usize) -> Rfloat;
313
314 fn get_region(&self, index: usize, data: &mut [Rfloat]) -> usize {
316 let len = self.length();
317 if index > len {
318 0
319 } else {
320 let num_elems = data.len().min(len - index);
321 let dest = &mut data[0..num_elems];
322 for (i, d) in dest.iter_mut().enumerate() {
323 *d = self.elt(i + index);
324 }
325 num_elems
326 }
327 }
328
329 fn is_sorted(&self) -> Rbool {
331 Rbool::na()
332 }
333
334 fn no_na(&self) -> bool {
336 false
337 }
338
339 fn sum(&self, remove_nas: bool) -> Robj {
342 let (tot, _min, _max, nas, _len) = self.tot_min_max_nas();
343 if !remove_nas && nas != 0 {
344 NA_REAL.into()
345 } else {
346 tot.into()
347 }
348 }
349
350 fn min(&self, remove_nas: bool) -> Robj {
353 let (_tot, min, _max, nas, len) = self.tot_min_max_nas();
354 if !remove_nas && nas != 0 || remove_nas && nas == len {
355 NA_REAL.into()
356 } else {
357 min.into()
358 }
359 }
360
361 fn max(&self, remove_nas: bool) -> Robj {
364 let (_tot, _min, max, nas, len) = self.tot_min_max_nas();
365 if !remove_nas && nas != 0 || remove_nas && nas == len {
366 NA_REAL.into()
367 } else {
368 max.into()
369 }
370 }
371}
372
373pub trait AltLogicalImpl: AltrepImpl {
374 fn tot_min_max_nas(&self) -> (i64, i32, i32, usize, usize) {
375 let len = self.length();
376 let mut tot = 0;
377 let mut nas = 0;
378 for i in 0..len {
379 let val = self.elt(i);
380 if !val.is_na() {
381 tot += val.inner() as i64;
382 nas += 1;
383 }
384 }
385 (tot, 0, 0, len - nas, len)
386 }
387
388 fn elt(&self, _index: usize) -> Rbool;
390
391 fn get_region(&self, index: usize, data: &mut [Rbool]) -> usize {
393 let len = self.length();
394 if index > len {
395 0
396 } else {
397 let num_elems = data.len().min(len - index);
398 let dest = &mut data[0..num_elems];
399 for (i, d) in dest.iter_mut().enumerate() {
400 *d = self.elt(i + index);
401 }
402 num_elems
403 }
404 }
405
406 fn is_sorted(&self) -> Rbool {
408 Rbool::na()
409 }
410
411 fn no_na(&self) -> bool {
413 false
414 }
415
416 fn sum(&self, remove_nas: bool) -> Robj {
419 let (tot, _min, _max, nas, len) = self.tot_min_max_nas();
420 if !remove_nas && nas != 0 || remove_nas && nas == len {
421 Rbool::na().into()
422 } else {
423 tot.into()
424 }
425 }
426}
427
428pub trait AltRawImpl: AltrepImpl {
429 fn elt(&self, _index: usize) -> u8;
431
432 fn get_region(&self, index: usize, data: &mut [u8]) -> usize {
434 let len = self.length();
435 if index > len {
436 0
437 } else {
438 let num_elems = data.len().min(len - index);
439 let dest = &mut data[0..num_elems];
440 for (i, d) in dest.iter_mut().enumerate() {
441 *d = self.elt(i + index);
442 }
443 num_elems
444 }
445 }
446}
447
448pub trait AltComplexImpl: AltrepImpl {
449 fn elt(&self, _index: usize) -> Rcplx;
451
452 fn get_region(&self, index: usize, data: &mut [Rcplx]) -> usize {
454 let len = self.length();
455 if index > len {
456 0
457 } else {
458 let num_elems = data.len().min(len - index);
459 let dest = &mut data[0..num_elems];
460 for (i, d) in dest.iter_mut().enumerate() {
461 *d = self.elt(i + index);
462 }
463 num_elems
464 }
465 }
466}
467
468make_from_iterator_impl!(AltIntegerImpl, Rint);
470make_from_iterator_impl!(AltLogicalImpl, Rbool);
471make_from_iterator_impl!(AltRealImpl, Rfloat);
472make_from_iterator_impl!(AltComplexImpl, Rcplx);
473
474pub trait AltStringImpl {
475 fn elt(&self, _index: usize) -> Rstr;
477
478 fn set_elt(&mut self, _index: usize, _value: Rstr) {}
480
481 fn is_sorted(&self) -> Rbool {
483 Rbool::na()
484 }
485
486 fn no_na(&self) -> bool {
488 false
489 }
490}
491
492#[cfg(use_r_altlist)]
493pub trait AltListImpl {
494 fn elt(&self, _index: usize) -> Robj;
497
498 fn set_elt(&mut self, _index: usize, _value: Robj) {}
500}
501
502impl Altrep {
503 pub fn data(&self) -> (Robj, Robj) {
506 unsafe {
507 (
508 Robj::from_sexp(R_altrep_data1(self.robj.get())),
509 Robj::from_sexp(R_altrep_data1(self.robj.get())),
510 )
511 }
512 }
513
514 pub fn set_data(&mut self, values: (Robj, Robj)) {
517 unsafe {
518 R_set_altrep_data1(self.robj.get(), values.0.get());
519 R_set_altrep_data2(self.robj.get(), values.1.get());
520 }
521 }
522
523 pub fn class(&self) -> Robj {
525 single_threaded(|| unsafe { Robj::from_sexp(ALTREP_CLASS(self.robj.get())) })
526 }
527
528 pub fn from_state_and_class<StateType: 'static>(
529 state: StateType,
530 class: Robj,
531 mutable: bool,
532 ) -> Altrep {
533 single_threaded(|| unsafe {
534 use std::os::raw::c_void;
535
536 unsafe extern "C" fn finalizer<StateType: 'static>(x: SEXP) {
537 let state = R_ExternalPtrAddr(x);
538 let ptr = state as *mut StateType;
539 drop(Box::from_raw(ptr));
540 }
541
542 let ptr: *mut StateType = Box::into_raw(Box::new(state));
543 let tag = R_NilValue;
544 let prot = R_NilValue;
545 let state = R_MakeExternalPtr(ptr as *mut c_void, tag, prot);
546
547 R_RegisterCFinalizerEx(state, Some(finalizer::<StateType>), Rboolean::TRUE);
550
551 let class_ptr = R_altrep_class_t { ptr: class.get() };
552 let sexp = R_new_altrep(class_ptr, state, R_NilValue);
553
554 if !mutable {
555 MARK_NOT_MUTABLE(sexp);
556 }
557
558 Altrep {
559 robj: Robj::from_sexp(sexp),
560 }
561 })
562 }
563
564 pub fn is_manifest(&self) -> bool {
566 unsafe { !DATAPTR_OR_NULL(self.get()).is_null() }
567 }
568
569 #[allow(dead_code)]
570 pub(crate) fn get_state<StateType>(x: SEXP) -> &'static StateType {
571 unsafe {
572 let state_ptr = R_ExternalPtrAddr(R_altrep_data1(x));
573 &*(state_ptr as *const StateType)
574 }
575 }
576
577 #[allow(dead_code)]
578 pub(crate) fn get_state_mut<StateType>(x: SEXP) -> &'static mut StateType {
579 unsafe {
580 let state_ptr = R_ExternalPtrAddr(R_altrep_data1(x));
581 &mut *(state_ptr as *mut StateType)
582 }
583 }
584
585 fn altrep_class<StateType: AltrepImpl + 'static>(ty: Rtype, name: &str, base: &str) -> Robj {
586 #![allow(non_snake_case)]
587 #![allow(unused_variables)]
588 use std::os::raw::c_int;
589 use std::os::raw::c_void;
590
591 #[cfg(feature = "non-api")]
592 unsafe extern "C" fn altrep_UnserializeEX<StateType: AltrepImpl>(
593 class: SEXP,
594 state: SEXP,
595 attr: SEXP,
596 objf: c_int,
597 levs: c_int,
598 ) -> SEXP {
599 <StateType>::unserialize_ex(
600 Robj::from_sexp(class),
601 Robj::from_sexp(state),
602 Robj::from_sexp(attr),
603 objf,
604 levs,
605 )
606 .get()
607 }
608
609 unsafe extern "C" fn altrep_Unserialize<StateType: AltrepImpl + 'static>(
610 class: SEXP,
611 state: SEXP,
612 ) -> SEXP {
613 <StateType>::unserialize(Robj::from_sexp(class), Robj::from_sexp(state)).get()
614 }
615
616 unsafe extern "C" fn altrep_Serialized_state<StateType: AltrepImpl + 'static>(
617 x: SEXP,
618 ) -> SEXP {
619 <StateType>::serialized_state(x).get()
620 }
621
622 unsafe extern "C" fn altrep_Coerce<StateType: AltrepImpl + 'static>(
623 x: SEXP,
624 ty: SEXPTYPE,
625 ) -> SEXP {
626 <StateType>::coerce(x, sxp_to_rtype(ty)).get()
627 }
628
629 unsafe extern "C" fn altrep_Duplicate<StateType: AltrepImpl + 'static>(
630 x: SEXP,
631 deep: Rboolean,
632 ) -> SEXP {
633 <StateType>::duplicate(x, deep == Rboolean::TRUE).get()
634 }
635
636 unsafe extern "C" fn altrep_DuplicateEX<StateType: AltrepImpl + 'static>(
637 x: SEXP,
638 deep: Rboolean,
639 ) -> SEXP {
640 <StateType>::duplicate_ex(x, deep == Rboolean::TRUE).get()
641 }
642
643 unsafe extern "C" fn altrep_Inspect<StateType: AltrepImpl + 'static>(
644 x: SEXP,
645 pre: c_int,
646 deep: c_int,
647 pvec: c_int,
648 func: Option<unsafe extern "C" fn(arg1: SEXP, arg2: c_int, arg3: c_int, arg4: c_int)>,
649 ) -> Rboolean {
650 Altrep::get_state::<StateType>(x)
651 .inspect(pre, deep == 1, pvec)
652 .into()
653 }
654
655 unsafe extern "C" fn altrep_Length<StateType: AltrepImpl + 'static>(x: SEXP) -> R_xlen_t {
656 Altrep::get_state::<StateType>(x).length() as R_xlen_t
657 }
658
659 unsafe extern "C" fn altvec_Dataptr<StateType: AltrepImpl + 'static>(
660 x: SEXP,
661 writeable: Rboolean,
662 ) -> *mut c_void {
663 <StateType>::dataptr(x, writeable != Rboolean::FALSE) as *mut c_void
664 }
665
666 unsafe extern "C" fn altvec_Dataptr_or_null<StateType: AltrepImpl + 'static>(
667 x: SEXP,
668 ) -> *const c_void {
669 <StateType>::dataptr_or_null(x) as *mut c_void
670 }
671
672 unsafe extern "C" fn altvec_Extract_subset<StateType: AltrepImpl + 'static>(
673 x: SEXP,
674 indx: SEXP,
675 call: SEXP,
676 ) -> SEXP {
677 <StateType>::extract_subset(
678 Robj::from_sexp(x),
679 Robj::from_sexp(indx),
680 Robj::from_sexp(call),
681 )
682 .get()
683 }
684
685 unsafe {
686 let csname = std::ffi::CString::new(name).unwrap();
687 let csbase = std::ffi::CString::new(base).unwrap();
688
689 let class_ptr = match ty {
690 Rtype::Integers => {
691 R_make_altinteger_class(csname.as_ptr(), csbase.as_ptr(), std::ptr::null_mut())
692 }
693 Rtype::Doubles => {
694 R_make_altreal_class(csname.as_ptr(), csbase.as_ptr(), std::ptr::null_mut())
695 }
696 Rtype::Logicals => {
697 R_make_altlogical_class(csname.as_ptr(), csbase.as_ptr(), std::ptr::null_mut())
698 }
699 Rtype::Raw => {
700 R_make_altraw_class(csname.as_ptr(), csbase.as_ptr(), std::ptr::null_mut())
701 }
702 Rtype::Complexes => {
703 R_make_altcomplex_class(csname.as_ptr(), csbase.as_ptr(), std::ptr::null_mut())
704 }
705 Rtype::Strings => {
706 R_make_altstring_class(csname.as_ptr(), csbase.as_ptr(), std::ptr::null_mut())
707 }
708 #[cfg(use_r_altlist)]
709 Rtype::List => {
710 R_make_altlist_class(csname.as_ptr(), csbase.as_ptr(), std::ptr::null_mut())
711 }
712 _ => panic!("expected Altvec compatible type"),
713 };
714
715 #[cfg(feature = "non-api")]
716 R_set_altrep_UnserializeEX_method(class_ptr, Some(altrep_UnserializeEX::<StateType>));
717 R_set_altrep_Unserialize_method(class_ptr, Some(altrep_Unserialize::<StateType>));
718 R_set_altrep_Serialized_state_method(
719 class_ptr,
720 Some(altrep_Serialized_state::<StateType>),
721 );
722 R_set_altrep_DuplicateEX_method(class_ptr, Some(altrep_DuplicateEX::<StateType>));
723 R_set_altrep_Duplicate_method(class_ptr, Some(altrep_Duplicate::<StateType>));
724 R_set_altrep_Coerce_method(class_ptr, Some(altrep_Coerce::<StateType>));
725 R_set_altrep_Inspect_method(class_ptr, Some(altrep_Inspect::<StateType>));
726 R_set_altrep_Length_method(class_ptr, Some(altrep_Length::<StateType>));
727
728 R_set_altvec_Dataptr_method(class_ptr, Some(altvec_Dataptr::<StateType>));
729 R_set_altvec_Dataptr_or_null_method(
730 class_ptr,
731 Some(altvec_Dataptr_or_null::<StateType>),
732 );
733 R_set_altvec_Extract_subset_method(class_ptr, Some(altvec_Extract_subset::<StateType>));
734
735 Robj::from_sexp(class_ptr.ptr)
736 }
737 }
738
739 pub fn make_altinteger_class<StateType: AltrepImpl + AltIntegerImpl + 'static>(
741 name: &str,
742 base: &str,
743 ) -> Robj {
744 #![allow(non_snake_case)]
745 use std::os::raw::c_int;
746
747 single_threaded(|| unsafe {
748 let class = Altrep::altrep_class::<StateType>(Rtype::Integers, name, base);
749 let class_ptr = R_altrep_class_t { ptr: class.get() };
750
751 unsafe extern "C" fn altinteger_Elt<StateType: AltIntegerImpl + 'static>(
752 x: SEXP,
753 i: R_xlen_t,
754 ) -> c_int {
755 Altrep::get_state::<StateType>(x).elt(i as usize).inner() as c_int
756 }
757
758 unsafe extern "C" fn altinteger_Get_region<StateType: AltIntegerImpl + 'static>(
759 x: SEXP,
760 i: R_xlen_t,
761 n: R_xlen_t,
762 buf: *mut c_int,
763 ) -> R_xlen_t {
764 let slice = std::slice::from_raw_parts_mut(buf as *mut Rint, n as usize);
765 Altrep::get_state::<StateType>(x).get_region(i as usize, slice) as R_xlen_t
766 }
767
768 unsafe extern "C" fn altinteger_Is_sorted<StateType: AltIntegerImpl + 'static>(
769 x: SEXP,
770 ) -> c_int {
771 Altrep::get_state::<StateType>(x).is_sorted().inner() as c_int
772 }
773
774 unsafe extern "C" fn altinteger_No_NA<StateType: AltIntegerImpl + 'static>(
775 x: SEXP,
776 ) -> c_int {
777 i32::from(Altrep::get_state::<StateType>(x).no_na())
778 }
779
780 unsafe extern "C" fn altinteger_Sum<StateType: AltIntegerImpl + 'static>(
781 x: SEXP,
782 narm: Rboolean,
783 ) -> SEXP {
784 Altrep::get_state::<StateType>(x)
785 .sum(narm == Rboolean::TRUE)
786 .get()
787 }
788
789 unsafe extern "C" fn altinteger_Min<StateType: AltIntegerImpl + 'static>(
790 x: SEXP,
791 narm: Rboolean,
792 ) -> SEXP {
793 Altrep::get_state::<StateType>(x)
794 .min(narm == Rboolean::TRUE)
795 .get()
796 }
797
798 unsafe extern "C" fn altinteger_Max<StateType: AltIntegerImpl + 'static>(
799 x: SEXP,
800 narm: Rboolean,
801 ) -> SEXP {
802 Altrep::get_state::<StateType>(x)
803 .max(narm == Rboolean::TRUE)
804 .get()
805 }
806
807 R_set_altinteger_Elt_method(class_ptr, Some(altinteger_Elt::<StateType>));
808 R_set_altinteger_Get_region_method(class_ptr, Some(altinteger_Get_region::<StateType>));
809 R_set_altinteger_Is_sorted_method(class_ptr, Some(altinteger_Is_sorted::<StateType>));
810 R_set_altinteger_No_NA_method(class_ptr, Some(altinteger_No_NA::<StateType>));
811 R_set_altinteger_Sum_method(class_ptr, Some(altinteger_Sum::<StateType>));
812 R_set_altinteger_Min_method(class_ptr, Some(altinteger_Min::<StateType>));
813 R_set_altinteger_Max_method(class_ptr, Some(altinteger_Max::<StateType>));
814
815 class
816 })
817 }
818
819 pub fn make_altreal_class<StateType: AltrepImpl + AltRealImpl + 'static>(
821 name: &str,
822 base: &str,
823 ) -> Robj {
824 #![allow(non_snake_case)]
825 use std::os::raw::c_int;
826
827 single_threaded(|| unsafe {
828 let class = Altrep::altrep_class::<StateType>(Rtype::Doubles, name, base);
829 let class_ptr = R_altrep_class_t { ptr: class.get() };
830
831 unsafe extern "C" fn altreal_Elt<StateType: AltRealImpl + 'static>(
832 x: SEXP,
833 i: R_xlen_t,
834 ) -> f64 {
835 Altrep::get_state::<StateType>(x).elt(i as usize).inner()
836 }
837
838 unsafe extern "C" fn altreal_Get_region<StateType: AltRealImpl + 'static>(
839 x: SEXP,
840 i: R_xlen_t,
841 n: R_xlen_t,
842 buf: *mut f64,
843 ) -> R_xlen_t {
844 let slice = std::slice::from_raw_parts_mut(buf as *mut Rfloat, n as usize);
845 Altrep::get_state::<StateType>(x).get_region(i as usize, slice) as R_xlen_t
846 }
847
848 unsafe extern "C" fn altreal_Is_sorted<StateType: AltRealImpl + 'static>(
849 x: SEXP,
850 ) -> c_int {
851 Altrep::get_state::<StateType>(x).is_sorted().inner() as c_int
852 }
853
854 unsafe extern "C" fn altreal_No_NA<StateType: AltRealImpl + 'static>(x: SEXP) -> c_int {
855 i32::from(Altrep::get_state::<StateType>(x).no_na())
856 }
857
858 unsafe extern "C" fn altreal_Sum<StateType: AltRealImpl + 'static>(
859 x: SEXP,
860 narm: Rboolean,
861 ) -> SEXP {
862 Altrep::get_state::<StateType>(x)
863 .sum(narm == Rboolean::TRUE)
864 .get()
865 }
866
867 unsafe extern "C" fn altreal_Min<StateType: AltRealImpl + 'static>(
868 x: SEXP,
869 narm: Rboolean,
870 ) -> SEXP {
871 Altrep::get_state::<StateType>(x)
872 .min(narm == Rboolean::TRUE)
873 .get()
874 }
875
876 unsafe extern "C" fn altreal_Max<StateType: AltRealImpl + 'static>(
877 x: SEXP,
878 narm: Rboolean,
879 ) -> SEXP {
880 Altrep::get_state::<StateType>(x)
881 .max(narm == Rboolean::TRUE)
882 .get()
883 }
884
885 R_set_altreal_Elt_method(class_ptr, Some(altreal_Elt::<StateType>));
886 R_set_altreal_Get_region_method(class_ptr, Some(altreal_Get_region::<StateType>));
887 R_set_altreal_Is_sorted_method(class_ptr, Some(altreal_Is_sorted::<StateType>));
888 R_set_altreal_No_NA_method(class_ptr, Some(altreal_No_NA::<StateType>));
889 R_set_altreal_Sum_method(class_ptr, Some(altreal_Sum::<StateType>));
890 R_set_altreal_Min_method(class_ptr, Some(altreal_Min::<StateType>));
891 R_set_altreal_Max_method(class_ptr, Some(altreal_Max::<StateType>));
892 class
893 })
894 }
895
896 pub fn make_altlogical_class<StateType: AltrepImpl + AltLogicalImpl + 'static>(
898 name: &str,
899 base: &str,
900 ) -> Robj {
901 #![allow(non_snake_case)]
902 use std::os::raw::c_int;
903
904 single_threaded(|| unsafe {
905 let class = Altrep::altrep_class::<StateType>(Rtype::Logicals, name, base);
906 let class_ptr = R_altrep_class_t { ptr: class.get() };
907
908 unsafe extern "C" fn altlogical_Elt<StateType: AltLogicalImpl + 'static>(
909 x: SEXP,
910 i: R_xlen_t,
911 ) -> c_int {
912 Altrep::get_state::<StateType>(x).elt(i as usize).inner() as c_int
913 }
914
915 unsafe extern "C" fn altlogical_Get_region<StateType: AltLogicalImpl + 'static>(
916 x: SEXP,
917 i: R_xlen_t,
918 n: R_xlen_t,
919 buf: *mut c_int,
920 ) -> R_xlen_t {
921 let slice = std::slice::from_raw_parts_mut(buf as *mut Rbool, n as usize);
922 Altrep::get_state::<StateType>(x).get_region(i as usize, slice) as R_xlen_t
923 }
924
925 unsafe extern "C" fn altlogical_Is_sorted<StateType: AltLogicalImpl + 'static>(
926 x: SEXP,
927 ) -> c_int {
928 Altrep::get_state::<StateType>(x).is_sorted().inner() as c_int
929 }
930
931 unsafe extern "C" fn altlogical_No_NA<StateType: AltLogicalImpl + 'static>(
932 x: SEXP,
933 ) -> c_int {
934 i32::from(Altrep::get_state::<StateType>(x).no_na())
935 }
936
937 unsafe extern "C" fn altlogical_Sum<StateType: AltLogicalImpl + 'static>(
938 x: SEXP,
939 narm: Rboolean,
940 ) -> SEXP {
941 Altrep::get_state::<StateType>(x)
942 .sum(narm == Rboolean::TRUE)
943 .get()
944 }
945
946 R_set_altlogical_Elt_method(class_ptr, Some(altlogical_Elt::<StateType>));
947 R_set_altlogical_Get_region_method(class_ptr, Some(altlogical_Get_region::<StateType>));
948 R_set_altlogical_Is_sorted_method(class_ptr, Some(altlogical_Is_sorted::<StateType>));
949 R_set_altlogical_No_NA_method(class_ptr, Some(altlogical_No_NA::<StateType>));
950 R_set_altlogical_Sum_method(class_ptr, Some(altlogical_Sum::<StateType>));
951
952 class
953 })
954 }
955
956 pub fn make_altraw_class<StateType: AltrepImpl + AltRawImpl + 'static>(
958 name: &str,
959 base: &str,
960 ) -> Robj {
961 #![allow(non_snake_case)]
962
963 single_threaded(|| unsafe {
964 let class = Altrep::altrep_class::<StateType>(Rtype::Raw, name, base);
965 let class_ptr = R_altrep_class_t { ptr: class.get() };
966
967 unsafe extern "C" fn altraw_Elt<StateType: AltRawImpl + 'static>(
968 x: SEXP,
969 i: R_xlen_t,
970 ) -> Rbyte {
971 Altrep::get_state::<StateType>(x).elt(i as usize) as Rbyte
972 }
973
974 unsafe extern "C" fn altraw_Get_region<StateType: AltRawImpl + 'static>(
975 x: SEXP,
976 i: R_xlen_t,
977 n: R_xlen_t,
978 buf: *mut u8,
979 ) -> R_xlen_t {
980 let slice = std::slice::from_raw_parts_mut(buf, n as usize);
981 Altrep::get_state::<StateType>(x).get_region(i as usize, slice) as R_xlen_t
982 }
983
984 R_set_altraw_Elt_method(class_ptr, Some(altraw_Elt::<StateType>));
985 R_set_altraw_Get_region_method(class_ptr, Some(altraw_Get_region::<StateType>));
986
987 class
988 })
989 }
990
991 pub fn make_altcomplex_class<StateType: AltrepImpl + AltComplexImpl + 'static>(
993 name: &str,
994 base: &str,
995 ) -> Robj {
996 #![allow(non_snake_case)]
997
998 single_threaded(|| unsafe {
999 let class = Altrep::altrep_class::<StateType>(Rtype::Complexes, name, base);
1000 let class_ptr = R_altrep_class_t { ptr: class.get() };
1001
1002 unsafe extern "C" fn altcomplex_Elt<StateType: AltComplexImpl + 'static>(
1003 x: SEXP,
1004 i: R_xlen_t,
1005 ) -> Rcomplex {
1006 std::mem::transmute(Altrep::get_state::<StateType>(x).elt(i as usize))
1007 }
1008
1009 unsafe extern "C" fn altcomplex_Get_region<StateType: AltComplexImpl + 'static>(
1010 x: SEXP,
1011 i: R_xlen_t,
1012 n: R_xlen_t,
1013 buf: *mut Rcomplex,
1014 ) -> R_xlen_t {
1015 let slice = std::slice::from_raw_parts_mut(buf as *mut Rcplx, n as usize);
1016 Altrep::get_state::<StateType>(x).get_region(i as usize, slice) as R_xlen_t
1017 }
1018
1019 R_set_altcomplex_Elt_method(class_ptr, Some(altcomplex_Elt::<StateType>));
1020 R_set_altcomplex_Get_region_method(class_ptr, Some(altcomplex_Get_region::<StateType>));
1021
1022 class
1023 })
1024 }
1025
1026 pub fn make_altstring_class<StateType: AltrepImpl + AltStringImpl + 'static>(
1028 name: &str,
1029 base: &str,
1030 ) -> Robj {
1031 #![allow(non_snake_case)]
1032 use std::os::raw::c_int;
1033
1034 single_threaded(|| unsafe {
1035 let class = Altrep::altrep_class::<StateType>(Rtype::Strings, name, base);
1036 let class_ptr = R_altrep_class_t { ptr: class.get() };
1037
1038 unsafe extern "C" fn altstring_Elt<StateType: AltStringImpl + 'static>(
1039 x: SEXP,
1040 i: R_xlen_t,
1041 ) -> SEXP {
1042 Altrep::get_state::<StateType>(x).elt(i as usize).get()
1043 }
1044
1045 unsafe extern "C" fn altstring_Set_elt<StateType: AltStringImpl + 'static>(
1046 x: SEXP,
1047 i: R_xlen_t,
1048 v: SEXP,
1049 ) {
1050 Altrep::get_state_mut::<StateType>(x)
1051 .set_elt(i as usize, Robj::from_sexp(v).try_into().unwrap())
1052 }
1053
1054 unsafe extern "C" fn altstring_Is_sorted<StateType: AltStringImpl + 'static>(
1055 x: SEXP,
1056 ) -> c_int {
1057 Altrep::get_state::<StateType>(x).is_sorted().inner() as c_int
1058 }
1059
1060 unsafe extern "C" fn altstring_No_NA<StateType: AltStringImpl + 'static>(
1061 x: SEXP,
1062 ) -> c_int {
1063 i32::from(Altrep::get_state::<StateType>(x).no_na())
1064 }
1065
1066 R_set_altstring_Elt_method(class_ptr, Some(altstring_Elt::<StateType>));
1067 R_set_altstring_Set_elt_method(class_ptr, Some(altstring_Set_elt::<StateType>));
1068 R_set_altstring_Is_sorted_method(class_ptr, Some(altstring_Is_sorted::<StateType>));
1069 R_set_altstring_No_NA_method(class_ptr, Some(altstring_No_NA::<StateType>));
1070
1071 class
1072 })
1073 }
1074
1075 #[cfg(use_r_altlist)]
1076 pub fn make_altlist_class<StateType: AltrepImpl + AltListImpl + 'static>(
1077 name: &str,
1078 base: &str,
1079 ) -> Robj {
1080 #![allow(non_snake_case)]
1081
1082 single_threaded(|| unsafe {
1083 let class = Altrep::altrep_class::<StateType>(Rtype::List, name, base);
1084 let class_ptr = R_altrep_class_t { ptr: class.get() };
1085
1086 unsafe extern "C" fn altlist_Elt<StateType: AltListImpl + 'static>(
1087 x: SEXP,
1088 i: R_xlen_t,
1089 ) -> SEXP {
1090 Altrep::get_state::<StateType>(x).elt(i as usize).get()
1091 }
1092
1093 unsafe extern "C" fn altlist_Set_elt<StateType: AltListImpl + 'static>(
1094 x: SEXP,
1095 i: R_xlen_t,
1096 v: SEXP,
1097 ) {
1098 Altrep::get_state_mut::<StateType>(x).set_elt(i as usize, Robj::from_sexp(v))
1099 }
1100
1101 R_set_altlist_Elt_method(class_ptr, Some(altlist_Elt::<StateType>));
1102 R_set_altlist_Set_elt_method(class_ptr, Some(altlist_Set_elt::<StateType>));
1103 class
1104 })
1105 }
1106
1107 make_from_iterator!(
1108 make_altinteger_from_iterator,
1109 make_altinteger_class,
1110 AltIntegerImpl,
1111 Rint,
1112 i32
1113 );
1114 make_from_iterator!(
1115 make_altlogical_from_iterator,
1116 make_altlogical_class,
1117 AltLogicalImpl,
1118 Rbool,
1119 i32
1120 );
1121 make_from_iterator!(
1122 make_altreal_from_iterator,
1123 make_altreal_class,
1124 AltRealImpl,
1125 Rfloat,
1126 f64
1127 );
1128 make_from_iterator!(
1129 make_altcomplex_from_iterator,
1130 make_altcomplex_class,
1131 AltComplexImpl,
1132 Rcplx,
1133 c64
1134 );
1135}
1136
1137impl<Iter: ExactSizeIterator + std::fmt::Debug + Clone> AltrepImpl for Iter {
1138 fn length(&self) -> usize {
1139 self.len()
1140 }
1141}