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
9use crate::ffi::{RLogical, RNativeType, SEXP, SEXPTYPE, SexpExt};
10use crate::from_r::{SexpError, SexpLengthError, SexpTypeError, TryFromSexp};
11
12macro_rules! impl_ref_conversions_for {
13    ($t:ty) => {
14        impl TryFromSexp for &'static $t {
15            type Error = SexpError;
16
17            #[inline]
18            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
19                let actual = sexp.type_of();
20                if actual != <$t as RNativeType>::SEXP_TYPE {
21                    return Err(SexpTypeError {
22                        expected: <$t as RNativeType>::SEXP_TYPE,
23                        actual,
24                    }
25                    .into());
26                }
27                let len = sexp.len();
28                if len != 1 {
29                    return Err(SexpLengthError {
30                        expected: 1,
31                        actual: len,
32                    }
33                    .into());
34                }
35                unsafe { sexp.as_slice::<$t>() }
36                    .first()
37                    .ok_or_else(|| SexpLengthError { expected: 1, actual: 0 }.into())
38            }
39
40            #[inline]
41            unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
42                let actual = sexp.type_of();
43                if actual != <$t as RNativeType>::SEXP_TYPE {
44                    return Err(SexpTypeError {
45                        expected: <$t as RNativeType>::SEXP_TYPE,
46                        actual,
47                    }
48                    .into());
49                }
50                let len = unsafe { sexp.len_unchecked() };
51                if len != 1 {
52                    return Err(SexpLengthError {
53                        expected: 1,
54                        actual: len,
55                    }
56                    .into());
57                }
58                unsafe { sexp.as_slice_unchecked::<$t>() }
59                    .first()
60                    .ok_or_else(|| SexpLengthError { expected: 1, actual: 0 }.into())
61            }
62        }
63
64        /// # Safety note (aliasing)
65        ///
66        /// This impl can produce aliased `&mut` references if the same R object
67        /// is passed to multiple mutable parameters. The caller (generated wrapper)
68        /// is responsible for ensuring no two `&mut` borrows alias the same SEXP.
69        impl TryFromSexp for &'static mut $t {
70            type Error = SexpError;
71
72            #[inline]
73            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
74                let actual = sexp.type_of();
75                if actual != <$t as RNativeType>::SEXP_TYPE {
76                    return Err(SexpTypeError {
77                        expected: <$t as RNativeType>::SEXP_TYPE,
78                        actual,
79                    }
80                    .into());
81                }
82                let len = sexp.len();
83                if len != 1 {
84                    return Err(SexpLengthError {
85                        expected: 1,
86                        actual: len,
87                    }
88                    .into());
89                }
90                let ptr = unsafe { <$t as RNativeType>::dataptr_mut(sexp) };
91                Ok(unsafe { &mut *ptr })
92            }
93
94            #[inline]
95            unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
96                let actual = sexp.type_of();
97                if actual != <$t as RNativeType>::SEXP_TYPE {
98                    return Err(SexpTypeError {
99                        expected: <$t as RNativeType>::SEXP_TYPE,
100                        actual,
101                    }
102                    .into());
103                }
104                let len = unsafe { sexp.len_unchecked() };
105                if len != 1 {
106                    return Err(SexpLengthError {
107                        expected: 1,
108                        actual: len,
109                    }
110                    .into());
111                }
112                let ptr = unsafe { <$t as RNativeType>::dataptr_mut(sexp) };
113                Ok(unsafe { &mut *ptr })
114            }
115        }
116
117        impl TryFromSexp for Option<&'static $t> {
118            type Error = SexpError;
119
120            #[inline]
121            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
122                if sexp.type_of() == SEXPTYPE::NILSXP {
123                    return Ok(None);
124                }
125                let value: &'static $t = TryFromSexp::try_from_sexp(sexp)?;
126                Ok(Some(value))
127            }
128
129            #[inline]
130            unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
131                if sexp.type_of() == SEXPTYPE::NILSXP {
132                    return Ok(None);
133                }
134                let value: &'static $t = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
135                Ok(Some(value))
136            }
137        }
138
139        impl TryFromSexp for Option<&'static mut $t> {
140            type Error = SexpError;
141
142            #[inline]
143            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
144                if sexp.type_of() == SEXPTYPE::NILSXP {
145                    return Ok(None);
146                }
147                let value: &'static mut $t = TryFromSexp::try_from_sexp(sexp)?;
148                Ok(Some(value))
149            }
150
151            #[inline]
152            unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
153                if sexp.type_of() == SEXPTYPE::NILSXP {
154                    return Ok(None);
155                }
156                let value: &'static mut $t =
157                    unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
158                Ok(Some(value))
159            }
160        }
161
162        // Option<&[T]> and Option<&mut [T]> impls removed - now use blanket impls
163
164        impl TryFromSexp for Vec<&'static $t> {
165            type Error = SexpError;
166
167            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
168                let actual = sexp.type_of();
169                if actual != SEXPTYPE::VECSXP {
170                    return Err(SexpTypeError {
171                        expected: SEXPTYPE::VECSXP,
172                        actual,
173                    }
174                    .into());
175                }
176
177                let len = sexp.len();
178                let mut out = Vec::with_capacity(len);
179
180                for i in 0..len {
181                    let elem = sexp.vector_elt(i as crate::ffi::R_xlen_t);
182                    let value: &'static $t = TryFromSexp::try_from_sexp(elem)?;
183                    out.push(value);
184                }
185
186                Ok(out)
187            }
188        }
189
190        impl TryFromSexp for Vec<Option<&'static $t>> {
191            type Error = SexpError;
192
193            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
194                let actual = sexp.type_of();
195                if actual != SEXPTYPE::VECSXP {
196                    return Err(SexpTypeError {
197                        expected: SEXPTYPE::VECSXP,
198                        actual,
199                    }
200                    .into());
201                }
202
203                let len = sexp.len();
204                let mut out = Vec::with_capacity(len);
205
206                for i in 0..len {
207                    let elem = sexp.vector_elt(i as crate::ffi::R_xlen_t);
208                    if elem.type_of() == SEXPTYPE::NILSXP {
209                        out.push(None);
210                    } else {
211                        let value: &'static $t = TryFromSexp::try_from_sexp(elem)?;
212                        out.push(Some(value));
213                    }
214                }
215
216                Ok(out)
217            }
218        }
219
220        impl TryFromSexp for Vec<&'static mut $t> {
221            type Error = SexpError;
222
223            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
224                let actual = sexp.type_of();
225                if actual != SEXPTYPE::VECSXP {
226                    return Err(SexpTypeError {
227                        expected: SEXPTYPE::VECSXP,
228                        actual,
229                    }
230                    .into());
231                }
232
233                let len = sexp.len();
234                let mut out = Vec::with_capacity(len);
235                let mut ptrs: Vec<*mut $t> = Vec::new();
236
237                for i in 0..len {
238                    let elem = sexp.vector_elt(i as crate::ffi::R_xlen_t);
239                    let value: &'static mut $t = TryFromSexp::try_from_sexp(elem)?;
240                    let ptr = std::ptr::from_mut(value);
241                    if ptrs.iter().any(|&p| p == ptr) {
242                        return Err(SexpError::InvalidValue(
243                            "list contains duplicate elements; cannot create multiple mutable references"
244                                .to_string(),
245                        ));
246                    }
247                    ptrs.push(ptr);
248                    out.push(value);
249                }
250
251                Ok(out)
252            }
253        }
254
255        impl TryFromSexp for Vec<Option<&'static mut $t>> {
256            type Error = SexpError;
257
258            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
259                let actual = sexp.type_of();
260                if actual != SEXPTYPE::VECSXP {
261                    return Err(SexpTypeError {
262                        expected: SEXPTYPE::VECSXP,
263                        actual,
264                    }
265                    .into());
266                }
267
268                let len = sexp.len();
269                let mut out = Vec::with_capacity(len);
270                let mut ptrs: Vec<*mut $t> = Vec::new();
271
272                for i in 0..len {
273                    let elem = sexp.vector_elt(i as crate::ffi::R_xlen_t);
274                    if elem.type_of() == SEXPTYPE::NILSXP {
275                        out.push(None);
276                        continue;
277                    }
278                    let value: &'static mut $t = TryFromSexp::try_from_sexp(elem)?;
279                    let ptr = std::ptr::from_mut(value);
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                    out.push(Some(value));
288                }
289
290                Ok(out)
291            }
292        }
293
294        impl TryFromSexp for Vec<&'static [$t]> {
295            type Error = SexpError;
296
297            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
298                let actual = sexp.type_of();
299                if actual != SEXPTYPE::VECSXP {
300                    return Err(SexpTypeError {
301                        expected: SEXPTYPE::VECSXP,
302                        actual,
303                    }
304                    .into());
305                }
306
307                let len = sexp.len();
308                let mut out = Vec::with_capacity(len);
309
310                for i in 0..len {
311                    let elem = sexp.vector_elt(i as crate::ffi::R_xlen_t);
312                    let slice: &'static [$t] =
313                        TryFromSexp::try_from_sexp(elem).map_err(SexpError::from)?;
314                    out.push(slice);
315                }
316
317                Ok(out)
318            }
319        }
320
321        impl TryFromSexp for Vec<Option<&'static [$t]>> {
322            type Error = SexpError;
323
324            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
325                let actual = sexp.type_of();
326                if actual != SEXPTYPE::VECSXP {
327                    return Err(SexpTypeError {
328                        expected: SEXPTYPE::VECSXP,
329                        actual,
330                    }
331                    .into());
332                }
333
334                let len = sexp.len();
335                let mut out = Vec::with_capacity(len);
336
337                for i in 0..len {
338                    let elem = sexp.vector_elt(i as crate::ffi::R_xlen_t);
339                    if elem.type_of() == SEXPTYPE::NILSXP {
340                        out.push(None);
341                    } else {
342                        let slice: &'static [$t] =
343                            TryFromSexp::try_from_sexp(elem).map_err(SexpError::from)?;
344                        out.push(Some(slice));
345                    }
346                }
347
348                Ok(out)
349            }
350        }
351
352        impl TryFromSexp for Vec<&'static mut [$t]> {
353            type Error = SexpError;
354
355            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
356                let actual = sexp.type_of();
357                if actual != SEXPTYPE::VECSXP {
358                    return Err(SexpTypeError {
359                        expected: SEXPTYPE::VECSXP,
360                        actual,
361                    }
362                    .into());
363                }
364
365                let len = sexp.len();
366                let mut out = Vec::with_capacity(len);
367                let mut ptrs: Vec<*mut $t> = Vec::new();
368
369                for i in 0..len {
370                    let elem = sexp.vector_elt(i as crate::ffi::R_xlen_t);
371                    let slice: &'static mut [$t] =
372                        TryFromSexp::try_from_sexp(elem).map_err(SexpError::from)?;
373                    if !slice.is_empty() {
374                        let ptr = slice.as_mut_ptr();
375                        if ptrs.iter().any(|&p| p == ptr) {
376                            return Err(SexpError::InvalidValue(
377                                "list contains duplicate elements; cannot create multiple mutable references"
378                                    .to_string(),
379                            ));
380                        }
381                        ptrs.push(ptr);
382                    }
383                    out.push(slice);
384                }
385
386                Ok(out)
387            }
388        }
389
390        impl TryFromSexp for Vec<Option<&'static mut [$t]>> {
391            type Error = SexpError;
392
393            fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
394                let actual = sexp.type_of();
395                if actual != SEXPTYPE::VECSXP {
396                    return Err(SexpTypeError {
397                        expected: SEXPTYPE::VECSXP,
398                        actual,
399                    }
400                    .into());
401                }
402
403                let len = sexp.len();
404                let mut out = Vec::with_capacity(len);
405                let mut ptrs: Vec<*mut $t> = Vec::new();
406
407                for i in 0..len {
408                    let elem = sexp.vector_elt(i as crate::ffi::R_xlen_t);
409                    if elem.type_of() == SEXPTYPE::NILSXP {
410                        out.push(None);
411                        continue;
412                    }
413                    let slice: &'static mut [$t] =
414                        TryFromSexp::try_from_sexp(elem).map_err(SexpError::from)?;
415                    if !slice.is_empty() {
416                        let ptr = slice.as_mut_ptr();
417                        if ptrs.iter().any(|&p| p == ptr) {
418                            return Err(SexpError::InvalidValue(
419                                "list contains duplicate elements; cannot create multiple mutable references"
420                                    .to_string(),
421                            ));
422                        }
423                        ptrs.push(ptr);
424                    }
425                    out.push(Some(slice));
426                }
427
428                Ok(out)
429            }
430        }
431    };
432}
433
434impl_ref_conversions_for!(i32);
435impl_ref_conversions_for!(f64);
436impl_ref_conversions_for!(u8);
437impl_ref_conversions_for!(RLogical);
438impl_ref_conversions_for!(crate::ffi::Rcomplex);
439// endregion