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 unsafe { 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 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 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 fn extract_subset(_x: Robj, _indx: Robj, _call: Robj) -> Robj {
167 Robj::from(())
170 }
171}
172
173fn 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 fn elt(&self, _index: usize) -> Rint;
228
229 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 fn is_sorted(&self) -> Rbool {
246 Rbool::na()
247 }
248
249 fn no_na(&self) -> bool {
251 false
252 }
253
254 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 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 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 fn elt(&self, _index: usize) -> Rfloat;
309
310 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 fn is_sorted(&self) -> Rbool {
327 Rbool::na()
328 }
329
330 fn no_na(&self) -> bool {
332 false
333 }
334
335 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 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 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 fn elt(&self, _index: usize) -> Rbool;
386
387 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 fn is_sorted(&self) -> Rbool {
404 Rbool::na()
405 }
406
407 fn no_na(&self) -> bool {
409 false
410 }
411
412 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 fn elt(&self, _index: usize) -> u8;
427
428 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 fn elt(&self, _index: usize) -> Rcplx;
447
448 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
464make_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 fn elt(&self, _index: usize) -> Rstr;
473
474 fn set_elt(&mut self, _index: usize, _value: Rstr) {}
476
477 fn is_sorted(&self) -> Rbool {
479 Rbool::na()
480 }
481
482 fn no_na(&self) -> bool {
484 false
485 }
486}
487
488#[cfg(use_r_altlist)]
489pub trait AltListImpl {
490 fn elt(&self, _index: usize) -> Robj;
493
494 fn set_elt(&mut self, _index: usize, _value: Robj) {}
496}
497
498impl Altrep {
499 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 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 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 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 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 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 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 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 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 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 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}