Skip to main content

miniextendr_api/altrep_data/
macros.rs

1//! Convenience macros for implementing `InferBase`.
2//!
3//! The parametric `__impl_inferbase!` macro provides the shared implementation.
4//! Each `impl_inferbase_*!` macro is a thin wrapper that passes family-specific
5//! parameters (`RBase` variant, `R_make_alt*_class` function, `install_*` function).
6//!
7//! These macros are used by the `#[derive(Altrep)]` proc macro and by the
8//! built-in type implementations in `super::builtins`.
9
10/// Parametric implementation of `InferBase` for any ALTREP family.
11///
12/// Takes the type, RBase variant, R_make_alt*_class function, and family installer.
13#[macro_export]
14#[doc(hidden)]
15macro_rules! __impl_inferbase {
16    ($ty:ty, $base:ident, $make_fn:path, $install_fn:ident) => {
17        $crate::__impl_inferbase!({} $ty {}, $base, $make_fn, $install_fn);
18    };
19    // Generic form: `{$gen} $ty {$where}, $base, $make_fn, $install_fn`. Brace
20    // delimiters (not `[]`/`()`) are deliberate — see `__impl_altrep_base!` in
21    // `altrep_impl/macros.rs` for why: `{` can never start a `$ty:ty` fragment,
22    // so the bare-`$ty:ty` arm above fails cleanly against a brace-led
23    // invocation instead of hard-erroring on a bogus type parse. The
24    // non-generic arm above forwards here with empty `{}` brackets so there
25    // is exactly one emission body.
26    ({$($gen:tt)*} $ty:ty {$($whr:tt)*}, $base:ident, $make_fn:path, $install_fn:ident) => {
27        impl<$($gen)*> $crate::altrep_data::InferBase for $ty where $($whr)* {
28            const BASE: $crate::altrep::RBase = $crate::altrep::RBase::$base;
29
30            unsafe fn make_class(
31                class_name: *const i8,
32                pkg_name: *const i8,
33            ) -> $crate::sys::altrep::R_altrep_class_t {
34                // Use stored DllInfo from package_init. R needs this to find
35                // the ALTREP class during cross-session deserialization (readRDS).
36                let dll = $crate::altrep_dll_info();
37                let cls = unsafe { $make_fn(class_name, pkg_name, dll) };
38                let name = unsafe { ::core::ffi::CStr::from_ptr(class_name) };
39                $crate::altrep::validate_altrep_class(cls, name, $crate::altrep::RBase::$base)
40            }
41
42            unsafe fn install_methods(cls: $crate::sys::altrep::R_altrep_class_t) {
43                unsafe { $crate::altrep_bridge::install_base::<$ty>(cls) };
44                unsafe { $crate::altrep_bridge::install_vec::<$ty>(cls) };
45                unsafe { $crate::altrep_bridge::$install_fn::<$ty>(cls) };
46            }
47        }
48    };
49}
50
51/// Implement `InferBase` for an integer ALTREP data type.
52///
53/// Accepts an optional generic form: `impl_inferbase_integer!({T} Foo<T> {T:
54/// Bound})` — see [`crate::impl_altinteger_from_data_generic!`] for the same
55/// convention at the family-macro layer.
56#[macro_export]
57macro_rules! impl_inferbase_integer {
58    ($ty:ty) => {
59        $crate::impl_inferbase_integer!({} $ty {});
60    };
61    ({$($gen:tt)*} $ty:ty {$($whr:tt)*}) => {
62        $crate::__impl_inferbase!(
63            {$($gen)*} $ty {$($whr)*},
64            Int,
65            $crate::sys::altrep::R_make_altinteger_class,
66            install_int
67        );
68    };
69}
70
71/// Implement `InferBase` for a real ALTREP data type. See
72/// [`impl_inferbase_integer!`] for the generic calling convention.
73#[macro_export]
74macro_rules! impl_inferbase_real {
75    ($ty:ty) => {
76        $crate::impl_inferbase_real!({} $ty {});
77    };
78    ({$($gen:tt)*} $ty:ty {$($whr:tt)*}) => {
79        $crate::__impl_inferbase!(
80            {$($gen)*} $ty {$($whr)*},
81            Real,
82            $crate::sys::altrep::R_make_altreal_class,
83            install_real
84        );
85    };
86}
87
88/// Implement `InferBase` for a logical ALTREP data type. See
89/// [`impl_inferbase_integer!`] for the generic calling convention.
90#[macro_export]
91macro_rules! impl_inferbase_logical {
92    ($ty:ty) => {
93        $crate::impl_inferbase_logical!({} $ty {});
94    };
95    ({$($gen:tt)*} $ty:ty {$($whr:tt)*}) => {
96        $crate::__impl_inferbase!(
97            {$($gen)*} $ty {$($whr)*},
98            Logical,
99            $crate::sys::altrep::R_make_altlogical_class,
100            install_lgl
101        );
102    };
103}
104
105/// Implement `InferBase` for a raw ALTREP data type. See
106/// [`impl_inferbase_integer!`] for the generic calling convention.
107#[macro_export]
108macro_rules! impl_inferbase_raw {
109    ($ty:ty) => {
110        $crate::impl_inferbase_raw!({} $ty {});
111    };
112    ({$($gen:tt)*} $ty:ty {$($whr:tt)*}) => {
113        $crate::__impl_inferbase!(
114            {$($gen)*} $ty {$($whr)*},
115            Raw,
116            $crate::sys::altrep::R_make_altraw_class,
117            install_raw
118        );
119    };
120}
121
122/// Implement `InferBase` for a string ALTREP data type. See
123/// [`impl_inferbase_integer!`] for the generic calling convention.
124#[macro_export]
125macro_rules! impl_inferbase_string {
126    ($ty:ty) => {
127        $crate::impl_inferbase_string!({} $ty {});
128    };
129    ({$($gen:tt)*} $ty:ty {$($whr:tt)*}) => {
130        $crate::__impl_inferbase!(
131            {$($gen)*} $ty {$($whr)*},
132            String,
133            $crate::sys::altrep::R_make_altstring_class,
134            install_str
135        );
136    };
137}
138
139/// Implement `InferBase` for a complex ALTREP data type. See
140/// [`impl_inferbase_integer!`] for the generic calling convention.
141#[macro_export]
142macro_rules! impl_inferbase_complex {
143    ($ty:ty) => {
144        $crate::impl_inferbase_complex!({} $ty {});
145    };
146    ({$($gen:tt)*} $ty:ty {$($whr:tt)*}) => {
147        $crate::__impl_inferbase!(
148            {$($gen)*} $ty {$($whr)*},
149            Complex,
150            $crate::sys::altrep::R_make_altcomplex_class,
151            install_cplx
152        );
153    };
154}
155
156/// Implement `InferBase` for a list ALTREP data type. See
157/// [`impl_inferbase_integer!`] for the generic calling convention.
158#[macro_export]
159macro_rules! impl_inferbase_list {
160    ($ty:ty) => {
161        $crate::impl_inferbase_list!({} $ty {});
162    };
163    ({$($gen:tt)*} $ty:ty {$($whr:tt)*}) => {
164        $crate::__impl_inferbase!(
165            {$($gen)*} $ty {$($whr)*},
166            List,
167            $crate::sys::altrep::R_make_altlist_class,
168            install_list
169        );
170    };
171}
172
173// region: Logical enum tests
174#[cfg(test)]
175mod tests;
176// endregion