1use crate::altrep_traits::{
13 AltComplex, AltInteger, AltList, AltLogical, AltRaw, AltReal, AltString, AltVec, Altrep,
14 AltrepGuard,
15};
16use crate::ffi::altrep::R_altrep_class_t;
17use crate::ffi::*;
18use core::ffi::c_void;
19
20#[inline(always)]
31fn guarded_altrep_call<T: Altrep, F, R>(f: F) -> R
32where
33 F: FnOnce() -> R,
34{
35 match T::GUARD {
36 AltrepGuard::Unsafe => f(),
37 AltrepGuard::RustUnwind => crate::ffi_guard::guarded_ffi_call(
38 f,
39 crate::ffi_guard::GuardMode::CatchUnwind,
40 crate::panic_telemetry::PanicSource::Altrep,
41 ),
42 AltrepGuard::RUnwind => crate::ffi_guard::guarded_ffi_call(
43 f,
44 crate::ffi_guard::GuardMode::RUnwind,
45 crate::panic_telemetry::PanicSource::Altrep,
46 ),
47 }
48}
49
50pub unsafe extern "C-unwind" fn t_length<T: Altrep>(x: SEXP) -> R_xlen_t {
56 guarded_altrep_call::<T, _, _>(|| T::length(x))
57}
58
59pub unsafe extern "C-unwind" fn t_duplicate<T: Altrep>(x: SEXP, deep: Rboolean) -> SEXP {
63 guarded_altrep_call::<T, _, _>(|| T::duplicate(x, matches!(deep, Rboolean::TRUE)))
64}
65
66pub unsafe extern "C-unwind" fn t_duplicate_ex<T: Altrep>(x: SEXP, deep: Rboolean) -> SEXP {
70 guarded_altrep_call::<T, _, _>(|| T::duplicate_ex(x, matches!(deep, Rboolean::TRUE)))
71}
72
73pub unsafe extern "C-unwind" fn t_inspect<T: Altrep>(
77 x: SEXP,
78 pre: i32,
79 deep: i32,
80 pvec: i32,
81 inspect_subtree: Option<unsafe extern "C-unwind" fn(SEXP, i32, i32, i32)>,
82) -> Rboolean {
83 guarded_altrep_call::<T, _, _>(|| {
84 if T::inspect(x, pre, deep, pvec, inspect_subtree) {
85 Rboolean::TRUE
86 } else {
87 Rboolean::FALSE
88 }
89 })
90}
91
92pub unsafe extern "C-unwind" fn t_serialized_state<T: Altrep>(x: SEXP) -> SEXP {
96 guarded_altrep_call::<T, _, _>(|| T::serialized_state(x))
97}
98
99pub unsafe extern "C-unwind" fn t_unserialize<T: Altrep>(class: SEXP, state: SEXP) -> SEXP {
103 guarded_altrep_call::<T, _, _>(|| T::unserialize(class, state))
104}
105
106pub unsafe extern "C-unwind" fn t_unserialize_ex<T: Altrep>(
110 class: SEXP,
111 state: SEXP,
112 attr: SEXP,
113 objf: ::std::os::raw::c_int,
114 levs: ::std::os::raw::c_int,
115) -> SEXP {
116 guarded_altrep_call::<T, _, _>(|| T::unserialize_ex(class, state, attr, objf, levs))
117}
118
119pub unsafe extern "C-unwind" fn t_coerce<T: Altrep>(x: SEXP, to_type: SEXPTYPE) -> SEXP {
123 guarded_altrep_call::<T, _, _>(|| T::coerce(x, to_type))
124}
125pub unsafe extern "C-unwind" fn t_dataptr<T: AltVec>(x: SEXP, w: Rboolean) -> *mut c_void {
133 guarded_altrep_call::<T, _, _>(|| T::dataptr(x, matches!(w, Rboolean::TRUE)))
134}
135
136pub unsafe extern "C-unwind" fn t_dataptr_or_null<T: AltVec>(x: SEXP) -> *const c_void {
140 guarded_altrep_call::<T, _, _>(|| T::dataptr_or_null(x))
141}
142
143pub unsafe extern "C-unwind" fn t_extract_subset<T: AltVec>(
147 x: SEXP,
148 indx: SEXP,
149 call: SEXP,
150) -> SEXP {
151 guarded_altrep_call::<T, _, _>(|| T::extract_subset(x, indx, call))
152}
153pub unsafe extern "C-unwind" fn t_int_elt<T: AltInteger>(x: SEXP, i: R_xlen_t) -> i32 {
161 guarded_altrep_call::<T, _, _>(|| T::elt(x, i))
162}
163
164pub unsafe extern "C-unwind" fn t_int_get_region<T: AltInteger>(
168 x: SEXP,
169 i: R_xlen_t,
170 n: R_xlen_t,
171 out: *mut i32,
172) -> R_xlen_t {
173 if n <= 0 {
174 return 0;
175 }
176 let buf = unsafe { crate::altrep_impl::altrep_region_buf(out, n as usize) };
177 guarded_altrep_call::<T, _, _>(|| T::get_region(x, i, n, buf))
178}
179
180pub unsafe extern "C-unwind" fn t_int_is_sorted<T: AltInteger>(x: SEXP) -> i32 {
184 guarded_altrep_call::<T, _, _>(|| T::is_sorted(x))
185}
186
187pub unsafe extern "C-unwind" fn t_int_no_na<T: AltInteger>(x: SEXP) -> i32 {
191 guarded_altrep_call::<T, _, _>(|| T::no_na(x))
192}
193
194pub unsafe extern "C-unwind" fn t_int_sum<T: AltInteger>(x: SEXP, narm: Rboolean) -> SEXP {
198 guarded_altrep_call::<T, _, _>(|| T::sum(x, matches!(narm, Rboolean::TRUE)))
199}
200
201pub unsafe extern "C-unwind" fn t_int_min<T: AltInteger>(x: SEXP, narm: Rboolean) -> SEXP {
205 guarded_altrep_call::<T, _, _>(|| T::min(x, matches!(narm, Rboolean::TRUE)))
206}
207
208pub unsafe extern "C-unwind" fn t_int_max<T: AltInteger>(x: SEXP, narm: Rboolean) -> SEXP {
212 guarded_altrep_call::<T, _, _>(|| T::max(x, matches!(narm, Rboolean::TRUE)))
213}
214pub unsafe extern "C-unwind" fn t_real_elt<T: AltReal>(x: SEXP, i: R_xlen_t) -> f64 {
222 guarded_altrep_call::<T, _, _>(|| T::elt(x, i))
223}
224
225pub unsafe extern "C-unwind" fn t_real_get_region<T: AltReal>(
229 x: SEXP,
230 i: R_xlen_t,
231 n: R_xlen_t,
232 out: *mut f64,
233) -> R_xlen_t {
234 if n <= 0 {
235 return 0;
236 }
237 let buf = unsafe { crate::altrep_impl::altrep_region_buf(out, n as usize) };
238 guarded_altrep_call::<T, _, _>(|| T::get_region(x, i, n, buf))
239}
240
241pub unsafe extern "C-unwind" fn t_real_is_sorted<T: AltReal>(x: SEXP) -> i32 {
245 guarded_altrep_call::<T, _, _>(|| T::is_sorted(x))
246}
247
248pub unsafe extern "C-unwind" fn t_real_no_na<T: AltReal>(x: SEXP) -> i32 {
252 guarded_altrep_call::<T, _, _>(|| T::no_na(x))
253}
254
255pub unsafe extern "C-unwind" fn t_real_sum<T: AltReal>(x: SEXP, narm: Rboolean) -> SEXP {
259 guarded_altrep_call::<T, _, _>(|| T::sum(x, matches!(narm, Rboolean::TRUE)))
260}
261
262pub unsafe extern "C-unwind" fn t_real_min<T: AltReal>(x: SEXP, narm: Rboolean) -> SEXP {
266 guarded_altrep_call::<T, _, _>(|| T::min(x, matches!(narm, Rboolean::TRUE)))
267}
268
269pub unsafe extern "C-unwind" fn t_real_max<T: AltReal>(x: SEXP, narm: Rboolean) -> SEXP {
273 guarded_altrep_call::<T, _, _>(|| T::max(x, matches!(narm, Rboolean::TRUE)))
274}
275pub unsafe extern "C-unwind" fn t_lgl_elt<T: AltLogical>(x: SEXP, i: R_xlen_t) -> i32 {
283 guarded_altrep_call::<T, _, _>(|| T::elt(x, i))
284}
285
286pub unsafe extern "C-unwind" fn t_lgl_get_region<T: AltLogical>(
290 x: SEXP,
291 i: R_xlen_t,
292 n: R_xlen_t,
293 out: *mut i32,
294) -> R_xlen_t {
295 if n <= 0 {
296 return 0;
297 }
298 let buf = unsafe { crate::altrep_impl::altrep_region_buf(out, n as usize) };
299 guarded_altrep_call::<T, _, _>(|| T::get_region(x, i, n, buf))
300}
301
302pub unsafe extern "C-unwind" fn t_lgl_is_sorted<T: AltLogical>(x: SEXP) -> i32 {
306 guarded_altrep_call::<T, _, _>(|| T::is_sorted(x))
307}
308
309pub unsafe extern "C-unwind" fn t_lgl_no_na<T: AltLogical>(x: SEXP) -> i32 {
313 guarded_altrep_call::<T, _, _>(|| T::no_na(x))
314}
315
316pub unsafe extern "C-unwind" fn t_lgl_sum<T: AltLogical>(x: SEXP, narm: Rboolean) -> SEXP {
320 guarded_altrep_call::<T, _, _>(|| T::sum(x, matches!(narm, Rboolean::TRUE)))
321}
322
323pub unsafe extern "C-unwind" fn t_raw_elt<T: AltRaw>(x: SEXP, i: R_xlen_t) -> Rbyte {
332 guarded_altrep_call::<T, _, _>(|| T::elt(x, i))
333}
334
335pub unsafe extern "C-unwind" fn t_raw_get_region<T: AltRaw>(
339 x: SEXP,
340 i: R_xlen_t,
341 n: R_xlen_t,
342 out: *mut Rbyte,
343) -> R_xlen_t {
344 if n <= 0 {
345 return 0;
346 }
347 let buf = unsafe { crate::altrep_impl::altrep_region_buf(out, n as usize) };
348 guarded_altrep_call::<T, _, _>(|| T::get_region(x, i, n, buf))
349}
350pub unsafe extern "C-unwind" fn t_cplx_elt<T: AltComplex>(x: SEXP, i: R_xlen_t) -> Rcomplex {
358 guarded_altrep_call::<T, _, _>(|| T::elt(x, i))
359}
360
361pub unsafe extern "C-unwind" fn t_cplx_get_region<T: AltComplex>(
365 x: SEXP,
366 i: R_xlen_t,
367 n: R_xlen_t,
368 out: *mut Rcomplex,
369) -> R_xlen_t {
370 if n <= 0 {
371 return 0;
372 }
373 let buf = unsafe { crate::altrep_impl::altrep_region_buf(out, n as usize) };
374 guarded_altrep_call::<T, _, _>(|| T::get_region(x, i, n, buf))
375}
376pub unsafe extern "C-unwind" fn t_str_elt<T: AltString>(x: SEXP, i: R_xlen_t) -> SEXP {
384 guarded_altrep_call::<T, _, _>(|| T::elt(x, i))
385}
386
387pub unsafe extern "C-unwind" fn t_str_set_elt<T: AltString>(x: SEXP, i: R_xlen_t, v: SEXP) {
391 guarded_altrep_call::<T, _, _>(|| T::set_elt(x, i, v))
392}
393
394pub unsafe extern "C-unwind" fn t_str_is_sorted<T: AltString>(x: SEXP) -> i32 {
398 guarded_altrep_call::<T, _, _>(|| T::is_sorted(x))
399}
400
401pub unsafe extern "C-unwind" fn t_str_no_na<T: AltString>(x: SEXP) -> i32 {
405 guarded_altrep_call::<T, _, _>(|| T::no_na(x))
406}
407pub unsafe extern "C-unwind" fn t_list_elt<T: AltList>(x: SEXP, i: R_xlen_t) -> SEXP {
415 guarded_altrep_call::<T, _, _>(|| T::elt(x, i))
416}
417
418pub unsafe extern "C-unwind" fn t_list_set_elt<T: AltList>(x: SEXP, i: R_xlen_t, v: SEXP) {
422 guarded_altrep_call::<T, _, _>(|| T::set_elt(x, i, v))
423}
424pub unsafe fn install_base<T: Altrep>(cls: R_altrep_class_t) {
432 unsafe { cls.set_length_method(Some(t_length::<T>)) };
434
435 if T::HAS_SERIALIZED_STATE {
437 unsafe { cls.set_serialized_state_method(Some(t_serialized_state::<T>)) };
438 }
439 if T::HAS_UNSERIALIZE {
440 unsafe { cls.set_unserialize_method(Some(t_unserialize::<T>)) };
441 }
442 if T::HAS_UNSERIALIZE_EX {
443 unsafe { cls.set_unserialize_ex_method(Some(t_unserialize_ex::<T>)) };
444 }
445 if T::HAS_DUPLICATE {
446 unsafe { cls.set_duplicate_method(Some(t_duplicate::<T>)) };
447 }
448 if T::HAS_DUPLICATE_EX {
449 unsafe { cls.set_duplicate_ex_method(Some(t_duplicate_ex::<T>)) };
450 }
451 if T::HAS_COERCE {
452 unsafe { cls.set_coerce_method(Some(t_coerce::<T>)) };
453 }
454 if T::HAS_INSPECT {
455 unsafe { cls.set_inspect_method(Some(t_inspect::<T>)) };
456 }
457}
458
459pub unsafe fn install_vec<T: AltVec>(cls: R_altrep_class_t) {
463 if T::HAS_DATAPTR {
464 unsafe { cls.set_dataptr_method(Some(t_dataptr::<T>)) };
465 }
466 if T::HAS_DATAPTR_OR_NULL {
467 unsafe { cls.set_dataptr_or_null_method(Some(t_dataptr_or_null::<T>)) };
468 }
469 if T::HAS_EXTRACT_SUBSET {
470 unsafe { cls.set_extract_subset_method(Some(t_extract_subset::<T>)) };
471 }
472}
473
474macro_rules! def_installer {
479 (
480 $(#[$meta:meta])*
481 $fn_name:ident < T: $trait:ident > {
482 $( $has:ident => $method:ident, $tramp:ident; )*
483 }
484 ) => {
485 $(#[$meta])*
486 pub unsafe fn $fn_name<T: $trait>(cls: R_altrep_class_t) {
487 $(
488 if T::$has { unsafe { cls.$method(Some($tramp::<T>)) } }
489 )*
490 }
491 };
492 (
493 $(#[$meta:meta])*
494 $fn_name:ident < T: $trait:ident > {
495 $( $has:ident => $method:ident, $tramp:ident; )*
496 }
497 always { $( $always_method:ident, $always_tramp:ident; )* }
498 ) => {
499 $(#[$meta])*
500 pub unsafe fn $fn_name<T: $trait>(cls: R_altrep_class_t) {
501 $(
502 unsafe { cls.$always_method(Some($always_tramp::<T>)) }
503 )*
504 $(
505 if T::$has { unsafe { cls.$method(Some($tramp::<T>)) } }
506 )*
507 }
508 };
509}
510
511def_installer! {
512 install_int<T: AltInteger> {
516 HAS_ELT => set_integer_elt_method, t_int_elt;
517 HAS_GET_REGION => set_integer_get_region_method, t_int_get_region;
518 HAS_IS_SORTED => set_integer_is_sorted_method, t_int_is_sorted;
519 HAS_NO_NA => set_integer_no_na_method, t_int_no_na;
520 HAS_SUM => set_integer_sum_method, t_int_sum;
521 HAS_MIN => set_integer_min_method, t_int_min;
522 HAS_MAX => set_integer_max_method, t_int_max;
523 }
524}
525
526def_installer! {
527 install_real<T: AltReal> {
531 HAS_ELT => set_real_elt_method, t_real_elt;
532 HAS_GET_REGION => set_real_get_region_method, t_real_get_region;
533 HAS_IS_SORTED => set_real_is_sorted_method, t_real_is_sorted;
534 HAS_NO_NA => set_real_no_na_method, t_real_no_na;
535 HAS_SUM => set_real_sum_method, t_real_sum;
536 HAS_MIN => set_real_min_method, t_real_min;
537 HAS_MAX => set_real_max_method, t_real_max;
538 }
539}
540
541def_installer! {
542 install_lgl<T: AltLogical> {
546 HAS_ELT => set_logical_elt_method, t_lgl_elt;
547 HAS_GET_REGION => set_logical_get_region_method, t_lgl_get_region;
548 HAS_IS_SORTED => set_logical_is_sorted_method, t_lgl_is_sorted;
549 HAS_NO_NA => set_logical_no_na_method, t_lgl_no_na;
550 HAS_SUM => set_logical_sum_method, t_lgl_sum;
551 }
552}
553
554def_installer! {
555 install_raw<T: AltRaw> {
559 HAS_ELT => set_raw_elt_method, t_raw_elt;
560 HAS_GET_REGION => set_raw_get_region_method, t_raw_get_region;
561 }
562}
563
564def_installer! {
565 install_cplx<T: AltComplex> {
569 HAS_ELT => set_complex_elt_method, t_cplx_elt;
570 HAS_GET_REGION => set_complex_get_region_method, t_cplx_get_region;
571 }
572}
573
574def_installer! {
575 install_str<T: AltString> {
580 HAS_SET_ELT => set_string_set_elt_method, t_str_set_elt;
581 HAS_IS_SORTED => set_string_is_sorted_method, t_str_is_sorted;
582 HAS_NO_NA => set_string_no_na_method, t_str_no_na;
583 }
584 always { set_string_elt_method, t_str_elt; }
585}
586
587def_installer! {
588 install_list<T: AltList> {
593 HAS_SET_ELT => set_list_set_elt_method, t_list_set_elt;
594 }
595 always { set_list_elt_method, t_list_elt; }
596}
597