Skip to main content

miniextendr_api/from_r/
references.rs

1//! Reference conversions (borrowed views into R vectors).
2//!
3//! Provides zero-copy access to R vector data via `'static` references.
4//! The lifetime is technically a lie — the data lives as long as R doesn't GC it.
5//!
6//! Covers: `&T`, `&mut T`, `Option<&T>`, `Vec<&T>`, `Vec<&[T]>`, and
7//! mutable variants for all `RNativeType` types.
8//!
9//! # Tradeoff
10//!
11//! Prefer borrowed `&[T]` over owned `Vec<T>` when you only need read access —
12//! this is the fast path (no allocation, no copy). Reach for `&mut [T]` only
13//! when you genuinely need to mutate R-owned data in place; the R caller will
14//! observe those writes (ALTREP MAYBE_REFERENCED rules still apply). Failure
15//! mode: taking `&mut [T]` from a shared SEXP that R has handed to multiple
16//! callers writes through that aliased buffer.
17//!
18//! For NA-aware reads use [`crate::from_r::na_vectors`] (`Vec<Option<T>>`) —
19//! borrowed slices cannot express NA without losing the sentinel encoding.
20//! Outbound: borrowed slices have no `IntoR` impl (R owns return-value
21//! storage); see [`crate::into_r`] for the owned equivalents.
22
23use crate::from_r::{SexpError, SexpLengthError, SexpTypeError, TryFromSexp, map_vecsxp_with};
24use crate::{RLogical, RNativeType, SEXP, SEXPTYPE, SexpExt};
25
26macro_rules! impl_ref_conversions_for {
27    ($t:ty) => {
28        impl TryFromSexp for &'static $t {
29            type Error = SexpError;
30
31            #[inline]
32            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
33                let actual = sexp.type_of();
34                if actual != <$t as RNativeType>::SEXP_TYPE {
35                    return Err(SexpTypeError {
36                        expected: <$t as RNativeType>::SEXP_TYPE,
37                        actual,
38                    }
39                    .into());
40                }
41                let len = sexp.len();
42                if len != 1 {
43                    return Err(SexpLengthError {
44                        expected: 1,
45                        actual: len,
46                    }
47                    .into());
48                }
49                unsafe { sexp.as_slice::<$t>() }
50                    .first()
51                    .ok_or_else(|| SexpLengthError { expected: 1, actual: 0 }.into())
52            }
53
54            #[inline]
55            unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
56                let actual = sexp.type_of();
57                if actual != <$t as RNativeType>::SEXP_TYPE {
58                    return Err(SexpTypeError {
59                        expected: <$t as RNativeType>::SEXP_TYPE,
60                        actual,
61                    }
62                    .into());
63                }
64                let len = unsafe { sexp.len_unchecked() };
65                if len != 1 {
66                    return Err(SexpLengthError {
67                        expected: 1,
68                        actual: len,
69                    }
70                    .into());
71                }
72                unsafe { sexp.as_slice_unchecked::<$t>() }
73                    .first()
74                    .ok_or_else(|| SexpLengthError { expected: 1, actual: 0 }.into())
75            }
76        }
77
78        /// # Safety note (aliasing)
79        ///
80        /// This impl can produce aliased `&mut` references if the same R object
81        /// is passed to multiple mutable parameters. The caller (generated wrapper)
82        /// is responsible for ensuring no two `&mut` borrows alias the same SEXP.
83        impl TryFromSexp for &'static mut $t {
84            type Error = SexpError;
85
86            #[inline]
87            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
88                let actual = sexp.type_of();
89                if actual != <$t as RNativeType>::SEXP_TYPE {
90                    return Err(SexpTypeError {
91                        expected: <$t as RNativeType>::SEXP_TYPE,
92                        actual,
93                    }
94                    .into());
95                }
96                let len = sexp.len();
97                if len != 1 {
98                    return Err(SexpLengthError {
99                        expected: 1,
100                        actual: len,
101                    }
102                    .into());
103                }
104                let ptr = unsafe { <$t as RNativeType>::dataptr_mut(sexp) };
105                Ok(unsafe { &mut *ptr })
106            }
107
108            #[inline]
109            unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
110                let actual = sexp.type_of();
111                if actual != <$t as RNativeType>::SEXP_TYPE {
112                    return Err(SexpTypeError {
113                        expected: <$t as RNativeType>::SEXP_TYPE,
114                        actual,
115                    }
116                    .into());
117                }
118                let len = unsafe { sexp.len_unchecked() };
119                if len != 1 {
120                    return Err(SexpLengthError {
121                        expected: 1,
122                        actual: len,
123                    }
124                    .into());
125                }
126                let ptr = unsafe { <$t as RNativeType>::dataptr_mut(sexp) };
127                Ok(unsafe { &mut *ptr })
128            }
129        }
130
131        impl TryFromSexp for Option<&'static $t> {
132            type Error = SexpError;
133
134            #[inline]
135            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
136                if sexp.type_of() == SEXPTYPE::NILSXP {
137                    return Ok(None);
138                }
139                let value: &'static $t = TryFromSexp::try_from_sexp(sexp)?;
140                Ok(Some(value))
141            }
142
143            #[inline]
144            unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
145                if sexp.type_of() == SEXPTYPE::NILSXP {
146                    return Ok(None);
147                }
148                let value: &'static $t = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
149                Ok(Some(value))
150            }
151        }
152
153        impl TryFromSexp for Option<&'static mut $t> {
154            type Error = SexpError;
155
156            #[inline]
157            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
158                if sexp.type_of() == SEXPTYPE::NILSXP {
159                    return Ok(None);
160                }
161                let value: &'static mut $t = TryFromSexp::try_from_sexp(sexp)?;
162                Ok(Some(value))
163            }
164
165            #[inline]
166            unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
167                if sexp.type_of() == SEXPTYPE::NILSXP {
168                    return Ok(None);
169                }
170                let value: &'static mut $t =
171                    unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
172                Ok(Some(value))
173            }
174        }
175
176        // Option<&[T]> and Option<&mut [T]> impls removed - now use blanket impls
177
178        impl TryFromSexp for Vec<&'static $t> {
179            type Error = SexpError;
180
181            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
182                map_vecsxp_with(sexp, |_i, elem| TryFromSexp::try_from_sexp(elem))
183            }
184        }
185
186        impl TryFromSexp for Vec<Option<&'static $t>> {
187            type Error = SexpError;
188
189            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
190                map_vecsxp_with(sexp, |_i, elem| {
191                    if elem.type_of() == SEXPTYPE::NILSXP {
192                        Ok(None)
193                    } else {
194                        let value: &'static $t = TryFromSexp::try_from_sexp(elem)?;
195                        Ok(Some(value))
196                    }
197                })
198            }
199        }
200
201        impl TryFromSexp for Vec<&'static mut $t> {
202            type Error = SexpError;
203
204            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
205                let mut ptrs: Vec<*mut $t> = Vec::new();
206                map_vecsxp_with(sexp, |_i, elem| {
207                    let value: &'static mut $t = TryFromSexp::try_from_sexp(elem)?;
208                    let ptr = std::ptr::from_mut(value);
209                    if ptrs.iter().any(|&p| p == ptr) {
210                        return Err(SexpError::InvalidValue(
211                            "list contains duplicate elements; cannot create multiple mutable references"
212                                .to_string(),
213                        ));
214                    }
215                    ptrs.push(ptr);
216                    Ok(value)
217                })
218            }
219        }
220
221        impl TryFromSexp for Vec<Option<&'static mut $t>> {
222            type Error = SexpError;
223
224            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
225                let mut ptrs: Vec<*mut $t> = Vec::new();
226                map_vecsxp_with(sexp, |_i, elem| {
227                    if elem.type_of() == SEXPTYPE::NILSXP {
228                        return Ok(None);
229                    }
230                    let value: &'static mut $t = TryFromSexp::try_from_sexp(elem)?;
231                    let ptr = std::ptr::from_mut(value);
232                    if ptrs.iter().any(|&p| p == ptr) {
233                        return Err(SexpError::InvalidValue(
234                            "list contains duplicate elements; cannot create multiple mutable references"
235                                .to_string(),
236                        ));
237                    }
238                    ptrs.push(ptr);
239                    Ok(Some(value))
240                })
241            }
242        }
243
244        impl TryFromSexp for Vec<&'static [$t]> {
245            type Error = SexpError;
246
247            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
248                map_vecsxp_with(sexp, |_i, elem| {
249                    TryFromSexp::try_from_sexp(elem).map_err(SexpError::from)
250                })
251            }
252        }
253
254        impl TryFromSexp for Vec<Option<&'static [$t]>> {
255            type Error = SexpError;
256
257            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
258                map_vecsxp_with(sexp, |_i, elem| {
259                    if elem.type_of() == SEXPTYPE::NILSXP {
260                        Ok(None)
261                    } else {
262                        let slice: &'static [$t] =
263                            TryFromSexp::try_from_sexp(elem).map_err(SexpError::from)?;
264                        Ok(Some(slice))
265                    }
266                })
267            }
268        }
269
270        impl TryFromSexp for Vec<&'static mut [$t]> {
271            type Error = SexpError;
272
273            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
274                let mut ptrs: Vec<*mut $t> = Vec::new();
275                map_vecsxp_with(sexp, |_i, elem| {
276                    let slice: &'static mut [$t] =
277                        TryFromSexp::try_from_sexp(elem).map_err(SexpError::from)?;
278                    if !slice.is_empty() {
279                        let ptr = slice.as_mut_ptr();
280                        if ptrs.iter().any(|&p| p == ptr) {
281                            return Err(SexpError::InvalidValue(
282                                "list contains duplicate elements; cannot create multiple mutable references"
283                                    .to_string(),
284                            ));
285                        }
286                        ptrs.push(ptr);
287                    }
288                    Ok(slice)
289                })
290            }
291        }
292
293        impl TryFromSexp for Vec<Option<&'static mut [$t]>> {
294            type Error = SexpError;
295
296            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
297                let mut ptrs: Vec<*mut $t> = Vec::new();
298                map_vecsxp_with(sexp, |_i, elem| {
299                    if elem.type_of() == SEXPTYPE::NILSXP {
300                        return Ok(None);
301                    }
302                    let slice: &'static mut [$t] =
303                        TryFromSexp::try_from_sexp(elem).map_err(SexpError::from)?;
304                    if !slice.is_empty() {
305                        let ptr = slice.as_mut_ptr();
306                        if ptrs.iter().any(|&p| p == ptr) {
307                            return Err(SexpError::InvalidValue(
308                                "list contains duplicate elements; cannot create multiple mutable references"
309                                    .to_string(),
310                            ));
311                        }
312                        ptrs.push(ptr);
313                    }
314                    Ok(Some(slice))
315                })
316            }
317        }
318    };
319}
320
321impl_ref_conversions_for!(i32);
322impl_ref_conversions_for!(f64);
323impl_ref_conversions_for!(u8);
324impl_ref_conversions_for!(RLogical);
325impl_ref_conversions_for!(crate::Rcomplex);
326// endregion