1use crate::altrep_traits::NA_INTEGER;
29use crate::coerce::TryCoerce;
30use crate::from_r::{SexpError, SexpNaError, TryFromSexp, is_na_real};
31use crate::{RLogical, SEXP, SEXPTYPE, SexpExt};
32
33#[inline]
39fn lglsxp_na_error() -> SexpError {
40 SexpNaError {
41 sexp_type: SEXPTYPE::LGLSXP,
42 }
43 .into()
44}
45
46#[inline]
47pub(crate) fn coerce_value<R, T>(value: R) -> Result<T, SexpError>
48where
49 R: TryCoerce<T>,
50 <R as TryCoerce<T>>::Error: std::fmt::Debug,
51{
52 value
53 .try_coerce()
54 .map_err(|e| SexpError::InvalidValue(format!("{e:?}")))
55}
56
57#[inline]
58fn try_from_sexp_numeric_scalar<T>(sexp: SEXP) -> Result<T, SexpError>
59where
60 i32: TryCoerce<T>,
61 f64: TryCoerce<T>,
62 u8: TryCoerce<T>,
63 <i32 as TryCoerce<T>>::Error: std::fmt::Debug,
64 <f64 as TryCoerce<T>>::Error: std::fmt::Debug,
65 <u8 as TryCoerce<T>>::Error: std::fmt::Debug,
66{
67 let actual = sexp.type_of();
68 match actual {
69 SEXPTYPE::INTSXP => {
70 let value: i32 = TryFromSexp::try_from_sexp(sexp)?;
71 coerce_value(value)
72 }
73 SEXPTYPE::REALSXP => {
74 let value: f64 = TryFromSexp::try_from_sexp(sexp)?;
75 coerce_value(value)
76 }
77 SEXPTYPE::RAWSXP => {
78 let value: u8 = TryFromSexp::try_from_sexp(sexp)?;
79 coerce_value(value)
80 }
81 SEXPTYPE::LGLSXP => {
82 let value: RLogical = TryFromSexp::try_from_sexp(sexp)?;
83 if value.is_na() {
84 return Err(lglsxp_na_error());
85 }
86 coerce_value(value.to_i32())
87 }
88 _ => Err(SexpError::InvalidValue(format!(
89 "expected integer, numeric, logical, or raw; got {:?}",
90 actual
91 ))),
92 }
93}
94
95#[inline]
96unsafe fn try_from_sexp_numeric_scalar_unchecked<T>(sexp: SEXP) -> Result<T, SexpError>
97where
98 i32: TryCoerce<T>,
99 f64: TryCoerce<T>,
100 u8: TryCoerce<T>,
101 <i32 as TryCoerce<T>>::Error: std::fmt::Debug,
102 <f64 as TryCoerce<T>>::Error: std::fmt::Debug,
103 <u8 as TryCoerce<T>>::Error: std::fmt::Debug,
104{
105 let actual = sexp.type_of();
106 match actual {
107 SEXPTYPE::INTSXP => {
108 let value: i32 = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
109 coerce_value(value)
110 }
111 SEXPTYPE::REALSXP => {
112 let value: f64 = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
113 coerce_value(value)
114 }
115 SEXPTYPE::RAWSXP => {
116 let value: u8 = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
117 coerce_value(value)
118 }
119 SEXPTYPE::LGLSXP => {
120 let value: RLogical = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
121 if value.is_na() {
122 return Err(lglsxp_na_error());
123 }
124 coerce_value(value.to_i32())
125 }
126 _ => Err(SexpError::InvalidValue(format!(
127 "expected integer, numeric, logical, or raw; got {:?}",
128 actual
129 ))),
130 }
131}
132
133#[inline]
134fn try_from_sexp_numeric_option<T>(sexp: SEXP) -> Result<Option<T>, SexpError>
135where
136 i32: TryCoerce<T>,
137 f64: TryCoerce<T>,
138 u8: TryCoerce<T>,
139 <i32 as TryCoerce<T>>::Error: std::fmt::Debug,
140 <f64 as TryCoerce<T>>::Error: std::fmt::Debug,
141 <u8 as TryCoerce<T>>::Error: std::fmt::Debug,
142{
143 if sexp.type_of() == SEXPTYPE::NILSXP {
144 return Ok(None);
145 }
146
147 let actual = sexp.type_of();
148 match actual {
149 SEXPTYPE::INTSXP => {
150 let len = sexp.len();
152 if len != 1 {
153 return Err(crate::from_r::SexpLengthError {
154 expected: 1,
155 actual: len,
156 }
157 .into());
158 }
159 let value = unsafe { sexp.as_slice::<i32>() }
160 .first()
161 .cloned()
162 .ok_or_else(|| {
163 SexpError::from(crate::from_r::SexpLengthError {
164 expected: 1,
165 actual: 0,
166 })
167 })?;
168 if value == NA_INTEGER {
169 Ok(None)
170 } else {
171 coerce_value(value).map(Some)
172 }
173 }
174 SEXPTYPE::REALSXP => {
175 let value: f64 = TryFromSexp::try_from_sexp(sexp)?;
176 if is_na_real(value) {
177 Ok(None)
178 } else {
179 coerce_value(value).map(Some)
180 }
181 }
182 SEXPTYPE::RAWSXP => {
183 let value: u8 = TryFromSexp::try_from_sexp(sexp)?;
184 coerce_value(value).map(Some)
185 }
186 SEXPTYPE::LGLSXP => {
187 let value: RLogical = TryFromSexp::try_from_sexp(sexp)?;
188 if value.is_na() {
189 Ok(None)
190 } else {
191 coerce_value(value.to_i32()).map(Some)
192 }
193 }
194 _ => Err(SexpError::InvalidValue(format!(
195 "expected integer, numeric, logical, or raw; got {:?}",
196 actual
197 ))),
198 }
199}
200
201#[inline]
202unsafe fn try_from_sexp_numeric_option_unchecked<T>(sexp: SEXP) -> Result<Option<T>, SexpError>
203where
204 i32: TryCoerce<T>,
205 f64: TryCoerce<T>,
206 u8: TryCoerce<T>,
207 <i32 as TryCoerce<T>>::Error: std::fmt::Debug,
208 <f64 as TryCoerce<T>>::Error: std::fmt::Debug,
209 <u8 as TryCoerce<T>>::Error: std::fmt::Debug,
210{
211 if sexp.type_of() == SEXPTYPE::NILSXP {
212 return Ok(None);
213 }
214
215 let actual = sexp.type_of();
216 match actual {
217 SEXPTYPE::INTSXP => {
218 let len = unsafe { sexp.len_unchecked() };
220 if len != 1 {
221 return Err(crate::from_r::SexpLengthError {
222 expected: 1,
223 actual: len,
224 }
225 .into());
226 }
227 let value = unsafe { sexp.as_slice_unchecked::<i32>() }
228 .first()
229 .cloned()
230 .ok_or_else(|| {
231 SexpError::from(crate::from_r::SexpLengthError {
232 expected: 1,
233 actual: 0,
234 })
235 })?;
236 if value == NA_INTEGER {
237 Ok(None)
238 } else {
239 coerce_value(value).map(Some)
240 }
241 }
242 SEXPTYPE::REALSXP => {
243 let value: f64 = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
244 if is_na_real(value) {
245 Ok(None)
246 } else {
247 coerce_value(value).map(Some)
248 }
249 }
250 SEXPTYPE::RAWSXP => {
251 let value: u8 = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
252 coerce_value(value).map(Some)
253 }
254 SEXPTYPE::LGLSXP => {
255 let value: RLogical = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
256 if value.is_na() {
257 Ok(None)
258 } else {
259 coerce_value(value.to_i32()).map(Some)
260 }
261 }
262 _ => Err(SexpError::InvalidValue(format!(
263 "expected integer, numeric, logical, or raw; got {:?}",
264 actual
265 ))),
266 }
267}
268
269impl TryFromSexp for i8 {
270 type Error = SexpError;
271
272 #[inline]
273 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
274 try_from_sexp_numeric_scalar(sexp)
275 }
276
277 #[inline]
278 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
279 unsafe { try_from_sexp_numeric_scalar_unchecked(sexp) }
280 }
281}
282
283impl TryFromSexp for i16 {
284 type Error = SexpError;
285
286 #[inline]
287 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
288 try_from_sexp_numeric_scalar(sexp)
289 }
290
291 #[inline]
292 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
293 unsafe { try_from_sexp_numeric_scalar_unchecked(sexp) }
294 }
295}
296
297impl TryFromSexp for u16 {
298 type Error = SexpError;
299
300 #[inline]
301 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
302 try_from_sexp_numeric_scalar(sexp)
303 }
304
305 #[inline]
306 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
307 unsafe { try_from_sexp_numeric_scalar_unchecked(sexp) }
308 }
309}
310
311impl TryFromSexp for u32 {
312 type Error = SexpError;
313
314 #[inline]
315 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
316 try_from_sexp_numeric_scalar(sexp)
317 }
318
319 #[inline]
320 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
321 unsafe { try_from_sexp_numeric_scalar_unchecked(sexp) }
322 }
323}
324
325impl TryFromSexp for f32 {
326 type Error = SexpError;
327
328 #[inline]
329 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
330 try_from_sexp_numeric_scalar(sexp)
331 }
332
333 #[inline]
334 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
335 unsafe { try_from_sexp_numeric_scalar_unchecked(sexp) }
336 }
337}
338
339impl TryFromSexp for Option<i8> {
340 type Error = SexpError;
341
342 #[inline]
343 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
344 try_from_sexp_numeric_option(sexp)
345 }
346
347 #[inline]
348 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
349 unsafe { try_from_sexp_numeric_option_unchecked(sexp) }
350 }
351}
352
353impl TryFromSexp for Option<i16> {
354 type Error = SexpError;
355
356 #[inline]
357 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
358 try_from_sexp_numeric_option(sexp)
359 }
360
361 #[inline]
362 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
363 unsafe { try_from_sexp_numeric_option_unchecked(sexp) }
364 }
365}
366
367impl TryFromSexp for Option<u16> {
368 type Error = SexpError;
369
370 #[inline]
371 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
372 try_from_sexp_numeric_option(sexp)
373 }
374
375 #[inline]
376 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
377 unsafe { try_from_sexp_numeric_option_unchecked(sexp) }
378 }
379}
380
381impl TryFromSexp for Option<u32> {
382 type Error = SexpError;
383
384 #[inline]
385 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
386 try_from_sexp_numeric_option(sexp)
387 }
388
389 #[inline]
390 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
391 unsafe { try_from_sexp_numeric_option_unchecked(sexp) }
392 }
393}
394
395impl TryFromSexp for Option<f32> {
396 type Error = SexpError;
397
398 #[inline]
399 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
400 try_from_sexp_numeric_option(sexp)
401 }
402
403 #[inline]
404 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
405 unsafe { try_from_sexp_numeric_option_unchecked(sexp) }
406 }
407}
408impl TryFromSexp for i64 {
447 type Error = SexpError;
448
449 #[inline]
450 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
451 try_from_sexp_numeric_scalar(sexp)
452 }
453
454 #[inline]
455 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
456 unsafe { try_from_sexp_numeric_scalar_unchecked(sexp) }
457 }
458}
459
460impl TryFromSexp for u64 {
465 type Error = SexpError;
466
467 #[inline]
468 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
469 try_from_sexp_numeric_scalar(sexp)
470 }
471
472 #[inline]
473 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
474 unsafe { try_from_sexp_numeric_scalar_unchecked(sexp) }
475 }
476}
477
478impl TryFromSexp for Option<i64> {
480 type Error = SexpError;
481
482 #[inline]
483 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
484 try_from_sexp_numeric_option(sexp)
485 }
486
487 #[inline]
488 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
489 unsafe { try_from_sexp_numeric_option_unchecked(sexp) }
490 }
491}
492
493impl TryFromSexp for Option<u64> {
494 type Error = SexpError;
495
496 #[inline]
497 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
498 try_from_sexp_numeric_option(sexp)
499 }
500
501 #[inline]
502 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
503 unsafe { try_from_sexp_numeric_option_unchecked(sexp) }
504 }
505}
506
507impl TryFromSexp for usize {
508 type Error = SexpError;
509
510 #[inline]
511 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
512 try_from_sexp_numeric_scalar(sexp)
513 }
514
515 #[inline]
516 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
517 unsafe { try_from_sexp_numeric_scalar_unchecked(sexp) }
518 }
519}
520
521impl TryFromSexp for Option<usize> {
522 type Error = SexpError;
523
524 #[inline]
525 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
526 try_from_sexp_numeric_option(sexp)
527 }
528
529 #[inline]
530 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
531 unsafe { try_from_sexp_numeric_option_unchecked(sexp) }
532 }
533}
534
535impl TryFromSexp for isize {
536 type Error = SexpError;
537
538 #[inline]
539 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
540 try_from_sexp_numeric_scalar(sexp)
541 }
542
543 #[inline]
544 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
545 unsafe { try_from_sexp_numeric_scalar_unchecked(sexp) }
546 }
547}
548
549impl TryFromSexp for Option<isize> {
550 type Error = SexpError;
551
552 #[inline]
553 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
554 try_from_sexp_numeric_option(sexp)
555 }
556
557 #[inline]
558 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
559 unsafe { try_from_sexp_numeric_option_unchecked(sexp) }
560 }
561}
562