miniextendr_api/from_r/
na_vectors.rs1use crate::coerce::TryCoerce;
9use crate::ffi::{RLogical, Rboolean, SEXP, SEXPTYPE, SexpExt};
10use crate::from_r::{
11 SexpError, SexpNaError, SexpTypeError, TryFromSexp, charsxp_to_str, coerce_value, is_na_real,
12 r_slice,
13};
14
15macro_rules! impl_vec_option_try_from_sexp {
17 ($t:ty, $sexptype:ident, $dataptr:ident, $is_na:expr) => {
18 impl TryFromSexp for Vec<Option<$t>> {
19 type Error = SexpError;
20
21 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
22 let actual = sexp.type_of();
23 if actual != SEXPTYPE::$sexptype {
24 return Err(SexpTypeError {
25 expected: SEXPTYPE::$sexptype,
26 actual,
27 }
28 .into());
29 }
30
31 let len = sexp.len();
32 let ptr = unsafe { crate::ffi::$dataptr(sexp) };
33 let slice = unsafe { r_slice(ptr, len) };
34
35 Ok(slice
36 .iter()
37 .map(|&v| if $is_na(v) { None } else { Some(v) })
38 .collect())
39 }
40 }
41 };
42}
43
44impl_vec_option_try_from_sexp!(f64, REALSXP, REAL, is_na_real);
45impl_vec_option_try_from_sexp!(i32, INTSXP, INTEGER, |v: i32| v == i32::MIN);
46
47macro_rules! impl_boxed_slice_option_try_from_sexp {
49 ($t:ty, $sexptype:ident, $dataptr:ident, $is_na:expr) => {
50 impl TryFromSexp for Box<[Option<$t>]> {
51 type Error = SexpError;
52
53 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
54 let actual = sexp.type_of();
55 if actual != SEXPTYPE::$sexptype {
56 return Err(SexpTypeError {
57 expected: SEXPTYPE::$sexptype,
58 actual,
59 }
60 .into());
61 }
62
63 let len = sexp.len();
64 let ptr = unsafe { crate::ffi::$dataptr(sexp) };
65 let slice = unsafe { r_slice(ptr, len) };
66
67 Ok(slice
68 .iter()
69 .map(|&v| if $is_na(v) { None } else { Some(v) })
70 .collect())
71 }
72 }
73 };
74}
75
76impl_boxed_slice_option_try_from_sexp!(f64, REALSXP, REAL, is_na_real);
77impl_boxed_slice_option_try_from_sexp!(i32, INTSXP, INTEGER, |v: i32| v == i32::MIN);
78
79impl TryFromSexp for Vec<Option<bool>> {
81 type Error = SexpError;
82
83 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
84 let actual = sexp.type_of();
85 if actual != SEXPTYPE::LGLSXP {
86 return Err(SexpTypeError {
87 expected: SEXPTYPE::LGLSXP,
88 actual,
89 }
90 .into());
91 }
92
93 let slice: &[RLogical] = unsafe { sexp.as_slice() };
94
95 Ok(slice.iter().map(|v| v.to_option_bool()).collect())
96 }
97
98 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
99 let actual = sexp.type_of();
100 if actual != SEXPTYPE::LGLSXP {
101 return Err(SexpTypeError {
102 expected: SEXPTYPE::LGLSXP,
103 actual,
104 }
105 .into());
106 }
107
108 let slice: &[RLogical] = unsafe { sexp.as_slice_unchecked() };
109
110 Ok(slice.iter().map(|v| v.to_option_bool()).collect())
111 }
112}
113
114impl TryFromSexp for Box<[Option<bool>]> {
116 type Error = SexpError;
117
118 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
119 let vec: Vec<Option<bool>> = TryFromSexp::try_from_sexp(sexp)?;
120 Ok(vec.into_boxed_slice())
121 }
122}
123
124impl TryFromSexp for Vec<Rboolean> {
126 type Error = SexpError;
127
128 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
129 let actual = sexp.type_of();
130 if actual != SEXPTYPE::LGLSXP {
131 return Err(SexpTypeError {
132 expected: SEXPTYPE::LGLSXP,
133 actual,
134 }
135 .into());
136 }
137
138 let slice: &[RLogical] = unsafe { sexp.as_slice() };
139
140 slice
141 .iter()
142 .map(|v| match v.to_option_bool() {
143 Some(false) => Ok(Rboolean::FALSE),
144 Some(true) => Ok(Rboolean::TRUE),
145 None => Err(SexpNaError {
146 sexp_type: SEXPTYPE::LGLSXP,
147 }
148 .into()),
149 })
150 .collect()
151 }
152}
153
154impl TryFromSexp for Vec<Option<Rboolean>> {
156 type Error = SexpError;
157
158 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
159 let actual = sexp.type_of();
160 if actual != SEXPTYPE::LGLSXP {
161 return Err(SexpTypeError {
162 expected: SEXPTYPE::LGLSXP,
163 actual,
164 }
165 .into());
166 }
167
168 let slice: &[RLogical] = unsafe { sexp.as_slice() };
169
170 Ok(slice
171 .iter()
172 .map(|v| match v.to_option_bool() {
173 Some(false) => Some(Rboolean::FALSE),
174 Some(true) => Some(Rboolean::TRUE),
175 None => None,
176 })
177 .collect())
178 }
179}
180
181impl TryFromSexp for Vec<crate::altrep_data::Logical> {
187 type Error = SexpError;
188
189 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
190 let actual = sexp.type_of();
191 if actual != SEXPTYPE::LGLSXP {
192 return Err(SexpTypeError {
193 expected: SEXPTYPE::LGLSXP,
194 actual,
195 }
196 .into());
197 }
198
199 let slice: &[RLogical] = unsafe { sexp.as_slice() };
200
201 Ok(slice
202 .iter()
203 .map(|&v| crate::altrep_data::Logical::from(v))
204 .collect())
205 }
206}
207
208impl TryFromSexp for Vec<Option<RLogical>> {
210 type Error = SexpError;
211
212 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
213 let actual = sexp.type_of();
214 if actual != SEXPTYPE::LGLSXP {
215 return Err(SexpTypeError {
216 expected: SEXPTYPE::LGLSXP,
217 actual,
218 }
219 .into());
220 }
221
222 let slice: &[RLogical] = unsafe { sexp.as_slice() };
223
224 Ok(slice
225 .iter()
226 .map(|v| if v.is_na() { None } else { Some(*v) })
227 .collect())
228 }
229}
230
231impl TryFromSexp for Vec<Option<String>> {
235 type Error = SexpError;
236
237 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
238 let actual = sexp.type_of();
239 if actual != SEXPTYPE::STRSXP {
240 return Err(SexpTypeError {
241 expected: SEXPTYPE::STRSXP,
242 actual,
243 }
244 .into());
245 }
246
247 let len = sexp.len();
248 let mut result = Vec::with_capacity(len);
249
250 for i in 0..len {
251 let charsxp = sexp.string_elt(i as crate::ffi::R_xlen_t);
252
253 if charsxp == SEXP::na_string() {
254 result.push(None);
255 } else {
256 result.push(Some(unsafe { charsxp_to_str(charsxp) }.to_owned()));
257 }
258 }
259
260 Ok(result)
261 }
262}
263
264impl TryFromSexp for Box<[Option<String>]> {
266 type Error = SexpError;
267
268 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
269 let vec: Vec<Option<String>> = TryFromSexp::try_from_sexp(sexp)?;
270 Ok(vec.into_boxed_slice())
271 }
272}
273
274impl TryFromSexp for Vec<Option<u8>> {
276 type Error = SexpError;
277
278 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
279 let actual = sexp.type_of();
280 if actual != SEXPTYPE::RAWSXP {
281 return Err(SexpTypeError {
282 expected: SEXPTYPE::RAWSXP,
283 actual,
284 }
285 .into());
286 }
287
288 let slice: &[u8] = unsafe { sexp.as_slice() };
289
290 Ok(slice.iter().map(|&v| Some(v)).collect())
291 }
292}
293
294#[inline]
295fn try_from_sexp_numeric_option_vec<T>(sexp: SEXP) -> Result<Vec<Option<T>>, SexpError>
296where
297 i32: TryCoerce<T>,
298 f64: TryCoerce<T>,
299 u8: TryCoerce<T>,
300 <i32 as TryCoerce<T>>::Error: std::fmt::Debug,
301 <f64 as TryCoerce<T>>::Error: std::fmt::Debug,
302 <u8 as TryCoerce<T>>::Error: std::fmt::Debug,
303{
304 let actual = sexp.type_of();
305 match actual {
306 SEXPTYPE::INTSXP => {
307 let slice: &[i32] = unsafe { sexp.as_slice() };
308 slice
309 .iter()
310 .map(|&v| {
311 if v == crate::altrep_traits::NA_INTEGER {
312 Ok(None)
313 } else {
314 coerce_value(v).map(Some)
315 }
316 })
317 .collect()
318 }
319 SEXPTYPE::REALSXP => {
320 let slice: &[f64] = unsafe { sexp.as_slice() };
321 slice
322 .iter()
323 .map(|&v| {
324 if is_na_real(v) {
325 Ok(None)
326 } else {
327 coerce_value(v).map(Some)
328 }
329 })
330 .collect()
331 }
332 SEXPTYPE::RAWSXP => {
333 let slice: &[u8] = unsafe { sexp.as_slice() };
334 slice.iter().map(|&v| coerce_value(v).map(Some)).collect()
335 }
336 SEXPTYPE::LGLSXP => {
337 let slice: &[RLogical] = unsafe { sexp.as_slice() };
338 slice
339 .iter()
340 .map(|&v| {
341 if v.is_na() {
342 Ok(None)
343 } else {
344 coerce_value(v.to_i32()).map(Some)
345 }
346 })
347 .collect()
348 }
349 _ => Err(SexpError::InvalidValue(format!(
350 "expected integer, numeric, logical, or raw; got {:?}",
351 actual
352 ))),
353 }
354}
355
356macro_rules! impl_vec_option_try_from_sexp_numeric {
357 ($t:ty) => {
358 impl TryFromSexp for Vec<Option<$t>> {
359 type Error = SexpError;
360
361 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
362 try_from_sexp_numeric_option_vec(sexp)
363 }
364
365 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
366 try_from_sexp_numeric_option_vec(sexp)
367 }
368 }
369 };
370}
371
372impl_vec_option_try_from_sexp_numeric!(i8);
373impl_vec_option_try_from_sexp_numeric!(i16);
374impl_vec_option_try_from_sexp_numeric!(u16);
375impl_vec_option_try_from_sexp_numeric!(u32);
376impl_vec_option_try_from_sexp_numeric!(i64);
377impl_vec_option_try_from_sexp_numeric!(u64);
378impl_vec_option_try_from_sexp_numeric!(isize);
379impl_vec_option_try_from_sexp_numeric!(usize);
380impl_vec_option_try_from_sexp_numeric!(f32);
381