Skip to main content

miniextendr_api/altrep_data/
builtins.rs

1//! Built-in ALTREP data implementations for standard Rust types.
2//!
3//! Provides `AltIntegerData`, `AltRealData`, `AltLogicalData`, `AltRawData`,
4//! `AltStringData`, and `AltComplexData` implementations for:
5//!
6//! - `Vec<T>` — owned vector (most common)
7//! - `Box<[T]>` — boxed slice
8//! - `Range<T>` — lazy arithmetic sequences (integer, real)
9//! - `&'static [T]` — borrowed slices (zero-copy from static data)
10//! - `[T; N]` — fixed-size arrays
11
12use std::borrow::Cow;
13use std::ops::Range;
14
15use crate::{IsNA, RLogical, Rcomplex, SEXP};
16
17use super::{
18    AltComplexData, AltIntegerData, AltLogicalData, AltRawData, AltRealData, AltStringData,
19    AltrepDataptr, AltrepLen, AltrepSerialize, Logical, Sortedness,
20};
21
22// region: Helper macros to reduce repetition
23
24/// Implement AltrepLen for Vec<$elem>
25macro_rules! impl_len_vec {
26    ($elem:ty) => {
27        impl AltrepLen for Vec<$elem> {
28            fn altrep_len(&self) -> usize {
29                Vec::len(self)
30            }
31        }
32    };
33}
34
35/// Implement AltrepLen for Box<[$elem]>
36macro_rules! impl_len_boxed {
37    ($elem:ty) => {
38        impl AltrepLen for Box<[$elem]> {
39            fn altrep_len(&self) -> usize {
40                <[$elem]>::len(self)
41            }
42        }
43    };
44}
45
46/// Implement AltrepLen for [$elem; N]
47macro_rules! impl_len_array {
48    ($elem:ty) => {
49        impl<const N: usize> AltrepLen for [$elem; N] {
50            fn altrep_len(&self) -> usize {
51                N
52            }
53        }
54    };
55}
56
57/// Implement AltrepLen for &[$elem]
58macro_rules! impl_len_slice {
59    ($elem:ty) => {
60        impl AltrepLen for &[$elem] {
61            fn altrep_len(&self) -> usize {
62                <[$elem]>::len(self)
63            }
64        }
65    };
66}
67
68/// Implement AltrepDataptr for Vec<$elem> (types with direct memory access)
69macro_rules! impl_dataptr_vec {
70    ($elem:ty) => {
71        impl_dataptr_vec!($elem => $elem);
72    };
73    // The storage type must have the same layout and valid bit patterns.
74    ($elem:ty => $storage:ty) => {
75        impl AltrepDataptr<$storage> for Vec<$elem> {
76            fn dataptr(&mut self, _writable: bool) -> Option<*mut $storage> {
77                Some(self.as_mut_ptr().cast())
78            }
79
80            fn dataptr_or_null(&self) -> Option<*const $storage> {
81                Some(self.as_ptr().cast())
82            }
83        }
84    };
85}
86
87/// Implement AltrepDataptr for Box<[$elem]> (types with direct memory access)
88macro_rules! impl_dataptr_boxed {
89    ($elem:ty) => {
90        impl_dataptr_boxed!($elem => $elem);
91    };
92    // The storage type must have the same layout and valid bit patterns.
93    ($elem:ty => $storage:ty) => {
94        impl AltrepDataptr<$storage> for Box<[$elem]> {
95            fn dataptr(&mut self, _writable: bool) -> Option<*mut $storage> {
96                Some(self.as_mut_ptr().cast())
97            }
98
99            fn dataptr_or_null(&self) -> Option<*const $storage> {
100                Some(self.as_ptr().cast())
101            }
102        }
103    };
104}
105
106/// Implement AltrepSerialize for types that can be cloned and converted to/from R.
107///
108/// This serializes by converting to a native R vector, ensuring the data survives
109/// even if the Rust package isn't loaded when unserializing.
110macro_rules! impl_serialize {
111    ($ty:ty) => {
112        impl_serialize!($ty, $ty, std::convert::identity);
113    };
114    ($ty:ty, $owned:ty, $wrap:expr) => {
115        impl AltrepSerialize for $ty {
116            fn serialized_state(&self) -> SEXP {
117                use crate::into_r::IntoR;
118                self.clone().into_sexp()
119            }
120
121            fn unserialize(state: SEXP) -> Option<Self> {
122                use crate::from_r::TryFromSexp;
123                <$owned>::try_from_sexp(state).ok().map($wrap)
124            }
125        }
126    };
127}
128// endregion
129
130// region: Slice-backed family macros
131//
132// The numeric / raw / complex ALTREP families share byte-identical bodies
133// across every container shape that derefs to `[T]` (`Vec<T>`, `Box<[T]>`,
134// `&[T]`, `Cow<'static, [T]>`). The element type is the only axis that varies
135// the *behaviour* (NA sentinel + statistic semantics); the container shape only
136// varies how the slice is spelled. Each macro below collapses one element
137// family across all slice-like containers by writing every method body against
138// the deref'd `&[$elem]` slice.
139//
140// `[T; N]` arrays are intentionally NOT routed through these macros: they need
141// `impl<const N: usize>` (not expressible via `$ty:ty`) and they deliberately
142// omit `sum`/`min`/`max` (falling back to R's defaults). `Range<T>` is lazy and
143// has its own arithmetic-sequence bodies. The string families have per-type
144// `elt`/`no_na` differences and stay hand-written.
145
146/// `AltIntegerData` for any container that derefs to `[i32]`.
147///
148/// `s` binds the underlying `&[i32]` uniformly across `Vec` / `Box<[T]>` /
149/// `&[T]` / `Cow`, using the same slice access for every owner.
150macro_rules! impl_altinteger_slice {
151    ($ty:ty) => {
152        impl AltIntegerData for $ty {
153            fn elt(&self, i: usize) -> i32 {
154                self[i]
155            }
156
157            fn as_slice(&self) -> Option<&[i32]> {
158                let s: &[i32] = self;
159                Some(s)
160            }
161
162            fn get_region(&self, start: usize, len: usize, buf: &mut [i32]) -> usize {
163                let s: &[i32] = self;
164                let end = (start + len).min(s.len());
165                let actual_len = end.saturating_sub(start);
166                if actual_len > 0 {
167                    buf[..actual_len].copy_from_slice(&s[start..end]);
168                }
169                actual_len
170            }
171
172            fn no_na(&self) -> Option<bool> {
173                let s: &[i32] = self;
174                Some(!s.iter().any(IsNA::is_na))
175            }
176
177            fn sum(&self, na_rm: bool) -> Option<i64> {
178                let s: &[i32] = self;
179                let mut sum: i64 = 0;
180                for &x in s.iter() {
181                    if x.is_na() {
182                        if !na_rm {
183                            return None; // NA propagates
184                        }
185                    } else {
186                        sum += x as i64;
187                    }
188                }
189                Some(sum)
190            }
191
192            fn min(&self, na_rm: bool) -> Option<i32> {
193                let s: &[i32] = self;
194                let mut min = i32::MAX;
195                let mut found = false;
196                for &x in s.iter() {
197                    if x.is_na() {
198                        if !na_rm {
199                            return None;
200                        }
201                    } else {
202                        found = true;
203                        min = min.min(x);
204                    }
205                }
206                if found { Some(min) } else { None }
207            }
208
209            fn max(&self, na_rm: bool) -> Option<i32> {
210                let s: &[i32] = self;
211                let mut max = i32::MIN + 1; // i32::MIN is the NA sentinel
212                let mut found = false;
213                for &x in s.iter() {
214                    if x.is_na() {
215                        if !na_rm {
216                            return None;
217                        }
218                    } else {
219                        found = true;
220                        max = max.max(x);
221                    }
222                }
223                if found { Some(max) } else { None }
224            }
225        }
226    };
227}
228
229// region: double NA/NaN summaries shared by the slice-backed AltRealData impls
230
231/// `no_na` for a double slice: `true` only when no element is `NA` **or** `NaN`.
232///
233/// This is R's `ISNAN` test, not `R_IsNA`: `anyNA()` returns `FALSE` as soon as
234/// `REAL_NO_NA()` reports true (its own scan tests `ISNAN`, so
235/// `anyNA(c(1, NaN))` is `TRUE`), and `sort()` uses the same hint to skip its
236/// NA handling, which drops NaN too.
237fn real_slice_no_na(s: &[f64]) -> bool {
238    !s.iter().any(|x| x.is_nan())
239}
240
241/// `sum` for a double slice, following R's `rsum`.
242///
243/// With `na_rm`, every `NA` and `NaN` is skipped (`ISNAN`). Without it, the
244/// result is the first element that is R's NA (`R_IsNA`, so a computed NA such
245/// as `NA_real_ * 1` counts), else `NaN` if any element is another NaN. R leaves
246/// the NA-vs-NaN outcome of a sum unspecified; letting NA win matches `min` and
247/// `max`.
248fn real_slice_sum(s: &[f64], na_rm: bool) -> f64 {
249    let mut sum = 0.0;
250    let mut nan = false;
251    for &x in s {
252        if x.is_nan() {
253            if na_rm {
254                continue;
255            }
256            if x.is_na() {
257                return x;
258            }
259            nan = true;
260        } else {
261            sum += x;
262        }
263    }
264    if nan { f64::NAN } else { sum }
265}
266
267/// `min` / `max` for a double slice, following R's `rmin` / `rmax`.
268///
269/// Missing values are handled as in [`real_slice_sum`]: skipped with `na_rm`,
270/// otherwise an NA (`R_IsNA`) wins over a NaN ("any NA trumps all NaNs" in
271/// R's source) and is returned as is, bits included, as R's loop does. `None`
272/// when nothing is left to compare (R then computes the `Inf` / `-Inf` result
273/// and its warning itself).
274fn real_slice_extreme(s: &[f64], na_rm: bool, pick: fn(f64, f64) -> f64) -> Option<f64> {
275    let mut best: Option<f64> = None;
276    let mut nan = false;
277    for &x in s {
278        if x.is_nan() {
279            if na_rm {
280                continue;
281            }
282            if x.is_na() {
283                return Some(x);
284            }
285            nan = true;
286        } else {
287            best = Some(best.map_or(x, |b| pick(b, x)));
288        }
289    }
290    if nan { Some(f64::NAN) } else { best }
291}
292
293// endregion
294
295/// `AltRealData` for any container that derefs to `[f64]`.
296///
297/// Distinguishes R's `NA_real_` from a regular IEEE NaN where R does: `sum`,
298/// `min` and `max` return NA for an NA element and NaN for a NaN element, while
299/// `no_na` treats both as missing (see [`real_slice_no_na`]).
300macro_rules! impl_altreal_slice {
301    ($ty:ty) => {
302        impl AltRealData for $ty {
303            fn elt(&self, i: usize) -> f64 {
304                self[i]
305            }
306
307            fn as_slice(&self) -> Option<&[f64]> {
308                let s: &[f64] = self;
309                Some(s)
310            }
311
312            fn get_region(&self, start: usize, len: usize, buf: &mut [f64]) -> usize {
313                let s: &[f64] = self;
314                let end = (start + len).min(s.len());
315                let actual_len = end.saturating_sub(start);
316                if actual_len > 0 {
317                    buf[..actual_len].copy_from_slice(&s[start..end]);
318                }
319                actual_len
320            }
321
322            fn no_na(&self) -> Option<bool> {
323                Some(real_slice_no_na(self))
324            }
325
326            fn sum(&self, na_rm: bool) -> Option<f64> {
327                Some(real_slice_sum(self, na_rm))
328            }
329
330            fn min(&self, na_rm: bool) -> Option<f64> {
331                real_slice_extreme(self, na_rm, f64::min)
332            }
333
334            fn max(&self, na_rm: bool) -> Option<f64> {
335                real_slice_extreme(self, na_rm, f64::max)
336            }
337        }
338    };
339}
340
341/// `AltRawData` for any container that derefs to `[u8]`. Raw has no NA.
342macro_rules! impl_altraw_slice {
343    ($ty:ty) => {
344        impl AltRawData for $ty {
345            fn elt(&self, i: usize) -> u8 {
346                self[i]
347            }
348
349            fn as_slice(&self) -> Option<&[u8]> {
350                let s: &[u8] = self;
351                Some(s)
352            }
353
354            fn get_region(&self, start: usize, len: usize, buf: &mut [u8]) -> usize {
355                let s: &[u8] = self;
356                let end = (start + len).min(s.len());
357                let actual_len = end.saturating_sub(start);
358                if actual_len > 0 {
359                    buf[..actual_len].copy_from_slice(&s[start..end]);
360                }
361                actual_len
362            }
363        }
364    };
365}
366
367/// `AltComplexData` for any container that derefs to `[Rcomplex]`.
368macro_rules! impl_altcomplex_slice {
369    ($ty:ty) => {
370        impl AltComplexData for $ty {
371            fn elt(&self, i: usize) -> Rcomplex {
372                self[i]
373            }
374
375            fn as_slice(&self) -> Option<&[Rcomplex]> {
376                let s: &[Rcomplex] = self;
377                Some(s)
378            }
379
380            fn get_region(&self, start: usize, len: usize, buf: &mut [Rcomplex]) -> usize {
381                let s: &[Rcomplex] = self;
382                let end = (start + len).min(s.len());
383                let actual_len = end.saturating_sub(start);
384                if actual_len > 0 {
385                    buf[..actual_len].copy_from_slice(&s[start..end]);
386                }
387                actual_len
388            }
389        }
390    };
391}
392
393/// `AltLogicalData` for any container that derefs to `[bool]`. `bool` can't be NA.
394macro_rules! impl_altlogical_slice {
395    ($ty:ty) => {
396        impl AltLogicalData for $ty {
397            fn elt(&self, i: usize) -> Logical {
398                self[i].into()
399            }
400
401            fn no_na(&self) -> Option<bool> {
402                Some(true) // bool can't be NA
403            }
404
405            fn sum(&self, _na_rm: bool) -> Option<i64> {
406                let s: &[bool] = self;
407                Some(s.iter().filter(|&&x| x).count() as i64)
408            }
409        }
410    };
411}
412/// `AltLogicalData` for R-native logical slices, including NA and raw values.
413macro_rules! impl_altlogical_native_slice {
414    ($ty:ty) => {
415        impl AltLogicalData for $ty {
416            fn elt(&self, i: usize) -> Logical {
417                self[i].into()
418            }
419
420            fn as_r_slice(&self) -> Option<&[i32]> {
421                let values: &[RLogical] = self;
422                // RLogical is repr(transparent) over i32; every bit pattern is valid.
423                Some(unsafe { std::slice::from_raw_parts(values.as_ptr().cast(), values.len()) })
424            }
425
426            fn get_region(&self, start: usize, len: usize, out: &mut [i32]) -> usize {
427                let values: &[RLogical] = self;
428                super::fill_region(start, len, values.len(), out, |i| values[i].to_i32())
429            }
430
431            fn no_na(&self) -> Option<bool> {
432                let values: &[RLogical] = self;
433                Some(!values.iter().any(IsNA::is_na))
434            }
435        }
436    };
437}
438// endregion
439
440// region: AltrepSerialize implementations for Vec<T>
441
442impl AltrepSerialize for Vec<i32> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<i32>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}impl_serialize!(Vec<i32>);
443impl AltrepSerialize for Vec<f64> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<f64>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}impl_serialize!(Vec<f64>);
444impl AltrepSerialize for Vec<u8> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<u8>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}impl_serialize!(Vec<u8>);
445impl AltrepSerialize for Vec<bool> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<bool>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}impl_serialize!(Vec<bool>);
446impl AltrepSerialize for Vec<RLogical> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<RLogical>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}impl_serialize!(Vec<RLogical>);
447impl AltrepSerialize for Vec<String> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<String>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}impl_serialize!(Vec<String>);
448impl AltrepSerialize for Vec<Option<String>> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<Option<String>>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}impl_serialize!(Vec<Option<String>>);
449impl AltrepSerialize for Vec<Rcomplex> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<Rcomplex>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}impl_serialize!(Vec<Rcomplex>);
450// The ALTREP outlives R's temporary serialization state. Its Rust backing
451// must own the decoded strings; no sidecar roots the original CHARSXPs.
452impl AltrepSerialize for Vec<Cow<'static, str>> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<String>>::try_from_sexp(state).ok().map(|values|
                { values.into_iter().map(Cow::Owned).collect() })
    }
}impl_serialize!(Vec<Cow<'static, str>>, Vec<String>, |values| {
453    values.into_iter().map(Cow::Owned).collect()
454});
455impl AltrepSerialize for Vec<Option<Cow<'static, str>>> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<Option<String>>>::try_from_sexp(state).ok().map(|values|
                values.into_iter().map(|value|
                            value.map(Cow::Owned)).collect())
    }
}impl_serialize!(
456    Vec<Option<Cow<'static, str>>>,
457    Vec<Option<String>>,
458    |values| values
459        .into_iter()
460        .map(|value| value.map(Cow::Owned))
461        .collect()
462);
463// endregion
464
465// region: AltrepSerialize implementations for Box<[T]>
466
467// Box<[T]>'s IntoR and TryFromSexp already delegate to Vec<T>.
468impl AltrepSerialize for Box<[i32]> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Box<[i32]>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}impl_serialize!(Box<[i32]>);
469impl AltrepSerialize for Box<[f64]> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Box<[f64]>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}impl_serialize!(Box<[f64]>);
470impl AltrepSerialize for Box<[u8]> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Box<[u8]>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}impl_serialize!(Box<[u8]>);
471impl AltrepSerialize for Box<[bool]> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Box<[bool]>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}impl_serialize!(Box<[bool]>);
472impl AltrepSerialize for Box<[RLogical]> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Box<[RLogical]>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}impl_serialize!(Box<[RLogical]>);
473impl AltrepSerialize for Box<[String]> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Box<[String]>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}impl_serialize!(Box<[String]>);
474impl AltrepSerialize for Box<[Rcomplex]> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Box<[Rcomplex]>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}impl_serialize!(Box<[Rcomplex]>);
475// endregion
476
477// region: Built-in implementations for Vec<T>
478
479impl AltrepLen for Vec<i32> {
    fn altrep_len(&self) -> usize { Vec::len(self) }
}impl_len_vec!(i32);
480impl AltIntegerData for Vec<i32> {
    fn elt(&self, i: usize) -> i32 { self[i] }
    fn as_slice(&self) -> Option<&[i32]> { let s: &[i32] = self; Some(s) }
    fn get_region(&self, start: usize, len: usize, buf: &mut [i32]) -> usize {
        let s: &[i32] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
    fn no_na(&self) -> Option<bool> {
        let s: &[i32] = self;
        Some(!s.iter().any(IsNA::is_na))
    }
    fn sum(&self, na_rm: bool) -> Option<i64> {
        let s: &[i32] = self;
        let mut sum: i64 = 0;
        for &x in s.iter() {
            if x.is_na() {
                if !na_rm { return None; }
            } else { sum += x as i64; }
        }
        Some(sum)
    }
    fn min(&self, na_rm: bool) -> Option<i32> {
        let s: &[i32] = self;
        let mut min = i32::MAX;
        let mut found = false;
        for &x in s.iter() {
            if x.is_na() {
                if !na_rm { return None; }
            } else { found = true; min = min.min(x); }
        }
        if found { Some(min) } else { None }
    }
    fn max(&self, na_rm: bool) -> Option<i32> {
        let s: &[i32] = self;
        let mut max = i32::MIN + 1;
        let mut found = false;
        for &x in s.iter() {
            if x.is_na() {
                if !na_rm { return None; }
            } else { found = true; max = max.max(x); }
        }
        if found { Some(max) } else { None }
    }
}impl_altinteger_slice!(Vec<i32>);
481impl AltrepDataptr<i32> for Vec<i32> {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut i32> {
        Some(self.as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const i32> {
        Some(self.as_ptr().cast())
    }
}impl_dataptr_vec!(i32);
482
483impl AltrepLen for Vec<f64> {
    fn altrep_len(&self) -> usize { Vec::len(self) }
}impl_len_vec!(f64);
484impl AltRealData for Vec<f64> {
    fn elt(&self, i: usize) -> f64 { self[i] }
    fn as_slice(&self) -> Option<&[f64]> { let s: &[f64] = self; Some(s) }
    fn get_region(&self, start: usize, len: usize, buf: &mut [f64]) -> usize {
        let s: &[f64] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
    fn no_na(&self) -> Option<bool> { Some(real_slice_no_na(self)) }
    fn sum(&self, na_rm: bool) -> Option<f64> {
        Some(real_slice_sum(self, na_rm))
    }
    fn min(&self, na_rm: bool) -> Option<f64> {
        real_slice_extreme(self, na_rm, f64::min)
    }
    fn max(&self, na_rm: bool) -> Option<f64> {
        real_slice_extreme(self, na_rm, f64::max)
    }
}impl_altreal_slice!(Vec<f64>);
485impl AltrepDataptr<f64> for Vec<f64> {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut f64> {
        Some(self.as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const f64> {
        Some(self.as_ptr().cast())
    }
}impl_dataptr_vec!(f64);
486
487impl AltrepLen for Vec<u8> {
    fn altrep_len(&self) -> usize { Vec::len(self) }
}impl_len_vec!(u8);
488impl AltRawData for Vec<u8> {
    fn elt(&self, i: usize) -> u8 { self[i] }
    fn as_slice(&self) -> Option<&[u8]> { let s: &[u8] = self; Some(s) }
    fn get_region(&self, start: usize, len: usize, buf: &mut [u8]) -> usize {
        let s: &[u8] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
}impl_altraw_slice!(Vec<u8>);
489impl AltrepDataptr<u8> for Vec<u8> {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut u8> {
        Some(self.as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const u8> {
        Some(self.as_ptr().cast())
    }
}impl_dataptr_vec!(u8);
490
491impl AltrepLen for Vec<String> {
    fn altrep_len(&self) -> usize { Vec::len(self) }
}impl_len_vec!(String);
492
493impl AltStringData for Vec<String> {
494    fn elt(&self, i: usize) -> Option<&str> {
495        Some(self[i].as_str())
496    }
497
498    fn no_na(&self) -> Option<bool> {
499        Some(true) // String vectors don't have NA
500    }
501}
502
503impl AltrepLen for Vec<Option<String>> {
    fn altrep_len(&self) -> usize { Vec::len(self) }
}impl_len_vec!(Option<String>);
504
505impl AltStringData for Vec<Option<String>> {
506    fn elt(&self, i: usize) -> Option<&str> {
507        self[i].as_deref()
508    }
509
510    fn no_na(&self) -> Option<bool> {
511        Some(!self.iter().any(|x| x.is_none()))
512    }
513}
514
515impl AltrepLen for Vec<std::borrow::Cow<'static, str>> {
516    fn altrep_len(&self) -> usize {
517        self.len()
518    }
519}
520
521impl AltStringData for Vec<std::borrow::Cow<'static, str>> {
522    fn elt(&self, i: usize) -> Option<&str> {
523        Some(self[i].as_ref())
524    }
525
526    fn no_na(&self) -> Option<bool> {
527        Some(true) // Cow vectors don't have NA
528    }
529}
530
531impl AltrepLen for Vec<Option<std::borrow::Cow<'static, str>>> {
532    fn altrep_len(&self) -> usize {
533        self.len()
534    }
535}
536
537impl AltStringData for Vec<Option<std::borrow::Cow<'static, str>>> {
538    fn elt(&self, i: usize) -> Option<&str> {
539        self[i].as_deref()
540    }
541
542    fn no_na(&self) -> Option<bool> {
543        Some(!self.iter().any(|x| x.is_none()))
544    }
545}
546
547impl AltrepLen for Vec<bool> {
    fn altrep_len(&self) -> usize { Vec::len(self) }
}impl_len_vec!(bool);
548impl AltLogicalData for Vec<bool> {
    fn elt(&self, i: usize) -> Logical { self[i].into() }
    fn no_na(&self) -> Option<bool> { Some(true) }
    fn sum(&self, _na_rm: bool) -> Option<i64> {
        let s: &[bool] = self;
        Some(s.iter().filter(|&&x| x).count() as i64)
    }
}impl_altlogical_slice!(Vec<bool>);
549
550impl AltrepLen for Vec<RLogical> {
    fn altrep_len(&self) -> usize { Vec::len(self) }
}impl_len_vec!(RLogical);
551impl AltLogicalData for Vec<RLogical> {
    fn elt(&self, i: usize) -> Logical { self[i].into() }
    fn as_r_slice(&self) -> Option<&[i32]> {
        let values: &[RLogical] = self;
        Some(unsafe {
                std::slice::from_raw_parts(values.as_ptr().cast(),
                    values.len())
            })
    }
    fn get_region(&self, start: usize, len: usize, out: &mut [i32]) -> usize {
        let values: &[RLogical] = self;
        super::fill_region(start, len, values.len(), out,
            |i| values[i].to_i32())
    }
    fn no_na(&self) -> Option<bool> {
        let values: &[RLogical] = self;
        Some(!values.iter().any(IsNA::is_na))
    }
}impl_altlogical_native_slice!(Vec<RLogical>);
552impl AltrepDataptr<i32> for Vec<RLogical> {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut i32> {
        Some(self.as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const i32> {
        Some(self.as_ptr().cast())
    }
}impl_dataptr_vec!(RLogical => i32);
553// endregion
554
555// region: Built-in implementations for Box<[T]> (owned slices)
556// Box<[T]> is a fat pointer (Sized) that wraps a DST slice.
557// Unlike Vec<T>, it has no capacity field - just ptr + len (2 words).
558// This makes it more memory-efficient for fixed-size data.
559//
560// Box<[T]> CAN be used directly with ALTREP via the proc-macro:
561// ```
562// #[miniextendr(class = "BoxedInts")]
563// pub struct BoxedIntsClass(Box<[i32]>);
564// ```
565//
566// Or use these trait implementations in custom wrapper structs.
567
568impl AltrepLen for Box<[i32]> {
    fn altrep_len(&self) -> usize { <[i32]>::len(self) }
}impl_len_boxed!(i32);
569impl AltIntegerData for Box<[i32]> {
    fn elt(&self, i: usize) -> i32 { self[i] }
    fn as_slice(&self) -> Option<&[i32]> { let s: &[i32] = self; Some(s) }
    fn get_region(&self, start: usize, len: usize, buf: &mut [i32]) -> usize {
        let s: &[i32] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
    fn no_na(&self) -> Option<bool> {
        let s: &[i32] = self;
        Some(!s.iter().any(IsNA::is_na))
    }
    fn sum(&self, na_rm: bool) -> Option<i64> {
        let s: &[i32] = self;
        let mut sum: i64 = 0;
        for &x in s.iter() {
            if x.is_na() {
                if !na_rm { return None; }
            } else { sum += x as i64; }
        }
        Some(sum)
    }
    fn min(&self, na_rm: bool) -> Option<i32> {
        let s: &[i32] = self;
        let mut min = i32::MAX;
        let mut found = false;
        for &x in s.iter() {
            if x.is_na() {
                if !na_rm { return None; }
            } else { found = true; min = min.min(x); }
        }
        if found { Some(min) } else { None }
    }
    fn max(&self, na_rm: bool) -> Option<i32> {
        let s: &[i32] = self;
        let mut max = i32::MIN + 1;
        let mut found = false;
        for &x in s.iter() {
            if x.is_na() {
                if !na_rm { return None; }
            } else { found = true; max = max.max(x); }
        }
        if found { Some(max) } else { None }
    }
}impl_altinteger_slice!(Box<[i32]>);
570impl AltrepDataptr<i32> for Box<[i32]> {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut i32> {
        Some(self.as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const i32> {
        Some(self.as_ptr().cast())
    }
}impl_dataptr_boxed!(i32);
571
572impl AltrepLen for Box<[f64]> {
    fn altrep_len(&self) -> usize { <[f64]>::len(self) }
}impl_len_boxed!(f64);
573impl AltRealData for Box<[f64]> {
    fn elt(&self, i: usize) -> f64 { self[i] }
    fn as_slice(&self) -> Option<&[f64]> { let s: &[f64] = self; Some(s) }
    fn get_region(&self, start: usize, len: usize, buf: &mut [f64]) -> usize {
        let s: &[f64] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
    fn no_na(&self) -> Option<bool> { Some(real_slice_no_na(self)) }
    fn sum(&self, na_rm: bool) -> Option<f64> {
        Some(real_slice_sum(self, na_rm))
    }
    fn min(&self, na_rm: bool) -> Option<f64> {
        real_slice_extreme(self, na_rm, f64::min)
    }
    fn max(&self, na_rm: bool) -> Option<f64> {
        real_slice_extreme(self, na_rm, f64::max)
    }
}impl_altreal_slice!(Box<[f64]>);
574impl AltrepDataptr<f64> for Box<[f64]> {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut f64> {
        Some(self.as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const f64> {
        Some(self.as_ptr().cast())
    }
}impl_dataptr_boxed!(f64);
575
576impl AltrepLen for Box<[u8]> {
    fn altrep_len(&self) -> usize { <[u8]>::len(self) }
}impl_len_boxed!(u8);
577impl AltRawData for Box<[u8]> {
    fn elt(&self, i: usize) -> u8 { self[i] }
    fn as_slice(&self) -> Option<&[u8]> { let s: &[u8] = self; Some(s) }
    fn get_region(&self, start: usize, len: usize, buf: &mut [u8]) -> usize {
        let s: &[u8] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
}impl_altraw_slice!(Box<[u8]>);
578impl AltrepDataptr<u8> for Box<[u8]> {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut u8> {
        Some(self.as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const u8> {
        Some(self.as_ptr().cast())
    }
}impl_dataptr_boxed!(u8);
579
580impl AltrepLen for Box<[bool]> {
    fn altrep_len(&self) -> usize { <[bool]>::len(self) }
}impl_len_boxed!(bool);
581impl AltLogicalData for Box<[bool]> {
    fn elt(&self, i: usize) -> Logical { self[i].into() }
    fn no_na(&self) -> Option<bool> { Some(true) }
    fn sum(&self, _na_rm: bool) -> Option<i64> {
        let s: &[bool] = self;
        Some(s.iter().filter(|&&x| x).count() as i64)
    }
}impl_altlogical_slice!(Box<[bool]>);
582
583impl AltrepLen for Box<[RLogical]> {
    fn altrep_len(&self) -> usize { <[RLogical]>::len(self) }
}impl_len_boxed!(RLogical);
584impl AltLogicalData for Box<[RLogical]> {
    fn elt(&self, i: usize) -> Logical { self[i].into() }
    fn as_r_slice(&self) -> Option<&[i32]> {
        let values: &[RLogical] = self;
        Some(unsafe {
                std::slice::from_raw_parts(values.as_ptr().cast(),
                    values.len())
            })
    }
    fn get_region(&self, start: usize, len: usize, out: &mut [i32]) -> usize {
        let values: &[RLogical] = self;
        super::fill_region(start, len, values.len(), out,
            |i| values[i].to_i32())
    }
    fn no_na(&self) -> Option<bool> {
        let values: &[RLogical] = self;
        Some(!values.iter().any(IsNA::is_na))
    }
}impl_altlogical_native_slice!(Box<[RLogical]>);
585impl AltrepDataptr<i32> for Box<[RLogical]> {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut i32> {
        Some(self.as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const i32> {
        Some(self.as_ptr().cast())
    }
}impl_dataptr_boxed!(RLogical => i32);
586
587impl AltrepLen for Box<[String]> {
    fn altrep_len(&self) -> usize { <[String]>::len(self) }
}impl_len_boxed!(String);
588
589impl AltStringData for Box<[String]> {
590    fn elt(&self, i: usize) -> Option<&str> {
591        Some(self[i].as_str())
592    }
593
594    fn no_na(&self) -> Option<bool> {
595        Some(true) // String can't be NA
596    }
597}
598// endregion
599
600// region: AltrepSerialize implementations for Range types
601// Ranges serialize to a 2-element integer/real vector [start, end].
602
603impl AltrepSerialize for Range<i32> {
604    fn serialized_state(&self) -> SEXP {
605        use crate::into_r::IntoR;
606        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [self.start, self.end]))vec![self.start, self.end].into_sexp()
607    }
608
609    fn unserialize(state: SEXP) -> Option<Self> {
610        use crate::from_r::TryFromSexp;
611        let v = Vec::<i32>::try_from_sexp(state).ok()?;
612        if v.len() == 2 { Some(v[0]..v[1]) } else { None }
613    }
614}
615
616impl AltrepSerialize for Range<i64> {
617    fn serialized_state(&self) -> SEXP {
618        use crate::into_r::IntoR;
619        // Store i64 bit patterns in f64 slots for lossless round-trip.
620        // Plain `as f64` loses precision for values > 2^53.
621        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [f64::from_bits(self.start as u64), f64::from_bits(self.end as u64)]))vec![
622            f64::from_bits(self.start as u64),
623            f64::from_bits(self.end as u64),
624        ]
625        .into_sexp()
626    }
627
628    fn unserialize(state: SEXP) -> Option<Self> {
629        use crate::from_r::TryFromSexp;
630        let v = Vec::<f64>::try_from_sexp(state).ok()?;
631        if v.len() == 2 {
632            Some((v[0].to_bits() as i64)..(v[1].to_bits() as i64))
633        } else {
634            None
635        }
636    }
637}
638
639impl AltrepSerialize for Range<f64> {
640    fn serialized_state(&self) -> SEXP {
641        use crate::into_r::IntoR;
642        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [self.start, self.end]))vec![self.start, self.end].into_sexp()
643    }
644
645    fn unserialize(state: SEXP) -> Option<Self> {
646        use crate::from_r::TryFromSexp;
647        let v = Vec::<f64>::try_from_sexp(state).ok()?;
648        if v.len() == 2 { Some(v[0]..v[1]) } else { None }
649    }
650}
651// endregion
652
653// region: Built-in implementations for Range types
654
655impl AltrepLen for Range<i32> {
656    fn altrep_len(&self) -> usize {
657        if self.end > self.start {
658            (self.end - self.start) as usize
659        } else {
660            0
661        }
662    }
663}
664
665impl AltIntegerData for Range<i32> {
666    fn elt(&self, i: usize) -> i32 {
667        self.start + i as i32
668    }
669
670    fn is_sorted(&self) -> Option<Sortedness> {
671        Some(Sortedness::Increasing)
672    }
673
674    fn no_na(&self) -> Option<bool> {
675        // i32::MIN is NA_INTEGER in R. Check if the range contains it.
676        // Range is [start, end), so i32::MIN is included iff start <= i32::MIN < end
677        // Since start is the smallest value, we just check if start == i32::MIN
678        let contains_na = self.start.is_na() && self.end > i32::MIN;
679        Some(!contains_na)
680    }
681
682    fn sum(&self, na_rm: bool) -> Option<i64> {
683        let n = AltrepLen::altrep_len(self) as i64;
684        if n == 0 {
685            return Some(0);
686        }
687
688        // Check if range contains NA (i32::MIN)
689        let contains_na = self.start.is_na() && self.end > i32::MIN;
690        if contains_na && !na_rm {
691            return None; // NA propagates
692        }
693
694        // Sum of arithmetic sequence: n/2 * (first + last)
695        // If na_rm and contains NA, exclude the first element (i32::MIN)
696        if contains_na {
697            // Exclude first element (NA), sum from start+1 to end-1
698            let n_valid = n - 1;
699            if n_valid == 0 {
700                return Some(0);
701            }
702            let first = (self.start + 1) as i64;
703            let last = (self.end - 1) as i64;
704            Some(n_valid * (first + last) / 2)
705        } else {
706            let first = self.start as i64;
707            let last = (self.end - 1) as i64;
708            Some(n * (first + last) / 2)
709        }
710    }
711
712    fn min(&self, na_rm: bool) -> Option<i32> {
713        if AltrepLen::altrep_len(self) == 0 {
714            return None;
715        }
716
717        // Check if first element is NA
718        if self.start.is_na() {
719            if na_rm {
720                // Skip NA, return second element if it exists
721                if self.end > self.start + 1 {
722                    Some(self.start + 1)
723                } else {
724                    None // Only element was NA
725                }
726            } else {
727                None // NA propagates
728            }
729        } else {
730            Some(self.start)
731        }
732    }
733
734    fn max(&self, na_rm: bool) -> Option<i32> {
735        if AltrepLen::altrep_len(self) == 0 {
736            return None;
737        }
738
739        // For increasing range, max is end-1 (last element)
740        // Check if range contains NA (first element)
741        let contains_na = self.start.is_na() && self.end > i32::MIN;
742        if contains_na && !na_rm {
743            return None; // NA propagates
744        }
745
746        // Max is always end-1 (last element), which is not NA
747        // (NA would only be first element if start == i32::MIN)
748        Some(self.end - 1)
749    }
750}
751
752impl AltrepLen for Range<i64> {
753    fn altrep_len(&self) -> usize {
754        if self.end > self.start {
755            (self.end - self.start) as usize
756        } else {
757            0
758        }
759    }
760}
761
762impl AltIntegerData for Range<i64> {
763    fn elt(&self, i: usize) -> i32 {
764        let val = self.start.saturating_add(i as i64);
765        // Bounds check: return NA_INTEGER for values outside i32 range
766        // Also, i32::MIN is the NA sentinel, so values equal to it are NA
767        if val > i32::MAX as i64 || val <= i32::MIN as i64 {
768            crate::altrep_traits::NA_INTEGER
769        } else {
770            val as i32
771        }
772    }
773
774    fn is_sorted(&self) -> Option<Sortedness> {
775        Some(Sortedness::Increasing)
776    }
777
778    fn no_na(&self) -> Option<bool> {
779        // An element is NA if:
780        // 1. It's outside valid i32 range (< i32::MIN or > i32::MAX)
781        // 2. It equals i32::MIN (NA sentinel)
782        //
783        // For increasing range [start, end), elements range from start to end-1.
784        // Range contains NA if:
785        // - start <= i32::MIN as i64 (NA sentinel could be in range)
786        // - OR end > i32::MAX as i64 + 1 (values exceed i32::MAX)
787        // - OR start < i32::MIN as i64 (values below i32 range)
788        let na_sentinel = i32::MIN as i64;
789        let i32_max = i32::MAX as i64;
790
791        // Check if NA sentinel is in [start, end)
792        let contains_na_sentinel = self.start <= na_sentinel && self.end > na_sentinel;
793
794        // Check if any values are outside valid i32 range
795        // Valid range for ALTREP integers: (i32::MIN, i32::MAX] (excluding NA sentinel)
796        let has_underflow = self.start < na_sentinel;
797        let has_overflow = (self.end - 1) > i32_max;
798
799        Some(!contains_na_sentinel && !has_underflow && !has_overflow)
800    }
801
802    fn sum(&self, na_rm: bool) -> Option<i64> {
803        let n = AltrepLen::altrep_len(self) as i64;
804        if n == 0 {
805            return Some(0);
806        }
807
808        // Check if range contains any NA values
809        let na_sentinel = i32::MIN as i64;
810        let i32_max = i32::MAX as i64;
811        let contains_na_sentinel = self.start <= na_sentinel && self.end > na_sentinel;
812        let has_underflow = self.start < na_sentinel;
813        let has_overflow = (self.end - 1) > i32_max;
814        let has_na = contains_na_sentinel || has_underflow || has_overflow;
815
816        if has_na && !na_rm {
817            return None; // NA propagates
818        }
819
820        if has_na {
821            // When na_rm=true, we need to exclude NA values
822            // This is complex for ranges with out-of-bounds values, so let R compute
823            return None;
824        }
825
826        let first = self.start;
827        let last = self.end - 1;
828
829        // Use checked arithmetic to detect overflow
830        // Formula: n * (first + last) / 2
831        let sum_endpoints = first.checked_add(last)?;
832        let product = n.checked_mul(sum_endpoints)?;
833        Some(product / 2)
834    }
835
836    fn min(&self, na_rm: bool) -> Option<i32> {
837        if AltrepLen::altrep_len(self) == 0 {
838            return None;
839        }
840
841        let na_sentinel = i32::MIN as i64;
842        let i32_max = i32::MAX as i64;
843
844        // Check for NA conditions
845        let contains_na_sentinel = self.start <= na_sentinel && self.end > na_sentinel;
846        let has_underflow = self.start < na_sentinel;
847        let has_overflow = (self.end - 1) > i32_max;
848        let has_na = contains_na_sentinel || has_underflow || has_overflow;
849
850        if has_na && !na_rm {
851            return None; // NA propagates
852        }
853
854        if has_na {
855            // Complex case: need to find first non-NA value
856            // Let R compute this
857            return None;
858        }
859
860        // No NA, return start (which is within valid i32 range)
861        Some(self.start as i32)
862    }
863
864    fn max(&self, na_rm: bool) -> Option<i32> {
865        if AltrepLen::altrep_len(self) == 0 {
866            return None;
867        }
868
869        let na_sentinel = i32::MIN as i64;
870        let i32_max = i32::MAX as i64;
871
872        // Check for NA conditions
873        let contains_na_sentinel = self.start <= na_sentinel && self.end > na_sentinel;
874        let has_underflow = self.start < na_sentinel;
875        let has_overflow = (self.end - 1) > i32_max;
876        let has_na = contains_na_sentinel || has_underflow || has_overflow;
877
878        if has_na && !na_rm {
879            return None; // NA propagates
880        }
881
882        if has_na {
883            // Complex case: need to find last non-NA value
884            // Let R compute this
885            return None;
886        }
887
888        // No NA, return end-1 (which is within valid i32 range)
889        Some((self.end - 1) as i32)
890    }
891}
892
893impl AltrepLen for Range<f64> {
894    fn altrep_len(&self) -> usize {
895        // For f64 ranges, assume step of 1.0
896        if self.end > self.start {
897            (self.end - self.start).ceil() as usize
898        } else {
899            0
900        }
901    }
902}
903
904impl AltRealData for Range<f64> {
905    fn elt(&self, i: usize) -> f64 {
906        self.start + i as f64
907    }
908
909    fn is_sorted(&self) -> Option<Sortedness> {
910        Some(Sortedness::Increasing)
911    }
912
913    fn no_na(&self) -> Option<bool> {
914        Some(true)
915    }
916
917    fn sum(&self, _na_rm: bool) -> Option<f64> {
918        let n = AltrepLen::altrep_len(self) as f64;
919        if n == 0.0 {
920            return Some(0.0);
921        }
922        let first = self.start;
923        let last = self.start + (n - 1.0);
924        Some(n * (first + last) / 2.0)
925    }
926
927    fn min(&self, _na_rm: bool) -> Option<f64> {
928        if AltrepLen::altrep_len(self) > 0 {
929            Some(self.start)
930        } else {
931            None
932        }
933    }
934
935    fn max(&self, _na_rm: bool) -> Option<f64> {
936        if AltrepLen::altrep_len(self) > 0 {
937            Some(self.start + (AltrepLen::altrep_len(self) - 1) as f64)
938        } else {
939            None
940        }
941    }
942}
943// endregion
944
945// region: Built-in implementations for slices (read-only)
946
947impl AltrepLen for &[i32] {
    fn altrep_len(&self) -> usize { <[i32]>::len(self) }
}impl_len_slice!(i32);
948impl AltIntegerData for &[i32] {
    fn elt(&self, i: usize) -> i32 { self[i] }
    fn as_slice(&self) -> Option<&[i32]> { let s: &[i32] = self; Some(s) }
    fn get_region(&self, start: usize, len: usize, buf: &mut [i32]) -> usize {
        let s: &[i32] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
    fn no_na(&self) -> Option<bool> {
        let s: &[i32] = self;
        Some(!s.iter().any(IsNA::is_na))
    }
    fn sum(&self, na_rm: bool) -> Option<i64> {
        let s: &[i32] = self;
        let mut sum: i64 = 0;
        for &x in s.iter() {
            if x.is_na() {
                if !na_rm { return None; }
            } else { sum += x as i64; }
        }
        Some(sum)
    }
    fn min(&self, na_rm: bool) -> Option<i32> {
        let s: &[i32] = self;
        let mut min = i32::MAX;
        let mut found = false;
        for &x in s.iter() {
            if x.is_na() {
                if !na_rm { return None; }
            } else { found = true; min = min.min(x); }
        }
        if found { Some(min) } else { None }
    }
    fn max(&self, na_rm: bool) -> Option<i32> {
        let s: &[i32] = self;
        let mut max = i32::MIN + 1;
        let mut found = false;
        for &x in s.iter() {
            if x.is_na() {
                if !na_rm { return None; }
            } else { found = true; max = max.max(x); }
        }
        if found { Some(max) } else { None }
    }
}impl_altinteger_slice!(&[i32]);
949
950impl AltrepLen for &[f64] {
    fn altrep_len(&self) -> usize { <[f64]>::len(self) }
}impl_len_slice!(f64);
951impl AltRealData for &[f64] {
    fn elt(&self, i: usize) -> f64 { self[i] }
    fn as_slice(&self) -> Option<&[f64]> { let s: &[f64] = self; Some(s) }
    fn get_region(&self, start: usize, len: usize, buf: &mut [f64]) -> usize {
        let s: &[f64] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
    fn no_na(&self) -> Option<bool> { Some(real_slice_no_na(self)) }
    fn sum(&self, na_rm: bool) -> Option<f64> {
        Some(real_slice_sum(self, na_rm))
    }
    fn min(&self, na_rm: bool) -> Option<f64> {
        real_slice_extreme(self, na_rm, f64::min)
    }
    fn max(&self, na_rm: bool) -> Option<f64> {
        real_slice_extreme(self, na_rm, f64::max)
    }
}impl_altreal_slice!(&[f64]);
952
953impl AltrepLen for &[u8] {
    fn altrep_len(&self) -> usize { <[u8]>::len(self) }
}impl_len_slice!(u8);
954impl AltRawData for &[u8] {
    fn elt(&self, i: usize) -> u8 { self[i] }
    fn as_slice(&self) -> Option<&[u8]> { let s: &[u8] = self; Some(s) }
    fn get_region(&self, start: usize, len: usize, buf: &mut [u8]) -> usize {
        let s: &[u8] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
}impl_altraw_slice!(&[u8]);
955
956impl AltrepLen for &[bool] {
    fn altrep_len(&self) -> usize { <[bool]>::len(self) }
}impl_len_slice!(bool);
957impl AltLogicalData for &[bool] {
    fn elt(&self, i: usize) -> Logical { self[i].into() }
    fn no_na(&self) -> Option<bool> { Some(true) }
    fn sum(&self, _na_rm: bool) -> Option<i64> {
        let s: &[bool] = self;
        Some(s.iter().filter(|&&x| x).count() as i64)
    }
}impl_altlogical_slice!(&[bool]);
958
959impl AltrepLen for &[String] {
    fn altrep_len(&self) -> usize { <[String]>::len(self) }
}impl_len_slice!(String);
960
961impl AltStringData for &[String] {
962    fn elt(&self, i: usize) -> Option<&str> {
963        Some(self[i].as_str())
964    }
965}
966
967impl AltrepLen for &[&str] {
    fn altrep_len(&self) -> usize { <[&str]>::len(self) }
}impl_len_slice!(&str);
968
969impl AltStringData for &[&str] {
970    fn elt(&self, i: usize) -> Option<&str> {
971        Some(self[i])
972    }
973}
974// endregion
975
976// region: NOTE on &'static [T] (static slices)
977//
978// `&'static [T]` is Sized (fat pointer: ptr + len) and satisfies 'static,
979// so it can be used DIRECTLY with ALTREP via ExternalPtr.
980//
981// The data trait implementations above for `&[T]` already cover `&'static [T]`
982// since `&'static [T]` is a subtype of `&[T]`. The ALTREP trait implementations
983// (Altrep, AltVec, AltInteger, etc.) are provided separately in altrep_impl.rs.
984//
985// Use cases:
986// - Const arrays: `static DATA: [i32; 5] = [1, 2, 3, 4, 5]; create_altrep(&DATA[..])`
987// - Leaked data: `let s: &'static [i32] = Box::leak(vec.into_boxed_slice());`
988// - Memory-mapped files with 'static lifetime
989// endregion
990
991// region: Built-in implementations for arrays (owned, fixed-size)
992
993// Native arrays live directly inside their ExternalPtr allocation.
994macro_rules! impl_dataptr_array {
995    ($elem:ty => $storage:ty) => {
996        impl<const N: usize> AltrepDataptr<$storage> for [$elem; N] {
997            fn dataptr(&mut self, _writable: bool) -> Option<*mut $storage> {
998                Some(self.as_mut_ptr().cast())
999            }
1000
1001            fn dataptr_or_null(&self) -> Option<*const $storage> {
1002                Some(self.as_ptr().cast())
1003            }
1004        }
1005    };
1006}
1007
1008impl<const N : usize> AltrepDataptr<i32> for [i32; N] {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut i32> {
        Some(self.as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const i32> {
        Some(self.as_ptr().cast())
    }
}impl_dataptr_array!(i32 => i32);
1009impl<const N : usize> AltrepDataptr<f64> for [f64; N] {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut f64> {
        Some(self.as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const f64> {
        Some(self.as_ptr().cast())
    }
}impl_dataptr_array!(f64 => f64);
1010impl<const N : usize> AltrepDataptr<u8> for [u8; N] {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut u8> {
        Some(self.as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const u8> {
        Some(self.as_ptr().cast())
    }
}impl_dataptr_array!(u8 => u8);
1011impl<const N : usize> AltrepDataptr<Rcomplex> for [Rcomplex; N] {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut Rcomplex> {
        Some(self.as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const Rcomplex> {
        Some(self.as_ptr().cast())
    }
}impl_dataptr_array!(Rcomplex => Rcomplex);
1012impl<const N : usize> AltrepDataptr<i32> for [RLogical; N] {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut i32> {
        Some(self.as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const i32> {
        Some(self.as_ptr().cast())
    }
}impl_dataptr_array!(RLogical => i32);
1013
1014impl<const N : usize> AltrepLen for [RLogical; N] {
    fn altrep_len(&self) -> usize { N }
}impl_len_array!(RLogical);
1015
1016impl<const N: usize> AltLogicalData for [RLogical; N] {
1017    fn elt(&self, i: usize) -> Logical {
1018        self[i].into()
1019    }
1020
1021    fn as_r_slice(&self) -> Option<&[i32]> {
1022        // RLogical is transparent over i32 and accepts every bit pattern.
1023        Some(unsafe { std::slice::from_raw_parts(self.as_ptr().cast(), N) })
1024    }
1025
1026    fn get_region(&self, start: usize, len: usize, out: &mut [i32]) -> usize {
1027        super::fill_region(start, len, N, out, |i| self[i].to_i32())
1028    }
1029
1030    fn no_na(&self) -> Option<bool> {
1031        Some(!self.contains(&RLogical::NA))
1032    }
1033}
1034
1035impl<const N : usize> AltrepLen for [i32; N] {
    fn altrep_len(&self) -> usize { N }
}impl_len_array!(i32);
1036
1037impl<const N: usize> AltIntegerData for [i32; N] {
1038    fn elt(&self, i: usize) -> i32 {
1039        self[i]
1040    }
1041
1042    fn as_slice(&self) -> Option<&[i32]> {
1043        Some(self.as_slice())
1044    }
1045
1046    fn get_region(&self, start: usize, len: usize, buf: &mut [i32]) -> usize {
1047        super::fill_region(start, len, N, buf, |i| self[i])
1048    }
1049
1050    fn no_na(&self) -> Option<bool> {
1051        Some(!self.iter().any(IsNA::is_na))
1052    }
1053}
1054
1055impl<const N : usize> AltrepLen for [f64; N] {
    fn altrep_len(&self) -> usize { N }
}impl_len_array!(f64);
1056
1057impl<const N: usize> AltRealData for [f64; N] {
1058    fn elt(&self, i: usize) -> f64 {
1059        self[i]
1060    }
1061
1062    fn as_slice(&self) -> Option<&[f64]> {
1063        Some(self.as_slice())
1064    }
1065
1066    fn get_region(&self, start: usize, len: usize, buf: &mut [f64]) -> usize {
1067        super::fill_region(start, len, N, buf, |i| self[i])
1068    }
1069
1070    fn no_na(&self) -> Option<bool> {
1071        Some(real_slice_no_na(self))
1072    }
1073}
1074
1075impl<const N : usize> AltrepLen for [bool; N] {
    fn altrep_len(&self) -> usize { N }
}impl_len_array!(bool);
1076
1077impl<const N: usize> AltLogicalData for [bool; N] {
1078    fn elt(&self, i: usize) -> Logical {
1079        Logical::from_bool(self[i])
1080    }
1081
1082    fn no_na(&self) -> Option<bool> {
1083        Some(true) // bool arrays can't have NA
1084    }
1085}
1086
1087impl<const N : usize> AltrepLen for [u8; N] {
    fn altrep_len(&self) -> usize { N }
}impl_len_array!(u8);
1088
1089impl<const N: usize> AltRawData for [u8; N] {
1090    fn elt(&self, i: usize) -> u8 {
1091        self[i]
1092    }
1093
1094    fn as_slice(&self) -> Option<&[u8]> {
1095        Some(self.as_slice())
1096    }
1097
1098    fn get_region(&self, start: usize, len: usize, buf: &mut [u8]) -> usize {
1099        super::fill_region(start, len, N, buf, |i| self[i])
1100    }
1101}
1102
1103impl<const N : usize> AltrepLen for [String; N] {
    fn altrep_len(&self) -> usize { N }
}impl_len_array!(String);
1104
1105impl<const N: usize> AltStringData for [String; N] {
1106    fn elt(&self, i: usize) -> Option<&str> {
1107        Some(self[i].as_str())
1108    }
1109}
1110// endregion
1111
1112// region: Built-in implementations for Vec<Rcomplex> (complex numbers)
1113
1114impl AltrepLen for Vec<Rcomplex> {
    fn altrep_len(&self) -> usize { Vec::len(self) }
}impl_len_vec!(Rcomplex);
1115impl AltComplexData for Vec<Rcomplex> {
    fn elt(&self, i: usize) -> Rcomplex { self[i] }
    fn as_slice(&self) -> Option<&[Rcomplex]> {
        let s: &[Rcomplex] = self;
        Some(s)
    }
    fn get_region(&self, start: usize, len: usize, buf: &mut [Rcomplex])
        -> usize {
        let s: &[Rcomplex] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
}impl_altcomplex_slice!(Vec<Rcomplex>);
1116impl AltrepDataptr<Rcomplex> for Vec<Rcomplex> {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut Rcomplex> {
        Some(self.as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const Rcomplex> {
        Some(self.as_ptr().cast())
    }
}impl_dataptr_vec!(Rcomplex);
1117// endregion
1118
1119// region: Built-in implementations for Box<[Rcomplex]>
1120
1121impl AltrepLen for Box<[Rcomplex]> {
    fn altrep_len(&self) -> usize { <[Rcomplex]>::len(self) }
}impl_len_boxed!(Rcomplex);
1122impl AltComplexData for Box<[Rcomplex]> {
    fn elt(&self, i: usize) -> Rcomplex { self[i] }
    fn as_slice(&self) -> Option<&[Rcomplex]> {
        let s: &[Rcomplex] = self;
        Some(s)
    }
    fn get_region(&self, start: usize, len: usize, buf: &mut [Rcomplex])
        -> usize {
        let s: &[Rcomplex] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
}impl_altcomplex_slice!(Box<[Rcomplex]>);
1123impl AltrepDataptr<Rcomplex> for Box<[Rcomplex]> {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut Rcomplex> {
        Some(self.as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const Rcomplex> {
        Some(self.as_ptr().cast())
    }
}impl_dataptr_boxed!(Rcomplex);
1124// endregion
1125
1126// region: Built-in implementations for [Rcomplex; N] (complex arrays)
1127
1128impl<const N : usize> AltrepLen for [Rcomplex; N] {
    fn altrep_len(&self) -> usize { N }
}impl_len_array!(Rcomplex);
1129
1130impl<const N: usize> AltComplexData for [Rcomplex; N] {
1131    fn elt(&self, i: usize) -> Rcomplex {
1132        self[i]
1133    }
1134
1135    fn as_slice(&self) -> Option<&[Rcomplex]> {
1136        Some(self.as_slice())
1137    }
1138
1139    fn get_region(&self, start: usize, len: usize, buf: &mut [Rcomplex]) -> usize {
1140        super::fill_region(start, len, N, buf, |i| self[i])
1141    }
1142}
1143// endregion
1144
1145// region: Vectors of owned unsized strings
1146
1147macro_rules! impl_owned_str_altrep_data {
1148    ($owner:ident) => {
1149        impl_len_vec!($owner<str>);
1150        impl_len_vec!(Option<$owner<str>>);
1151        impl AltStringData for Vec<$owner<str>> {
1152            fn elt(&self, i: usize) -> Option<&str> {
1153                Some(self[i].as_ref())
1154            }
1155            fn no_na(&self) -> Option<bool> {
1156                Some(true)
1157            }
1158        }
1159        impl AltStringData for Vec<Option<$owner<str>>> {
1160            fn elt(&self, i: usize) -> Option<&str> {
1161                self[i].as_deref()
1162            }
1163            fn no_na(&self) -> Option<bool> {
1164                Some(self.iter().all(Option::is_some))
1165            }
1166        }
1167        impl_serialize!(Vec<$owner<str>>);
1168        impl_serialize!(Vec<Option<$owner<str>>>);
1169    };
1170}
1171impl AltrepLen for Vec<Option<Box<str>>> {
    fn altrep_len(&self) -> usize { Vec::len(self) }
}
impl AltStringData for Vec<Box<str>> {
    fn elt(&self, i: usize) -> Option<&str> { Some(self[i].as_ref()) }
    fn no_na(&self) -> Option<bool> { Some(true) }
}
impl AltStringData for Vec<Option<Box<str>>> {
    fn elt(&self, i: usize) -> Option<&str> { self[i].as_deref() }
    fn no_na(&self) -> Option<bool> { Some(self.iter().all(Option::is_some)) }
}
impl AltrepSerialize for Vec<Box<str>> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<Box<str>>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}
impl AltrepSerialize for Vec<Option<Box<str>>> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<Option<Box<str>>>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}impl_owned_str_altrep_data!(Box);
1172impl AltrepLen for Vec<Option<Rc<str>>> {
    fn altrep_len(&self) -> usize { Vec::len(self) }
}
impl AltStringData for Vec<Rc<str>> {
    fn elt(&self, i: usize) -> Option<&str> { Some(self[i].as_ref()) }
    fn no_na(&self) -> Option<bool> { Some(true) }
}
impl AltStringData for Vec<Option<Rc<str>>> {
    fn elt(&self, i: usize) -> Option<&str> { self[i].as_deref() }
    fn no_na(&self) -> Option<bool> { Some(self.iter().all(Option::is_some)) }
}
impl AltrepSerialize for Vec<Rc<str>> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<Rc<str>>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}
impl AltrepSerialize for Vec<Option<Rc<str>>> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<Option<Rc<str>>>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}impl_owned_str_altrep_data!(Rc);
1173impl AltrepLen for Vec<Option<Arc<str>>> {
    fn altrep_len(&self) -> usize { Vec::len(self) }
}
impl AltStringData for Vec<Arc<str>> {
    fn elt(&self, i: usize) -> Option<&str> { Some(self[i].as_ref()) }
    fn no_na(&self) -> Option<bool> { Some(true) }
}
impl AltStringData for Vec<Option<Arc<str>>> {
    fn elt(&self, i: usize) -> Option<&str> { self[i].as_deref() }
    fn no_na(&self) -> Option<bool> { Some(self.iter().all(Option::is_some)) }
}
impl AltrepSerialize for Vec<Arc<str>> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<Arc<str>>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}
impl AltrepSerialize for Vec<Option<Arc<str>>> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<Option<Arc<str>>>>::try_from_sexp(state).ok().map(std::convert::identity)
    }
}impl_owned_str_altrep_data!(Arc);
1174// endregion
1175
1176// region: Shared slices
1177
1178// A unique owner may already have supplied a pointer to R. Shared owners have
1179// not: Dataptr_or_null refuses them, and Dataptr detaches before exposing one.
1180// The duplicate callback uses the same rule, so it never re-shares exposed data.
1181macro_rules! impl_shared_slice_data {
1182    ($owner:ident) => {
1183        impl<T> AltrepLen for $owner<[T]> {
1184            fn altrep_len(&self) -> usize {
1185                <[T]>::len(self)
1186            }
1187        }
1188        impl_altinteger_slice!($owner<[i32]>);
1189        impl_altreal_slice!($owner<[f64]>);
1190        impl_altraw_slice!($owner<[u8]>);
1191        impl_altcomplex_slice!($owner<[Rcomplex]>);
1192        impl_altlogical_native_slice!($owner<[RLogical]>);
1193        impl_altlogical_slice!($owner<[bool]>);
1194        impl AltStringData for $owner<[String]> {
1195            fn elt(&self, i: usize) -> Option<&str> {
1196                Some(&self[i])
1197            }
1198            fn no_na(&self) -> Option<bool> {
1199                Some(true)
1200            }
1201        }
1202    };
1203}
1204macro_rules! impl_shared_slice_dataptr {
1205    ($owner:ident, $elem:ty, $storage:ty) => {
1206        impl AltrepDataptr<$storage> for $owner<[$elem]> {
1207            fn dataptr(&mut self, _writable: bool) -> Option<*mut $storage> {
1208                // Even a read-only pointer request detaches shared storage.
1209                // This keeps that pointer valid if a later write requests COW.
1210                Some($owner::make_mut(self).as_mut_ptr().cast())
1211            }
1212            fn dataptr_or_null(&self) -> Option<*const $storage> {
1213                ($owner::strong_count(self) == 1 && $owner::weak_count(self) == 0)
1214                    .then(|| self.as_ptr().cast())
1215            }
1216        }
1217    };
1218}
1219use std::rc::Rc;
1220use std::sync::Arc;
1221impl<T> AltrepLen for Rc<[T]> {
    fn altrep_len(&self) -> usize { <[T]>::len(self) }
}
impl AltIntegerData for Rc<[i32]> {
    fn elt(&self, i: usize) -> i32 { self[i] }
    fn as_slice(&self) -> Option<&[i32]> { let s: &[i32] = self; Some(s) }
    fn get_region(&self, start: usize, len: usize, buf: &mut [i32]) -> usize {
        let s: &[i32] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
    fn no_na(&self) -> Option<bool> {
        let s: &[i32] = self;
        Some(!s.iter().any(IsNA::is_na))
    }
    fn sum(&self, na_rm: bool) -> Option<i64> {
        let s: &[i32] = self;
        let mut sum: i64 = 0;
        for &x in s.iter() {
            if x.is_na() {
                if !na_rm { return None; }
            } else { sum += x as i64; }
        }
        Some(sum)
    }
    fn min(&self, na_rm: bool) -> Option<i32> {
        let s: &[i32] = self;
        let mut min = i32::MAX;
        let mut found = false;
        for &x in s.iter() {
            if x.is_na() {
                if !na_rm { return None; }
            } else { found = true; min = min.min(x); }
        }
        if found { Some(min) } else { None }
    }
    fn max(&self, na_rm: bool) -> Option<i32> {
        let s: &[i32] = self;
        let mut max = i32::MIN + 1;
        let mut found = false;
        for &x in s.iter() {
            if x.is_na() {
                if !na_rm { return None; }
            } else { found = true; max = max.max(x); }
        }
        if found { Some(max) } else { None }
    }
}
impl AltRealData for Rc<[f64]> {
    fn elt(&self, i: usize) -> f64 { self[i] }
    fn as_slice(&self) -> Option<&[f64]> { let s: &[f64] = self; Some(s) }
    fn get_region(&self, start: usize, len: usize, buf: &mut [f64]) -> usize {
        let s: &[f64] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
    fn no_na(&self) -> Option<bool> { Some(real_slice_no_na(self)) }
    fn sum(&self, na_rm: bool) -> Option<f64> {
        Some(real_slice_sum(self, na_rm))
    }
    fn min(&self, na_rm: bool) -> Option<f64> {
        real_slice_extreme(self, na_rm, f64::min)
    }
    fn max(&self, na_rm: bool) -> Option<f64> {
        real_slice_extreme(self, na_rm, f64::max)
    }
}
impl AltRawData for Rc<[u8]> {
    fn elt(&self, i: usize) -> u8 { self[i] }
    fn as_slice(&self) -> Option<&[u8]> { let s: &[u8] = self; Some(s) }
    fn get_region(&self, start: usize, len: usize, buf: &mut [u8]) -> usize {
        let s: &[u8] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
}
impl AltComplexData for Rc<[Rcomplex]> {
    fn elt(&self, i: usize) -> Rcomplex { self[i] }
    fn as_slice(&self) -> Option<&[Rcomplex]> {
        let s: &[Rcomplex] = self;
        Some(s)
    }
    fn get_region(&self, start: usize, len: usize, buf: &mut [Rcomplex])
        -> usize {
        let s: &[Rcomplex] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
}
impl AltLogicalData for Rc<[RLogical]> {
    fn elt(&self, i: usize) -> Logical { self[i].into() }
    fn as_r_slice(&self) -> Option<&[i32]> {
        let values: &[RLogical] = self;
        Some(unsafe {
                std::slice::from_raw_parts(values.as_ptr().cast(),
                    values.len())
            })
    }
    fn get_region(&self, start: usize, len: usize, out: &mut [i32]) -> usize {
        let values: &[RLogical] = self;
        super::fill_region(start, len, values.len(), out,
            |i| values[i].to_i32())
    }
    fn no_na(&self) -> Option<bool> {
        let values: &[RLogical] = self;
        Some(!values.iter().any(IsNA::is_na))
    }
}
impl AltLogicalData for Rc<[bool]> {
    fn elt(&self, i: usize) -> Logical { self[i].into() }
    fn no_na(&self) -> Option<bool> { Some(true) }
    fn sum(&self, _na_rm: bool) -> Option<i64> {
        let s: &[bool] = self;
        Some(s.iter().filter(|&&x| x).count() as i64)
    }
}
impl AltStringData for Rc<[String]> {
    fn elt(&self, i: usize) -> Option<&str> { Some(&self[i]) }
    fn no_na(&self) -> Option<bool> { Some(true) }
}impl_shared_slice_data!(Rc);
1222impl<T> AltrepLen for Arc<[T]> {
    fn altrep_len(&self) -> usize { <[T]>::len(self) }
}
impl AltIntegerData for Arc<[i32]> {
    fn elt(&self, i: usize) -> i32 { self[i] }
    fn as_slice(&self) -> Option<&[i32]> { let s: &[i32] = self; Some(s) }
    fn get_region(&self, start: usize, len: usize, buf: &mut [i32]) -> usize {
        let s: &[i32] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
    fn no_na(&self) -> Option<bool> {
        let s: &[i32] = self;
        Some(!s.iter().any(IsNA::is_na))
    }
    fn sum(&self, na_rm: bool) -> Option<i64> {
        let s: &[i32] = self;
        let mut sum: i64 = 0;
        for &x in s.iter() {
            if x.is_na() {
                if !na_rm { return None; }
            } else { sum += x as i64; }
        }
        Some(sum)
    }
    fn min(&self, na_rm: bool) -> Option<i32> {
        let s: &[i32] = self;
        let mut min = i32::MAX;
        let mut found = false;
        for &x in s.iter() {
            if x.is_na() {
                if !na_rm { return None; }
            } else { found = true; min = min.min(x); }
        }
        if found { Some(min) } else { None }
    }
    fn max(&self, na_rm: bool) -> Option<i32> {
        let s: &[i32] = self;
        let mut max = i32::MIN + 1;
        let mut found = false;
        for &x in s.iter() {
            if x.is_na() {
                if !na_rm { return None; }
            } else { found = true; max = max.max(x); }
        }
        if found { Some(max) } else { None }
    }
}
impl AltRealData for Arc<[f64]> {
    fn elt(&self, i: usize) -> f64 { self[i] }
    fn as_slice(&self) -> Option<&[f64]> { let s: &[f64] = self; Some(s) }
    fn get_region(&self, start: usize, len: usize, buf: &mut [f64]) -> usize {
        let s: &[f64] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
    fn no_na(&self) -> Option<bool> { Some(real_slice_no_na(self)) }
    fn sum(&self, na_rm: bool) -> Option<f64> {
        Some(real_slice_sum(self, na_rm))
    }
    fn min(&self, na_rm: bool) -> Option<f64> {
        real_slice_extreme(self, na_rm, f64::min)
    }
    fn max(&self, na_rm: bool) -> Option<f64> {
        real_slice_extreme(self, na_rm, f64::max)
    }
}
impl AltRawData for Arc<[u8]> {
    fn elt(&self, i: usize) -> u8 { self[i] }
    fn as_slice(&self) -> Option<&[u8]> { let s: &[u8] = self; Some(s) }
    fn get_region(&self, start: usize, len: usize, buf: &mut [u8]) -> usize {
        let s: &[u8] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
}
impl AltComplexData for Arc<[Rcomplex]> {
    fn elt(&self, i: usize) -> Rcomplex { self[i] }
    fn as_slice(&self) -> Option<&[Rcomplex]> {
        let s: &[Rcomplex] = self;
        Some(s)
    }
    fn get_region(&self, start: usize, len: usize, buf: &mut [Rcomplex])
        -> usize {
        let s: &[Rcomplex] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
}
impl AltLogicalData for Arc<[RLogical]> {
    fn elt(&self, i: usize) -> Logical { self[i].into() }
    fn as_r_slice(&self) -> Option<&[i32]> {
        let values: &[RLogical] = self;
        Some(unsafe {
                std::slice::from_raw_parts(values.as_ptr().cast(),
                    values.len())
            })
    }
    fn get_region(&self, start: usize, len: usize, out: &mut [i32]) -> usize {
        let values: &[RLogical] = self;
        super::fill_region(start, len, values.len(), out,
            |i| values[i].to_i32())
    }
    fn no_na(&self) -> Option<bool> {
        let values: &[RLogical] = self;
        Some(!values.iter().any(IsNA::is_na))
    }
}
impl AltLogicalData for Arc<[bool]> {
    fn elt(&self, i: usize) -> Logical { self[i].into() }
    fn no_na(&self) -> Option<bool> { Some(true) }
    fn sum(&self, _na_rm: bool) -> Option<i64> {
        let s: &[bool] = self;
        Some(s.iter().filter(|&&x| x).count() as i64)
    }
}
impl AltStringData for Arc<[String]> {
    fn elt(&self, i: usize) -> Option<&str> { Some(&self[i]) }
    fn no_na(&self) -> Option<bool> { Some(true) }
}impl_shared_slice_data!(Arc);
1223impl AltrepDataptr<i32> for Rc<[i32]> {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut i32> {
        Some(Rc::make_mut(self).as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const i32> {
        (Rc::strong_count(self) == 1 &&
                    Rc::weak_count(self) == 0).then(|| self.as_ptr().cast())
    }
}impl_shared_slice_dataptr!(Rc, i32, i32);
1224impl AltrepDataptr<f64> for Rc<[f64]> {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut f64> {
        Some(Rc::make_mut(self).as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const f64> {
        (Rc::strong_count(self) == 1 &&
                    Rc::weak_count(self) == 0).then(|| self.as_ptr().cast())
    }
}impl_shared_slice_dataptr!(Rc, f64, f64);
1225impl AltrepDataptr<u8> for Rc<[u8]> {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut u8> {
        Some(Rc::make_mut(self).as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const u8> {
        (Rc::strong_count(self) == 1 &&
                    Rc::weak_count(self) == 0).then(|| self.as_ptr().cast())
    }
}impl_shared_slice_dataptr!(Rc, u8, u8);
1226impl AltrepDataptr<Rcomplex> for Rc<[Rcomplex]> {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut Rcomplex> {
        Some(Rc::make_mut(self).as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const Rcomplex> {
        (Rc::strong_count(self) == 1 &&
                    Rc::weak_count(self) == 0).then(|| self.as_ptr().cast())
    }
}impl_shared_slice_dataptr!(Rc, Rcomplex, Rcomplex);
1227impl AltrepDataptr<i32> for Rc<[RLogical]> {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut i32> {
        Some(Rc::make_mut(self).as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const i32> {
        (Rc::strong_count(self) == 1 &&
                    Rc::weak_count(self) == 0).then(|| self.as_ptr().cast())
    }
}impl_shared_slice_dataptr!(Rc, RLogical, i32);
1228impl AltrepDataptr<i32> for Arc<[i32]> {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut i32> {
        Some(Arc::make_mut(self).as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const i32> {
        (Arc::strong_count(self) == 1 &&
                    Arc::weak_count(self) == 0).then(|| self.as_ptr().cast())
    }
}impl_shared_slice_dataptr!(Arc, i32, i32);
1229impl AltrepDataptr<f64> for Arc<[f64]> {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut f64> {
        Some(Arc::make_mut(self).as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const f64> {
        (Arc::strong_count(self) == 1 &&
                    Arc::weak_count(self) == 0).then(|| self.as_ptr().cast())
    }
}impl_shared_slice_dataptr!(Arc, f64, f64);
1230impl AltrepDataptr<u8> for Arc<[u8]> {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut u8> {
        Some(Arc::make_mut(self).as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const u8> {
        (Arc::strong_count(self) == 1 &&
                    Arc::weak_count(self) == 0).then(|| self.as_ptr().cast())
    }
}impl_shared_slice_dataptr!(Arc, u8, u8);
1231impl AltrepDataptr<Rcomplex> for Arc<[Rcomplex]> {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut Rcomplex> {
        Some(Arc::make_mut(self).as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const Rcomplex> {
        (Arc::strong_count(self) == 1 &&
                    Arc::weak_count(self) == 0).then(|| self.as_ptr().cast())
    }
}impl_shared_slice_dataptr!(Arc, Rcomplex, Rcomplex);
1232impl AltrepDataptr<i32> for Arc<[RLogical]> {
    fn dataptr(&mut self, _writable: bool) -> Option<*mut i32> {
        Some(Arc::make_mut(self).as_mut_ptr().cast())
    }
    fn dataptr_or_null(&self) -> Option<*const i32> {
        (Arc::strong_count(self) == 1 &&
                    Arc::weak_count(self) == 0).then(|| self.as_ptr().cast())
    }
}impl_shared_slice_dataptr!(Arc, RLogical, i32);
1233// endregion
1234
1235// region: Built-in implementations for Cow<'static, [T]>
1236//
1237// Cow<'static, [T]> supports static Rust borrows or owned R conversions, retaining
1238// ownership semantics. Borrowed variants expose the underlying R data directly
1239// via dataptr; Owned variants behave like Vec<T>. Copy-on-write happens
1240// automatically when R requests a writable dataptr on a Borrowed variant.
1241
1242macro_rules! impl_len_cow {
1243    ($elem:ty) => {
1244        impl AltrepLen for Cow<'static, [$elem]> {
1245            fn altrep_len(&self) -> usize {
1246                <[$elem]>::len(self)
1247            }
1248        }
1249    };
1250}
1251
1252macro_rules! impl_dataptr_cow {
1253    ($elem:ty) => {
1254        impl_dataptr_cow!($elem => $elem);
1255    };
1256    // The storage type must have the same layout and valid bit patterns.
1257    ($elem:ty => $storage:ty) => {
1258        impl AltrepDataptr<$storage> for Cow<'static, [$elem]> {
1259            fn dataptr(&mut self, writable: bool) -> Option<*mut $storage> {
1260                if writable {
1261                    // to_mut() triggers copy-on-write for Borrowed variants.
1262                    // Only do this when R intends to write through the pointer.
1263                    Some(self.to_mut().as_mut_ptr().cast())
1264                } else {
1265                    // Read-only access: return the existing pointer without
1266                    // forcing a copy for Borrowed variants.
1267                    Some(self.as_ptr().cast_mut().cast())
1268                }
1269            }
1270
1271            fn dataptr_or_null(&self) -> Option<*const $storage> {
1272                Some(self.as_ptr().cast())
1273            }
1274        }
1275    };
1276}
1277
1278// A restored ALTREP must not borrow the temporary state SEXP: data1 owns
1279// only the Rust value, and data2 is reserved for materialization.
1280impl AltrepLen for Cow<'static, [RLogical]> {
    fn altrep_len(&self) -> usize { <[RLogical]>::len(self) }
}impl_len_cow!(RLogical);
1281impl AltLogicalData for Cow<'static, [RLogical]> {
    fn elt(&self, i: usize) -> Logical { self[i].into() }
    fn as_r_slice(&self) -> Option<&[i32]> {
        let values: &[RLogical] = self;
        Some(unsafe {
                std::slice::from_raw_parts(values.as_ptr().cast(),
                    values.len())
            })
    }
    fn get_region(&self, start: usize, len: usize, out: &mut [i32]) -> usize {
        let values: &[RLogical] = self;
        super::fill_region(start, len, values.len(), out,
            |i| values[i].to_i32())
    }
    fn no_na(&self) -> Option<bool> {
        let values: &[RLogical] = self;
        Some(!values.iter().any(IsNA::is_na))
    }
}impl_altlogical_native_slice!(Cow<'static, [RLogical]>);
1282impl AltrepDataptr<i32> for Cow<'static, [RLogical]> {
    fn dataptr(&mut self, writable: bool) -> Option<*mut i32> {
        if writable {
            Some(self.to_mut().as_mut_ptr().cast())
        } else { Some(self.as_ptr().cast_mut().cast()) }
    }
    fn dataptr_or_null(&self) -> Option<*const i32> {
        Some(self.as_ptr().cast())
    }
}impl_dataptr_cow!(RLogical => i32);
1283impl AltrepSerialize for Cow<'static, [RLogical]> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<RLogical>>::try_from_sexp(state).ok().map(Cow::Owned)
    }
}impl_serialize!(Cow<'static, [RLogical]>, Vec<RLogical>, Cow::Owned);
1284
1285impl AltrepLen for Cow<'static, [i32]> {
    fn altrep_len(&self) -> usize { <[i32]>::len(self) }
}impl_len_cow!(i32);
1286impl AltIntegerData for Cow<'static, [i32]> {
    fn elt(&self, i: usize) -> i32 { self[i] }
    fn as_slice(&self) -> Option<&[i32]> { let s: &[i32] = self; Some(s) }
    fn get_region(&self, start: usize, len: usize, buf: &mut [i32]) -> usize {
        let s: &[i32] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
    fn no_na(&self) -> Option<bool> {
        let s: &[i32] = self;
        Some(!s.iter().any(IsNA::is_na))
    }
    fn sum(&self, na_rm: bool) -> Option<i64> {
        let s: &[i32] = self;
        let mut sum: i64 = 0;
        for &x in s.iter() {
            if x.is_na() {
                if !na_rm { return None; }
            } else { sum += x as i64; }
        }
        Some(sum)
    }
    fn min(&self, na_rm: bool) -> Option<i32> {
        let s: &[i32] = self;
        let mut min = i32::MAX;
        let mut found = false;
        for &x in s.iter() {
            if x.is_na() {
                if !na_rm { return None; }
            } else { found = true; min = min.min(x); }
        }
        if found { Some(min) } else { None }
    }
    fn max(&self, na_rm: bool) -> Option<i32> {
        let s: &[i32] = self;
        let mut max = i32::MIN + 1;
        let mut found = false;
        for &x in s.iter() {
            if x.is_na() {
                if !na_rm { return None; }
            } else { found = true; max = max.max(x); }
        }
        if found { Some(max) } else { None }
    }
}impl_altinteger_slice!(Cow<'static, [i32]>);
1287impl AltrepDataptr<i32> for Cow<'static, [i32]> {
    fn dataptr(&mut self, writable: bool) -> Option<*mut i32> {
        if writable {
            Some(self.to_mut().as_mut_ptr().cast())
        } else { Some(self.as_ptr().cast_mut().cast()) }
    }
    fn dataptr_or_null(&self) -> Option<*const i32> {
        Some(self.as_ptr().cast())
    }
}impl_dataptr_cow!(i32);
1288impl AltrepSerialize for Cow<'static, [i32]> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<i32>>::try_from_sexp(state).ok().map(Cow::Owned)
    }
}impl_serialize!(Cow<'static, [i32]>, Vec<i32>, Cow::Owned);
1289
1290impl AltrepLen for Cow<'static, [f64]> {
    fn altrep_len(&self) -> usize { <[f64]>::len(self) }
}impl_len_cow!(f64);
1291impl AltRealData for Cow<'static, [f64]> {
    fn elt(&self, i: usize) -> f64 { self[i] }
    fn as_slice(&self) -> Option<&[f64]> { let s: &[f64] = self; Some(s) }
    fn get_region(&self, start: usize, len: usize, buf: &mut [f64]) -> usize {
        let s: &[f64] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
    fn no_na(&self) -> Option<bool> { Some(real_slice_no_na(self)) }
    fn sum(&self, na_rm: bool) -> Option<f64> {
        Some(real_slice_sum(self, na_rm))
    }
    fn min(&self, na_rm: bool) -> Option<f64> {
        real_slice_extreme(self, na_rm, f64::min)
    }
    fn max(&self, na_rm: bool) -> Option<f64> {
        real_slice_extreme(self, na_rm, f64::max)
    }
}impl_altreal_slice!(Cow<'static, [f64]>);
1292impl AltrepDataptr<f64> for Cow<'static, [f64]> {
    fn dataptr(&mut self, writable: bool) -> Option<*mut f64> {
        if writable {
            Some(self.to_mut().as_mut_ptr().cast())
        } else { Some(self.as_ptr().cast_mut().cast()) }
    }
    fn dataptr_or_null(&self) -> Option<*const f64> {
        Some(self.as_ptr().cast())
    }
}impl_dataptr_cow!(f64);
1293impl AltrepSerialize for Cow<'static, [f64]> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<f64>>::try_from_sexp(state).ok().map(Cow::Owned)
    }
}impl_serialize!(Cow<'static, [f64]>, Vec<f64>, Cow::Owned);
1294
1295impl AltrepLen for Cow<'static, [u8]> {
    fn altrep_len(&self) -> usize { <[u8]>::len(self) }
}impl_len_cow!(u8);
1296impl AltRawData for Cow<'static, [u8]> {
    fn elt(&self, i: usize) -> u8 { self[i] }
    fn as_slice(&self) -> Option<&[u8]> { let s: &[u8] = self; Some(s) }
    fn get_region(&self, start: usize, len: usize, buf: &mut [u8]) -> usize {
        let s: &[u8] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
}impl_altraw_slice!(Cow<'static, [u8]>);
1297impl AltrepDataptr<u8> for Cow<'static, [u8]> {
    fn dataptr(&mut self, writable: bool) -> Option<*mut u8> {
        if writable {
            Some(self.to_mut().as_mut_ptr().cast())
        } else { Some(self.as_ptr().cast_mut().cast()) }
    }
    fn dataptr_or_null(&self) -> Option<*const u8> {
        Some(self.as_ptr().cast())
    }
}impl_dataptr_cow!(u8);
1298impl AltrepSerialize for Cow<'static, [u8]> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<u8>>::try_from_sexp(state).ok().map(Cow::Owned)
    }
}impl_serialize!(Cow<'static, [u8]>, Vec<u8>, Cow::Owned);
1299
1300impl AltrepLen for Cow<'static, [Rcomplex]> {
    fn altrep_len(&self) -> usize { <[Rcomplex]>::len(self) }
}impl_len_cow!(Rcomplex);
1301impl AltComplexData for Cow<'static, [Rcomplex]> {
    fn elt(&self, i: usize) -> Rcomplex { self[i] }
    fn as_slice(&self) -> Option<&[Rcomplex]> {
        let s: &[Rcomplex] = self;
        Some(s)
    }
    fn get_region(&self, start: usize, len: usize, buf: &mut [Rcomplex])
        -> usize {
        let s: &[Rcomplex] = self;
        let end = (start + len).min(s.len());
        let actual_len = end.saturating_sub(start);
        if actual_len > 0 {
            buf[..actual_len].copy_from_slice(&s[start..end]);
        }
        actual_len
    }
}impl_altcomplex_slice!(Cow<'static, [Rcomplex]>);
1302impl AltrepDataptr<Rcomplex> for Cow<'static, [Rcomplex]> {
    fn dataptr(&mut self, writable: bool) -> Option<*mut Rcomplex> {
        if writable {
            Some(self.to_mut().as_mut_ptr().cast())
        } else { Some(self.as_ptr().cast_mut().cast()) }
    }
    fn dataptr_or_null(&self) -> Option<*const Rcomplex> {
        Some(self.as_ptr().cast())
    }
}impl_dataptr_cow!(Rcomplex);
1303impl AltrepSerialize for Cow<'static, [Rcomplex]> {
    fn serialized_state(&self) -> SEXP {
        use crate::into_r::IntoR;
        self.clone().into_sexp()
    }
    fn unserialize(state: SEXP) -> Option<Self> {
        use crate::from_r::TryFromSexp;
        <Vec<Rcomplex>>::try_from_sexp(state).ok().map(Cow::Owned)
    }
}impl_serialize!(Cow<'static, [Rcomplex]>, Vec<Rcomplex>, Cow::Owned);
1304// endregion
1305
1306// region: Low-level ALTREP trait implementations
1307//
1308// The low-level trait impls (Altrep, AltVec, Alt*, InferBase) for builtin types
1309// are located in altrep_impl.rs. This is because the impl_alt*_from_data! macros
1310// are defined there and need to be in the same module.
1311//
1312// See altrep_impl.rs for:
1313// - Vec<i32>, Vec<f64>, Vec<bool>, Vec<u8>, Vec<String>, Vec<Rcomplex>
1314// - Box<[i32]>, Box<[f64]>, Box<[bool]>, Box<[u8]>, Box<[String]>, Box<[Rcomplex]>
1315// - Cow<'static, [i32]>, Cow<'static, [f64]>, Cow<'static, [u8]>, Cow<'static, [Rcomplex]>
1316// - Range<i32>, Range<i64>, Range<f64>
1317// endregion
1318
1319#[cfg(test)]
1320mod tests {
1321    use super::*;
1322    use crate::altrep_data::AltRealData;
1323    use crate::altrep_traits::NA_REAL;
1324
1325    /// `NA_real_ * 1` as R computes it: arithmetic quiets the NaN, so the
1326    /// high word differs from `NA_REAL`'s while the low word stays 1954.
1327    const COMPUTED_NA: f64 = f64::from_bits(0x7FF8_0000_0000_07A2);
1328
1329    // region: NA_REAL bit pattern tests
1330
1331    /// Verify NA_REAL has the expected R bit pattern.
1332    #[test]
1333    fn na_real_bit_pattern() {
1334        assert_eq!(NA_REAL.to_bits(), 0x7FF0_0000_0000_07A2);
1335    }
1336
1337    /// Regular NaN is NOT the same bit pattern as NA_real_.
1338    #[test]
1339    fn nan_is_not_na_real() {
1340        let nan = f64::NAN;
1341        assert!(nan.is_nan());
1342        assert_ne!(nan.to_bits(), NA_REAL.to_bits());
1343    }
1344
1345    // endregion
1346
1347    // region: Vec<f64> no_na — NA vs NaN
1348
1349    /// A vector holding a regular NaN reports no_na = Some(false): R's
1350    /// `anyNA()` trusts the hint and counts NaN as missing (`ISNAN`).
1351    #[test]
1352    fn vec_f64_no_na_with_regular_nan_is_false() {
1353        let v: Vec<f64> = vec![1.0, f64::NAN, 3.0];
1354        assert_eq!(AltRealData::no_na(&v), Some(false));
1355    }
1356
1357    /// A computed NA (`NA_real_ * 1` quiets the NaN) is still NA.
1358    #[test]
1359    fn vec_f64_no_na_with_computed_na_is_false() {
1360        let v: Vec<f64> = vec![1.0, COMPUTED_NA, 3.0];
1361        assert_eq!(AltRealData::no_na(&v), Some(false));
1362    }
1363
1364    /// A vector containing NA_real_ should report no_na = Some(false).
1365    #[test]
1366    fn vec_f64_no_na_with_na_real_is_false() {
1367        let v: Vec<f64> = vec![1.0, NA_REAL, 3.0];
1368        assert_eq!(AltRealData::no_na(&v), Some(false));
1369    }
1370
1371    /// A vector with no NaN and no NA should report no_na = Some(true).
1372    #[test]
1373    fn vec_f64_no_na_all_finite_is_true() {
1374        let v: Vec<f64> = vec![1.0, 2.0, 3.0];
1375        assert_eq!(AltRealData::no_na(&v), Some(true));
1376    }
1377
1378    // endregion
1379
1380    // region: Vec<f64> sum — NA vs NaN
1381
1382    /// sum with na_rm=false and NA_real_ present should return Some(NA_REAL).
1383    #[test]
1384    fn vec_f64_sum_na_propagates() {
1385        let v: Vec<f64> = vec![1.0, NA_REAL, 3.0];
1386        let result = AltRealData::sum(&v, false);
1387        assert!(result.is_some());
1388        let bits = result.unwrap().to_bits();
1389        assert_eq!(
1390            bits,
1391            NA_REAL.to_bits(),
1392            "sum with NA should return NA_real_"
1393        );
1394    }
1395
1396    /// sum with na_rm=true and NA_real_ present should skip the NA and sum the rest.
1397    #[test]
1398    fn vec_f64_sum_na_rm_skips_na() {
1399        let v: Vec<f64> = vec![1.0, NA_REAL, 3.0];
1400        let result = AltRealData::sum(&v, true);
1401        assert_eq!(result, Some(4.0));
1402    }
1403
1404    /// sum with na_rm=false and regular NaN present should return Some(NaN) — NOT NA.
1405    #[test]
1406    fn vec_f64_sum_nan_propagates_as_nan_not_na() {
1407        let v: Vec<f64> = vec![1.0, f64::NAN, 3.0];
1408        let result = AltRealData::sum(&v, false);
1409        assert!(result.is_some());
1410        let val = result.unwrap();
1411        assert!(val.is_nan(), "sum with NaN (not NA) should return NaN");
1412        assert_ne!(
1413            val.to_bits(),
1414            NA_REAL.to_bits(),
1415            "sum with regular NaN should NOT return NA_real_"
1416        );
1417    }
1418
1419    /// sum with na_rm=true and regular NaN present should skip the NaN.
1420    #[test]
1421    fn vec_f64_sum_nan_rm_skips_nan() {
1422        let v: Vec<f64> = vec![1.0, f64::NAN, 3.0];
1423        let result = AltRealData::sum(&v, true);
1424        assert_eq!(result, Some(4.0));
1425    }
1426
1427    /// A computed NA propagates as NA (not NaN) and is skipped by na_rm.
1428    #[test]
1429    fn vec_f64_sum_computed_na() {
1430        let v: Vec<f64> = vec![1.0, COMPUTED_NA, 3.0];
1431        let na = AltRealData::sum(&v, false).expect("sum is always computed");
1432        assert!(na.is_na(), "{:#x}", na.to_bits());
1433        assert_eq!(AltRealData::sum(&v, true), Some(4.0));
1434    }
1435
1436    /// NA wins over NaN whatever the order, as in R's `rmin` / `rmax`.
1437    #[test]
1438    fn vec_f64_min_max_na_trumps_nan() {
1439        for v in [
1440            vec![f64::NAN, 1.0, COMPUTED_NA],
1441            vec![COMPUTED_NA, f64::NAN, 1.0],
1442            vec![1.0, f64::NAN, NA_REAL],
1443        ] {
1444            for extreme in [
1445                AltRealData::min(&v, false),
1446                AltRealData::max(&v, false),
1447                AltRealData::sum(&v, false),
1448            ] {
1449                let value = extreme.expect("missing values give a result");
1450                assert!(value.is_na(), "{v:?} gave {:#x}", value.to_bits());
1451            }
1452            assert_eq!(AltRealData::min(&v, true), Some(1.0));
1453            assert_eq!(AltRealData::max(&v, true), Some(1.0));
1454        }
1455        let nan_only = vec![3.0, f64::NAN, 1.0];
1456        let min = AltRealData::min(&nan_only, false).expect("NaN gives a result");
1457        assert!(min.is_nan() && !min.is_na());
1458        assert_eq!(AltRealData::min(&nan_only, true), Some(1.0));
1459        assert_eq!(AltRealData::max(&nan_only, true), Some(3.0));
1460        let all_missing = vec![NA_REAL, f64::NAN];
1461        assert_eq!(AltRealData::min(&all_missing, true), None);
1462    }
1463
1464    // endregion
1465
1466    // region: Box<[f64]> no_na — NA vs NaN
1467
1468    #[test]
1469    fn box_f64_no_na_with_regular_nan_is_false() {
1470        let v: Box<[f64]> = vec![1.0, f64::NAN, 3.0].into_boxed_slice();
1471        assert_eq!(AltRealData::no_na(&v), Some(false));
1472    }
1473
1474    #[test]
1475    fn box_f64_no_na_with_na_real_is_false() {
1476        let v: Box<[f64]> = vec![1.0, NA_REAL, 3.0].into_boxed_slice();
1477        assert_eq!(AltRealData::no_na(&v), Some(false));
1478    }
1479
1480    // endregion
1481
1482    // region: &[f64] no_na — NA vs NaN
1483
1484    #[test]
1485    fn slice_f64_no_na_with_regular_nan_is_false() {
1486        let data: &[f64] = &[1.0, f64::NAN, 3.0];
1487        assert_eq!(AltRealData::no_na(&data), Some(false));
1488    }
1489
1490    #[test]
1491    fn slice_f64_no_na_with_na_real_is_false() {
1492        let data: &[f64] = &[1.0, NA_REAL, 3.0];
1493        assert_eq!(AltRealData::no_na(&data), Some(false));
1494    }
1495
1496    // endregion
1497
1498    // region: [f64; N] no_na — NA vs NaN
1499
1500    #[test]
1501    fn array_f64_no_na_with_regular_nan_is_false() {
1502        let arr: [f64; 3] = [1.0, f64::NAN, 3.0];
1503        assert_eq!(AltRealData::no_na(&arr), Some(false));
1504    }
1505
1506    #[test]
1507    fn array_f64_no_na_with_na_real_is_false() {
1508        let arr: [f64; 3] = [1.0, NA_REAL, 3.0];
1509        assert_eq!(AltRealData::no_na(&arr), Some(false));
1510    }
1511
1512    // endregion
1513
1514    // region: Cow<'static, [f64]> no_na — NA vs NaN
1515
1516    #[test]
1517    fn cow_f64_no_na_with_regular_nan_is_false() {
1518        let v: Cow<'static, [f64]> = Cow::Owned(vec![1.0, f64::NAN, 3.0]);
1519        assert_eq!(AltRealData::no_na(&v), Some(false));
1520    }
1521
1522    #[test]
1523    fn cow_f64_no_na_with_na_real_is_false() {
1524        let v: Cow<'static, [f64]> = Cow::Owned(vec![1.0, NA_REAL, 3.0]);
1525        assert_eq!(AltRealData::no_na(&v), Some(false));
1526    }
1527
1528    // endregion
1529}