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
48pub trait AltrepImpl: Clone + std::fmt::Debug {
52 #[cfg(feature = "non-api")]
53 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 fn unserialize(_class: Robj, _state: Robj) -> Robj {
76 ().into()
78 }
79
80 fn serialized_state(_x: SEXP) -> Robj {
82 ().into()
84 }
85
86 fn duplicate_ex(x: SEXP, deep: bool) -> Robj {
89 Self::duplicate(x, deep)
90 }
91
92 fn duplicate(x: SEXP, _deep: bool) -> Robj {
95 Robj::from_sexp(manifest(x))
96 }
97
98 fn coerce(_x: SEXP, _ty: Rtype) -> Robj {
100 ().into()
101 }
102
103 fn inspect(
105 &self,
106 _pre: i32,
107 _deep: bool,
108 _pvec: i32, ) -> bool {
110 rprintln!("{:?}", self);
111 true
112 }
113
114 fn length(&self) -> usize;
117
118 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 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 fn extract_subset(_x: Robj, _indx: Robj, _call: Robj) -> Robj {
148 Robj::from(())
151 }
152}
153
154fn 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 fn elt(&self, _index: usize) -> Rint;
209
210 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 fn is_sorted(&self) -> Rbool {
227 Rbool::na()
228 }
229
230 fn no_na(&self) -> bool {
232 false
233 }
234
235 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 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 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 fn elt(&self, _index: usize) -> Rfloat;
290
291 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 fn is_sorted(&self) -> Rbool {
308 Rbool::na()
309 }
310
311 fn no_na(&self) -> bool {
313 false
314 }
315
316 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 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 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 fn elt(&self, _index: usize) -> Rbool;
367
368 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 fn is_sorted(&self) -> Rbool {
385 Rbool::na()
386 }
387
388 fn no_na(&self) -> bool {
390 false
391 }
392
393 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 fn elt(&self, _index: usize) -> u8;
408
409 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 fn elt(&self, _index: usize) -> Rcplx;
428
429 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 fn elt(&self, _index: usize) -> Rstr;
448
449 fn set_elt(&mut self, _index: usize, _value: Rstr) {}
451
452 fn is_sorted(&self) -> Rbool {
454 Rbool::na()
455 }
456
457 fn no_na(&self) -> bool {
459 false
460 }
461}
462
463#[cfg(use_r_altlist)]
464pub trait AltListImpl {
465 fn elt(&self, _index: usize) -> Robj;
468
469 fn set_elt(&mut self, _index: usize, _value: Robj) {}
471}
472
473impl Altrep {
474 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 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 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 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 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 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 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 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 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 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 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}