1use crate::altrep_traits::{
35 AltComplex, AltInteger, AltList, AltLogical, AltRaw, AltReal, AltString, AltVec, Altrep,
36 AltrepGuard,
37};
38use crate::sys::altrep::R_altrep_class_t;
39use crate::{R_xlen_t, Rboolean, Rbyte, Rcomplex, SEXP, SEXPTYPE};
40use core::ffi::c_void;
41
42#[inline(always)]
53fn guarded_altrep_call<T: Altrep, F, R>(f: F) -> R
54where
55 F: FnOnce() -> R,
56{
57 match T::GUARD {
58 AltrepGuard::Unsafe => f(),
59 AltrepGuard::RustUnwind => crate::ffi_guard::guarded_ffi_call(
60 f,
61 crate::ffi_guard::GuardMode::CatchUnwind,
62 crate::panic_telemetry::PanicSource::Altrep,
63 ),
64 AltrepGuard::RUnwind => crate::ffi_guard::guarded_ffi_call(
65 f,
66 crate::ffi_guard::GuardMode::RUnwind,
67 crate::panic_telemetry::PanicSource::Altrep,
68 ),
69 }
70}
71
72pub unsafe extern "C-unwind" fn t_length<T: Altrep>(x: SEXP) -> R_xlen_t {
78 guarded_altrep_call::<T, _, _>(|| T::length(x))
79}
80
81pub unsafe extern "C-unwind" fn t_duplicate<T: Altrep>(x: SEXP, deep: Rboolean) -> SEXP {
85 guarded_altrep_call::<T, _, _>(|| T::duplicate(x, matches!(deep, Rboolean::TRUE)))
86}
87
88pub unsafe extern "C-unwind" fn t_duplicate_ex<T: Altrep>(x: SEXP, deep: Rboolean) -> SEXP {
92 guarded_altrep_call::<T, _, _>(|| T::duplicate_ex(x, matches!(deep, Rboolean::TRUE)))
93}
94
95pub unsafe extern "C-unwind" fn t_inspect<T: Altrep>(
99 x: SEXP,
100 pre: i32,
101 deep: i32,
102 pvec: i32,
103 inspect_subtree: Option<unsafe extern "C-unwind" fn(SEXP, i32, i32, i32)>,
104) -> Rboolean {
105 guarded_altrep_call::<T, _, _>(|| {
106 if T::inspect(x, pre, deep, pvec, inspect_subtree) {
107 Rboolean::TRUE
108 } else {
109 Rboolean::FALSE
110 }
111 })
112}
113
114pub unsafe extern "C-unwind" fn t_serialized_state<T: Altrep>(x: SEXP) -> SEXP {
118 guarded_altrep_call::<T, _, _>(|| T::serialized_state(x))
119}
120
121pub unsafe extern "C-unwind" fn t_unserialize<T: Altrep>(class: SEXP, state: SEXP) -> SEXP {
125 guarded_altrep_call::<T, _, _>(|| T::unserialize(class, state))
126}
127
128pub unsafe extern "C-unwind" fn t_unserialize_ex<T: Altrep>(
132 class: SEXP,
133 state: SEXP,
134 attr: SEXP,
135 objf: ::std::os::raw::c_int,
136 levs: ::std::os::raw::c_int,
137) -> SEXP {
138 guarded_altrep_call::<T, _, _>(|| T::unserialize_ex(class, state, attr, objf, levs))
139}
140
141pub unsafe extern "C-unwind" fn t_coerce<T: Altrep>(x: SEXP, to_type: SEXPTYPE) -> SEXP {
145 guarded_altrep_call::<T, _, _>(|| T::coerce(x, to_type))
146}
147pub unsafe extern "C-unwind" fn t_dataptr<T: AltVec>(x: SEXP, w: Rboolean) -> *mut c_void {
155 guarded_altrep_call::<T, _, _>(|| T::dataptr(x, matches!(w, Rboolean::TRUE)))
156}
157
158pub unsafe extern "C-unwind" fn t_dataptr_or_null<T: AltVec>(x: SEXP) -> *const c_void {
162 guarded_altrep_call::<T, _, _>(|| T::dataptr_or_null(x))
163}
164
165pub unsafe extern "C-unwind" fn t_extract_subset<T: AltVec>(
169 x: SEXP,
170 indx: SEXP,
171 call: SEXP,
172) -> SEXP {
173 guarded_altrep_call::<T, _, _>(|| T::extract_subset(x, indx, call))
174}
175pub unsafe extern "C-unwind" fn t_int_elt<T: AltInteger>(x: SEXP, i: R_xlen_t) -> i32 {
183 guarded_altrep_call::<T, _, _>(|| T::elt(x, i))
184}
185
186pub unsafe extern "C-unwind" fn t_int_get_region<T: AltInteger>(
190 x: SEXP,
191 i: R_xlen_t,
192 n: R_xlen_t,
193 out: *mut i32,
194) -> R_xlen_t {
195 if n <= 0 {
196 return 0;
197 }
198 let buf = unsafe { crate::altrep_impl::altrep_region_buf(out, n as usize) };
199 guarded_altrep_call::<T, _, _>(|| T::get_region(x, i, n, buf))
200}
201
202pub unsafe extern "C-unwind" fn t_int_is_sorted<T: AltInteger>(x: SEXP) -> i32 {
206 guarded_altrep_call::<T, _, _>(|| T::is_sorted(x))
207}
208
209pub unsafe extern "C-unwind" fn t_int_no_na<T: AltInteger>(x: SEXP) -> i32 {
213 guarded_altrep_call::<T, _, _>(|| T::no_na(x))
214}
215
216pub unsafe extern "C-unwind" fn t_int_sum<T: AltInteger>(x: SEXP, narm: Rboolean) -> SEXP {
220 guarded_altrep_call::<T, _, _>(|| T::sum(x, matches!(narm, Rboolean::TRUE)))
221}
222
223pub unsafe extern "C-unwind" fn t_int_min<T: AltInteger>(x: SEXP, narm: Rboolean) -> SEXP {
227 guarded_altrep_call::<T, _, _>(|| T::min(x, matches!(narm, Rboolean::TRUE)))
228}
229
230pub unsafe extern "C-unwind" fn t_int_max<T: AltInteger>(x: SEXP, narm: Rboolean) -> SEXP {
234 guarded_altrep_call::<T, _, _>(|| T::max(x, matches!(narm, Rboolean::TRUE)))
235}
236pub unsafe extern "C-unwind" fn t_real_elt<T: AltReal>(x: SEXP, i: R_xlen_t) -> f64 {
244 guarded_altrep_call::<T, _, _>(|| T::elt(x, i))
245}
246
247pub unsafe extern "C-unwind" fn t_real_get_region<T: AltReal>(
251 x: SEXP,
252 i: R_xlen_t,
253 n: R_xlen_t,
254 out: *mut f64,
255) -> R_xlen_t {
256 if n <= 0 {
257 return 0;
258 }
259 let buf = unsafe { crate::altrep_impl::altrep_region_buf(out, n as usize) };
260 guarded_altrep_call::<T, _, _>(|| T::get_region(x, i, n, buf))
261}
262
263pub unsafe extern "C-unwind" fn t_real_is_sorted<T: AltReal>(x: SEXP) -> i32 {
267 guarded_altrep_call::<T, _, _>(|| T::is_sorted(x))
268}
269
270pub unsafe extern "C-unwind" fn t_real_no_na<T: AltReal>(x: SEXP) -> i32 {
274 guarded_altrep_call::<T, _, _>(|| T::no_na(x))
275}
276
277pub unsafe extern "C-unwind" fn t_real_sum<T: AltReal>(x: SEXP, narm: Rboolean) -> SEXP {
281 guarded_altrep_call::<T, _, _>(|| T::sum(x, matches!(narm, Rboolean::TRUE)))
282}
283
284pub unsafe extern "C-unwind" fn t_real_min<T: AltReal>(x: SEXP, narm: Rboolean) -> SEXP {
288 guarded_altrep_call::<T, _, _>(|| T::min(x, matches!(narm, Rboolean::TRUE)))
289}
290
291pub unsafe extern "C-unwind" fn t_real_max<T: AltReal>(x: SEXP, narm: Rboolean) -> SEXP {
295 guarded_altrep_call::<T, _, _>(|| T::max(x, matches!(narm, Rboolean::TRUE)))
296}
297pub unsafe extern "C-unwind" fn t_lgl_elt<T: AltLogical>(x: SEXP, i: R_xlen_t) -> i32 {
305 guarded_altrep_call::<T, _, _>(|| T::elt(x, i))
306}
307
308pub unsafe extern "C-unwind" fn t_lgl_get_region<T: AltLogical>(
312 x: SEXP,
313 i: R_xlen_t,
314 n: R_xlen_t,
315 out: *mut i32,
316) -> R_xlen_t {
317 if n <= 0 {
318 return 0;
319 }
320 let buf = unsafe { crate::altrep_impl::altrep_region_buf(out, n as usize) };
321 guarded_altrep_call::<T, _, _>(|| T::get_region(x, i, n, buf))
322}
323
324pub unsafe extern "C-unwind" fn t_lgl_is_sorted<T: AltLogical>(x: SEXP) -> i32 {
328 guarded_altrep_call::<T, _, _>(|| T::is_sorted(x))
329}
330
331pub unsafe extern "C-unwind" fn t_lgl_no_na<T: AltLogical>(x: SEXP) -> i32 {
335 guarded_altrep_call::<T, _, _>(|| T::no_na(x))
336}
337
338pub unsafe extern "C-unwind" fn t_lgl_sum<T: AltLogical>(x: SEXP, narm: Rboolean) -> SEXP {
342 guarded_altrep_call::<T, _, _>(|| T::sum(x, matches!(narm, Rboolean::TRUE)))
343}
344
345pub unsafe extern "C-unwind" fn t_raw_elt<T: AltRaw>(x: SEXP, i: R_xlen_t) -> Rbyte {
354 guarded_altrep_call::<T, _, _>(|| T::elt(x, i))
355}
356
357pub unsafe extern "C-unwind" fn t_raw_get_region<T: AltRaw>(
361 x: SEXP,
362 i: R_xlen_t,
363 n: R_xlen_t,
364 out: *mut Rbyte,
365) -> R_xlen_t {
366 if n <= 0 {
367 return 0;
368 }
369 let buf = unsafe { crate::altrep_impl::altrep_region_buf(out, n as usize) };
370 guarded_altrep_call::<T, _, _>(|| T::get_region(x, i, n, buf))
371}
372pub unsafe extern "C-unwind" fn t_cplx_elt<T: AltComplex>(x: SEXP, i: R_xlen_t) -> Rcomplex {
380 guarded_altrep_call::<T, _, _>(|| T::elt(x, i))
381}
382
383pub unsafe extern "C-unwind" fn t_cplx_get_region<T: AltComplex>(
387 x: SEXP,
388 i: R_xlen_t,
389 n: R_xlen_t,
390 out: *mut Rcomplex,
391) -> R_xlen_t {
392 if n <= 0 {
393 return 0;
394 }
395 let buf = unsafe { crate::altrep_impl::altrep_region_buf(out, n as usize) };
396 guarded_altrep_call::<T, _, _>(|| T::get_region(x, i, n, buf))
397}
398pub unsafe extern "C-unwind" fn t_str_elt<T: AltString>(x: SEXP, i: R_xlen_t) -> SEXP {
406 guarded_altrep_call::<T, _, _>(|| T::elt(x, i))
407}
408
409pub unsafe extern "C-unwind" fn t_str_set_elt<T: AltString>(x: SEXP, i: R_xlen_t, v: SEXP) {
413 guarded_altrep_call::<T, _, _>(|| T::set_elt(x, i, v))
414}
415
416pub unsafe extern "C-unwind" fn t_str_is_sorted<T: AltString>(x: SEXP) -> i32 {
420 guarded_altrep_call::<T, _, _>(|| T::is_sorted(x))
421}
422
423pub unsafe extern "C-unwind" fn t_str_no_na<T: AltString>(x: SEXP) -> i32 {
427 guarded_altrep_call::<T, _, _>(|| T::no_na(x))
428}
429pub unsafe extern "C-unwind" fn t_list_elt<T: AltList>(x: SEXP, i: R_xlen_t) -> SEXP {
437 guarded_altrep_call::<T, _, _>(|| T::elt(x, i))
438}
439
440pub unsafe extern "C-unwind" fn t_list_set_elt<T: AltList>(x: SEXP, i: R_xlen_t, v: SEXP) {
444 guarded_altrep_call::<T, _, _>(|| T::set_elt(x, i, v))
445}
446pub unsafe fn install_base<T: Altrep>(cls: R_altrep_class_t) {
454 unsafe { cls.set_length_method(Some(t_length::<T>)) };
456
457 if T::HAS_SERIALIZED_STATE {
459 unsafe { cls.set_serialized_state_method(Some(t_serialized_state::<T>)) };
460 }
461 if T::HAS_UNSERIALIZE {
462 unsafe { cls.set_unserialize_method(Some(t_unserialize::<T>)) };
463 }
464 if T::HAS_UNSERIALIZE_EX {
465 unsafe { cls.set_unserialize_ex_method(Some(t_unserialize_ex::<T>)) };
466 }
467 if T::HAS_DUPLICATE {
468 unsafe { cls.set_duplicate_method(Some(t_duplicate::<T>)) };
469 }
470 if T::HAS_DUPLICATE_EX {
471 unsafe { cls.set_duplicate_ex_method(Some(t_duplicate_ex::<T>)) };
472 }
473 if T::HAS_COERCE {
474 unsafe { cls.set_coerce_method(Some(t_coerce::<T>)) };
475 }
476 if T::HAS_INSPECT {
477 unsafe { cls.set_inspect_method(Some(t_inspect::<T>)) };
478 }
479}
480
481pub unsafe fn install_vec<T: AltVec>(cls: R_altrep_class_t) {
485 if T::HAS_DATAPTR {
486 unsafe { cls.set_dataptr_method(Some(t_dataptr::<T>)) };
487 }
488 if T::HAS_DATAPTR_OR_NULL {
489 unsafe { cls.set_dataptr_or_null_method(Some(t_dataptr_or_null::<T>)) };
490 }
491 if T::HAS_EXTRACT_SUBSET {
492 unsafe { cls.set_extract_subset_method(Some(t_extract_subset::<T>)) };
493 }
494}
495
496macro_rules! def_installer {
501 (
502 $(#[$meta:meta])*
503 $fn_name:ident < T: $trait:ident > {
504 $( $has:ident => $method:ident, $tramp:ident; )*
505 }
506 ) => {
507 $(#[$meta])*
508 pub unsafe fn $fn_name<T: $trait>(cls: R_altrep_class_t) {
509 $(
510 if T::$has { unsafe { cls.$method(Some($tramp::<T>)) } }
511 )*
512 }
513 };
514 (
515 $(#[$meta:meta])*
516 $fn_name:ident < T: $trait:ident > {
517 $( $has:ident => $method:ident, $tramp:ident; )*
518 }
519 always { $( $always_method:ident, $always_tramp:ident; )* }
520 ) => {
521 $(#[$meta])*
522 pub unsafe fn $fn_name<T: $trait>(cls: R_altrep_class_t) {
523 $(
524 unsafe { cls.$always_method(Some($always_tramp::<T>)) }
525 )*
526 $(
527 if T::$has { unsafe { cls.$method(Some($tramp::<T>)) } }
528 )*
529 }
530 };
531}
532
533def_installer! {
534 install_int<T: AltInteger> {
538 HAS_ELT => set_integer_elt_method, t_int_elt;
539 HAS_GET_REGION => set_integer_get_region_method, t_int_get_region;
540 HAS_IS_SORTED => set_integer_is_sorted_method, t_int_is_sorted;
541 HAS_NO_NA => set_integer_no_na_method, t_int_no_na;
542 HAS_SUM => set_integer_sum_method, t_int_sum;
543 HAS_MIN => set_integer_min_method, t_int_min;
544 HAS_MAX => set_integer_max_method, t_int_max;
545 }
546}
547
548def_installer! {
549 install_real<T: AltReal> {
553 HAS_ELT => set_real_elt_method, t_real_elt;
554 HAS_GET_REGION => set_real_get_region_method, t_real_get_region;
555 HAS_IS_SORTED => set_real_is_sorted_method, t_real_is_sorted;
556 HAS_NO_NA => set_real_no_na_method, t_real_no_na;
557 HAS_SUM => set_real_sum_method, t_real_sum;
558 HAS_MIN => set_real_min_method, t_real_min;
559 HAS_MAX => set_real_max_method, t_real_max;
560 }
561}
562
563def_installer! {
564 install_lgl<T: AltLogical> {
568 HAS_ELT => set_logical_elt_method, t_lgl_elt;
569 HAS_GET_REGION => set_logical_get_region_method, t_lgl_get_region;
570 HAS_IS_SORTED => set_logical_is_sorted_method, t_lgl_is_sorted;
571 HAS_NO_NA => set_logical_no_na_method, t_lgl_no_na;
572 HAS_SUM => set_logical_sum_method, t_lgl_sum;
573 }
574}
575
576def_installer! {
577 install_raw<T: AltRaw> {
581 HAS_ELT => set_raw_elt_method, t_raw_elt;
582 HAS_GET_REGION => set_raw_get_region_method, t_raw_get_region;
583 }
584}
585
586def_installer! {
587 install_cplx<T: AltComplex> {
591 HAS_ELT => set_complex_elt_method, t_cplx_elt;
592 HAS_GET_REGION => set_complex_get_region_method, t_cplx_get_region;
593 }
594}
595
596def_installer! {
597 install_str<T: AltString> {
602 HAS_SET_ELT => set_string_set_elt_method, t_str_set_elt;
603 HAS_IS_SORTED => set_string_is_sorted_method, t_str_is_sorted;
604 HAS_NO_NA => set_string_no_na_method, t_str_no_na;
605 }
606 always { set_string_elt_method, t_str_elt; }
607}
608
609def_installer! {
610 install_list<T: AltList> {
615 HAS_SET_ELT => set_list_set_elt_method, t_list_set_elt;
616 }
617 always { set_list_elt_method, t_list_elt; }
618}
619