Skip to main content

miniextendr_api/altrep_impl/
static_slices.rs

1//! ALTREP impls for `&'static [T]`.
2//!
3//! Static slices are Sized (fat pointer: ptr + len) and satisfy `'static`, so
4//! they work directly with the ExternalPtr-backed ALTREP machinery. These
5//! impls are hand-written rather than macro-generated because the writable
6//! `dataptr` path must assert `!writable` (static data is immutable).
7//!
8//! Use cases: const arrays via `&DATA[..]`, leaked vectors via
9//! `Box::leak(vec.into_boxed_slice())`, memory-mapped files with `'static`
10//! lifetime.
11
12// region: Static slice implementations (&'static [T])
13//
14// `&'static [T]` is Sized (fat pointer: ptr + len) and satisfies 'static,
15// so it can be used DIRECTLY with ALTREP via ExternalPtr.
16//
17// Use cases:
18// - Const arrays: `static DATA: [i32; 5] = [1, 2, 3, 4, 5]; create_altrep(&DATA[..])`
19// - Leaked data: `let s: &'static [i32] = Box::leak(vec.into_boxed_slice());`
20// - Memory-mapped files with 'static lifetime
21
22// Integer static slices
23impl crate::altrep_traits::Altrep for &'static [i32] {
24    fn length(x: crate::SEXP) -> crate::R_xlen_t {
25        let data =
26            unsafe { <&'static [i32] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
27        crate::altrep_data::AltrepLen::len(data) as crate::R_xlen_t
28    }
29}
30
31impl crate::altrep_traits::AltVec for &'static [i32] {
32    const HAS_DATAPTR: bool = true;
33
34    fn dataptr(x: crate::SEXP, writable: bool) -> *mut std::ffi::c_void {
35        // Static data cannot be modified. Panic is caught by RUnwind guard.
36        assert!(
37            !writable,
38            "cannot get writable DATAPTR for static ALTREP data"
39        );
40        let data =
41            unsafe { <&'static [i32] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
42        data.as_ptr().cast::<std::ffi::c_void>().cast_mut()
43    }
44
45    const HAS_DATAPTR_OR_NULL: bool = true;
46
47    fn dataptr_or_null(x: crate::SEXP) -> *const std::ffi::c_void {
48        let data =
49            unsafe { <&'static [i32] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
50        data.as_ptr().cast::<std::ffi::c_void>()
51    }
52}
53
54impl crate::altrep_traits::AltInteger for &'static [i32] {
55    const HAS_ELT: bool = true;
56
57    fn elt(x: crate::SEXP, i: crate::R_xlen_t) -> i32 {
58        let data =
59            unsafe { <&'static [i32] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
60        crate::altrep_data::AltIntegerData::elt(data, i.max(0) as usize)
61    }
62
63    const HAS_GET_REGION: bool = true;
64
65    fn get_region(
66        x: crate::SEXP,
67        start: crate::R_xlen_t,
68        len: crate::R_xlen_t,
69        buf: &mut [i32],
70    ) -> crate::R_xlen_t {
71        if start < 0 || len <= 0 {
72            return 0;
73        }
74        let data =
75            unsafe { <&'static [i32] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
76        let len = len as usize;
77        crate::altrep_data::AltIntegerData::get_region(data, start as usize, len, buf)
78            as crate::R_xlen_t
79    }
80
81    const HAS_NO_NA: bool = true;
82
83    fn no_na(x: crate::SEXP) -> i32 {
84        let data =
85            unsafe { <&'static [i32] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
86        crate::altrep_data::AltIntegerData::no_na(data)
87            .map(|b| if b { 1 } else { 0 })
88            .unwrap_or(0)
89    }
90
91    const HAS_SUM: bool = true;
92
93    // ALTREP protocol: return C NULL (not R_NilValue) to signal "can't compute"
94    fn sum(x: crate::SEXP, narm: bool) -> crate::SEXP {
95        let data =
96            unsafe { <&'static [i32] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
97        crate::altrep_data::AltIntegerData::sum(data, narm)
98            .map(|s| {
99                if s >= i32::MIN as i64 && s <= i32::MAX as i64 {
100                    crate::SEXP::scalar_integer(s as i32)
101                } else {
102                    crate::SEXP::scalar_real(s as f64)
103                }
104            })
105            .unwrap_or(crate::SEXP::null())
106    }
107
108    const HAS_MIN: bool = true;
109
110    fn min(x: crate::SEXP, narm: bool) -> crate::SEXP {
111        let data =
112            unsafe { <&'static [i32] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
113        crate::altrep_data::AltIntegerData::min(data, narm)
114            .map(crate::SEXP::scalar_integer)
115            .unwrap_or(crate::SEXP::null())
116    }
117
118    const HAS_MAX: bool = true;
119
120    fn max(x: crate::SEXP, narm: bool) -> crate::SEXP {
121        let data =
122            unsafe { <&'static [i32] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
123        crate::altrep_data::AltIntegerData::max(data, narm)
124            .map(crate::SEXP::scalar_integer)
125            .unwrap_or(crate::SEXP::null())
126    }
127}
128
129crate::impl_inferbase_integer!(&'static [i32]);
130
131// Real static slices
132impl crate::altrep_traits::Altrep for &'static [f64] {
133    fn length(x: crate::SEXP) -> crate::R_xlen_t {
134        let data =
135            unsafe { <&'static [f64] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
136        crate::altrep_data::AltrepLen::len(data) as crate::R_xlen_t
137    }
138}
139
140impl crate::altrep_traits::AltVec for &'static [f64] {
141    const HAS_DATAPTR: bool = true;
142
143    fn dataptr(x: crate::SEXP, writable: bool) -> *mut std::ffi::c_void {
144        assert!(
145            !writable,
146            "cannot get writable DATAPTR for static ALTREP data"
147        );
148        let data =
149            unsafe { <&'static [f64] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
150        data.as_ptr().cast::<std::ffi::c_void>().cast_mut()
151    }
152
153    const HAS_DATAPTR_OR_NULL: bool = true;
154
155    fn dataptr_or_null(x: crate::SEXP) -> *const std::ffi::c_void {
156        let data =
157            unsafe { <&'static [f64] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
158        data.as_ptr().cast::<std::ffi::c_void>()
159    }
160}
161
162impl crate::altrep_traits::AltReal for &'static [f64] {
163    const HAS_ELT: bool = true;
164
165    fn elt(x: crate::SEXP, i: crate::R_xlen_t) -> f64 {
166        let data =
167            unsafe { <&'static [f64] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
168        crate::altrep_data::AltRealData::elt(data, i.max(0) as usize)
169    }
170
171    const HAS_GET_REGION: bool = true;
172
173    fn get_region(
174        x: crate::SEXP,
175        start: crate::R_xlen_t,
176        len: crate::R_xlen_t,
177        buf: &mut [f64],
178    ) -> crate::R_xlen_t {
179        if start < 0 || len <= 0 {
180            return 0;
181        }
182        let data =
183            unsafe { <&'static [f64] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
184        let len = len as usize;
185        crate::altrep_data::AltRealData::get_region(data, start as usize, len, buf)
186            as crate::R_xlen_t
187    }
188
189    const HAS_NO_NA: bool = true;
190
191    fn no_na(x: crate::SEXP) -> i32 {
192        let data =
193            unsafe { <&'static [f64] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
194        crate::altrep_data::AltRealData::no_na(data)
195            .map(|b| if b { 1 } else { 0 })
196            .unwrap_or(0)
197    }
198
199    const HAS_SUM: bool = true;
200
201    // ALTREP protocol: return C NULL (not R_NilValue) to signal "can't compute"
202    fn sum(x: crate::SEXP, narm: bool) -> crate::SEXP {
203        let data =
204            unsafe { <&'static [f64] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
205        crate::altrep_data::AltRealData::sum(data, narm)
206            .map(crate::SEXP::scalar_real)
207            .unwrap_or(crate::SEXP::null())
208    }
209
210    const HAS_MIN: bool = true;
211
212    fn min(x: crate::SEXP, narm: bool) -> crate::SEXP {
213        let data =
214            unsafe { <&'static [f64] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
215        crate::altrep_data::AltRealData::min(data, narm)
216            .map(crate::SEXP::scalar_real)
217            .unwrap_or(crate::SEXP::null())
218    }
219
220    const HAS_MAX: bool = true;
221
222    fn max(x: crate::SEXP, narm: bool) -> crate::SEXP {
223        let data =
224            unsafe { <&'static [f64] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
225        crate::altrep_data::AltRealData::max(data, narm)
226            .map(crate::SEXP::scalar_real)
227            .unwrap_or(crate::SEXP::null())
228    }
229}
230
231crate::impl_inferbase_real!(&'static [f64]);
232
233// Logical static slices
234impl crate::altrep_traits::Altrep for &'static [bool] {
235    fn length(x: crate::SEXP) -> crate::R_xlen_t {
236        let data = unsafe {
237            <&'static [bool] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x)
238        };
239        crate::altrep_data::AltrepLen::len(data) as crate::R_xlen_t
240    }
241}
242
243impl crate::altrep_traits::AltVec for &'static [bool] {}
244
245impl crate::altrep_traits::AltLogical for &'static [bool] {
246    const HAS_ELT: bool = true;
247
248    fn elt(x: crate::SEXP, i: crate::R_xlen_t) -> i32 {
249        let data = unsafe {
250            <&'static [bool] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x)
251        };
252        crate::altrep_data::AltLogicalData::elt(data, i.max(0) as usize).to_r_int()
253    }
254
255    const HAS_NO_NA: bool = true;
256
257    fn no_na(x: crate::SEXP) -> i32 {
258        let data = unsafe {
259            <&'static [bool] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x)
260        };
261        crate::altrep_data::AltLogicalData::no_na(data)
262            .map(|b| if b { 1 } else { 0 })
263            .unwrap_or(0)
264    }
265
266    const HAS_SUM: bool = true;
267
268    // ALTREP protocol: return C NULL (not R_NilValue) to signal "can't compute"
269    fn sum(x: crate::SEXP, narm: bool) -> crate::SEXP {
270        let data = unsafe {
271            <&'static [bool] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x)
272        };
273        crate::altrep_data::AltLogicalData::sum(data, narm)
274            .map(|s| {
275                if s >= i32::MIN as i64 && s <= i32::MAX as i64 {
276                    crate::SEXP::scalar_integer(s as i32)
277                } else {
278                    crate::SEXP::scalar_real(s as f64)
279                }
280            })
281            .unwrap_or(crate::SEXP::null())
282    }
283}
284
285crate::impl_inferbase_logical!(&'static [bool]);
286
287// Raw static slices
288impl crate::altrep_traits::Altrep for &'static [u8] {
289    fn length(x: crate::SEXP) -> crate::R_xlen_t {
290        let data =
291            unsafe { <&'static [u8] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
292        crate::altrep_data::AltrepLen::len(data) as crate::R_xlen_t
293    }
294}
295
296impl crate::altrep_traits::AltVec for &'static [u8] {
297    const HAS_DATAPTR: bool = true;
298
299    fn dataptr(x: crate::SEXP, writable: bool) -> *mut std::ffi::c_void {
300        assert!(
301            !writable,
302            "cannot get writable DATAPTR for static ALTREP data"
303        );
304        let data =
305            unsafe { <&'static [u8] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
306        data.as_ptr().cast::<std::ffi::c_void>().cast_mut()
307    }
308
309    const HAS_DATAPTR_OR_NULL: bool = true;
310
311    fn dataptr_or_null(x: crate::SEXP) -> *const std::ffi::c_void {
312        let data =
313            unsafe { <&'static [u8] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
314        data.as_ptr().cast::<std::ffi::c_void>()
315    }
316}
317
318impl crate::altrep_traits::AltRaw for &'static [u8] {
319    const HAS_ELT: bool = true;
320
321    fn elt(x: crate::SEXP, i: crate::R_xlen_t) -> crate::Rbyte {
322        let data =
323            unsafe { <&'static [u8] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
324        crate::altrep_data::AltRawData::elt(data, i.max(0) as usize)
325    }
326
327    const HAS_GET_REGION: bool = true;
328
329    fn get_region(
330        x: crate::SEXP,
331        start: crate::R_xlen_t,
332        len: crate::R_xlen_t,
333        buf: &mut [u8],
334    ) -> crate::R_xlen_t {
335        if start < 0 || len <= 0 {
336            return 0;
337        }
338        let data =
339            unsafe { <&'static [u8] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x) };
340        let len = len as usize;
341        crate::altrep_data::AltRawData::get_region(data, start as usize, len, buf)
342            as crate::R_xlen_t
343    }
344}
345
346crate::impl_inferbase_raw!(&'static [u8]);
347
348// String static slices (owned strings)
349impl crate::altrep_traits::Altrep for &'static [String] {
350    // String ALTREP elt calls Rf_mkCharLenCE (R API) — must use RUnwind.
351    const GUARD: crate::altrep_traits::AltrepGuard = crate::altrep_traits::AltrepGuard::RUnwind;
352
353    fn length(x: crate::SEXP) -> crate::R_xlen_t {
354        let data = unsafe {
355            <&'static [String] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x)
356        };
357        crate::altrep_data::AltrepLen::len(data) as crate::R_xlen_t
358    }
359}
360
361impl crate::altrep_traits::AltVec for &'static [String] {}
362
363impl crate::altrep_traits::AltString for &'static [String] {
364    fn elt(x: crate::SEXP, i: crate::R_xlen_t) -> crate::SEXP {
365        let data = unsafe {
366            <&'static [String] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x)
367        };
368        match crate::altrep_data::AltStringData::elt(data, i.max(0) as usize) {
369            Some(s) => unsafe { super::checked_mkchar(s) },
370            None => crate::SEXP::na_string(),
371        }
372    }
373
374    const HAS_NO_NA: bool = true;
375
376    fn no_na(x: crate::SEXP) -> i32 {
377        let data = unsafe {
378            <&'static [String] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x)
379        };
380        crate::altrep_data::AltStringData::no_na(data)
381            .map(|b| if b { 1 } else { 0 })
382            .unwrap_or(0)
383    }
384}
385
386crate::impl_inferbase_string!(&'static [String]);
387
388// String static slices (str references)
389impl crate::altrep_traits::Altrep for &'static [&'static str] {
390    // String ALTREP elt calls Rf_mkCharLenCE (R API) — must use RUnwind.
391    const GUARD: crate::altrep_traits::AltrepGuard = crate::altrep_traits::AltrepGuard::RUnwind;
392
393    fn length(x: crate::SEXP) -> crate::R_xlen_t {
394        let data = unsafe {
395            <&'static [&'static str] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x)
396        };
397        crate::altrep_data::AltrepLen::len(data) as crate::R_xlen_t
398    }
399}
400
401impl crate::altrep_traits::AltVec for &'static [&'static str] {}
402
403impl crate::altrep_traits::AltString for &'static [&'static str] {
404    fn elt(x: crate::SEXP, i: crate::R_xlen_t) -> crate::SEXP {
405        let data = unsafe {
406            <&'static [&'static str] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x)
407        };
408        match crate::altrep_data::AltStringData::elt(data, i.max(0) as usize) {
409            Some(s) => unsafe { super::checked_mkchar(s) },
410            None => crate::SEXP::na_string(),
411        }
412    }
413
414    const HAS_NO_NA: bool = true;
415
416    fn no_na(x: crate::SEXP) -> i32 {
417        let data = unsafe {
418            <&'static [&'static str] as crate::altrep_data::AltrepExtract>::altrep_extract_ref(x)
419        };
420        crate::altrep_data::AltStringData::no_na(data)
421            .map(|b| if b { 1 } else { 0 })
422            .unwrap_or(0)
423    }
424}
425
426crate::impl_inferbase_string!(&'static [&'static str]);
427// endregion