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