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