1#![allow(rustdoc::private_intra_doc_links)]
2use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
53
54use crate::altrep_traits::NA_REAL;
55use crate::coerce::TryCoerce;
56use crate::{RLogical, SEXP, SEXPTYPE, SexpExt};
57
58#[inline]
64pub(crate) fn is_na_real(value: f64) -> bool {
65 value.to_bits() == NA_REAL.to_bits()
66}
67
68#[inline]
81pub(crate) unsafe fn charsxp_to_str(charsxp: SEXP) -> &'static str {
82 unsafe { charsxp_to_str_impl(charsxp.r_char(), charsxp) }
83}
84
85#[inline]
87pub(crate) unsafe fn charsxp_to_str_unchecked(charsxp: SEXP) -> &'static str {
88 unsafe { charsxp_to_str_impl(charsxp.r_char_unchecked(), charsxp) }
89}
90
91#[inline]
95unsafe fn charsxp_to_str_impl(ptr: *const std::os::raw::c_char, charsxp: SEXP) -> &'static str {
96 unsafe {
97 let len: usize = charsxp.len();
98 let bytes = r_slice(ptr.cast::<u8>(), len);
99 debug_assert!(
102 std::str::from_utf8(bytes).is_ok(),
103 "CHARSXP contains non-UTF-8 bytes (locale assertion may have been skipped)"
104 );
105 std::str::from_utf8_unchecked(bytes)
106 }
107}
108
109#[inline]
112pub(crate) unsafe fn charsxp_to_cow(charsxp: SEXP) -> std::borrow::Cow<'static, str> {
113 std::borrow::Cow::Borrowed(unsafe { charsxp_to_str(charsxp) })
114}
115
116#[inline]
132pub(crate) unsafe fn charsxp_to_string_lossy(charsxp: SEXP) -> Option<String> {
133 if charsxp.is_null_or_nil() || charsxp.is_na_string() {
134 return None;
135 }
136 let ptr = charsxp.r_char();
137 if ptr.is_null() {
138 return None;
139 }
140 Some(
141 unsafe { std::ffi::CStr::from_ptr(ptr) }
142 .to_string_lossy()
143 .into_owned(),
144 )
145}
146
147#[inline(always)]
160pub(crate) unsafe fn r_slice<'a, T>(ptr: *const T, len: usize) -> &'a [T] {
161 if len == 0 {
162 &[]
163 } else {
164 unsafe { std::slice::from_raw_parts(ptr, len) }
165 }
166}
167
168#[inline(always)]
174pub(crate) unsafe fn r_slice_mut<'a, T>(ptr: *mut T, len: usize) -> &'a mut [T] {
175 if len == 0 {
176 &mut []
177 } else {
178 unsafe { std::slice::from_raw_parts_mut(ptr, len) }
179 }
180}
181
182#[derive(Debug, Clone, Copy)]
183pub struct SexpTypeError {
185 pub expected: SEXPTYPE,
187 pub actual: SEXPTYPE,
189}
190
191impl std::fmt::Display for SexpTypeError {
192 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
193 write!(
194 f,
195 "type mismatch: expected {:?}, got {:?}",
196 self.expected, self.actual
197 )
198 }
199}
200
201impl std::error::Error for SexpTypeError {}
202
203#[derive(Debug, Clone, Copy)]
204pub struct SexpLengthError {
206 pub expected: usize,
208 pub actual: usize,
210}
211
212impl std::fmt::Display for SexpLengthError {
213 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
214 write!(
215 f,
216 "length mismatch: expected {}, got {}",
217 self.expected, self.actual
218 )
219 }
220}
221
222impl std::error::Error for SexpLengthError {}
223
224#[derive(Debug, Clone, Copy)]
225pub struct SexpNaError {
227 pub sexp_type: SEXPTYPE,
229}
230
231impl std::fmt::Display for SexpNaError {
232 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
233 write!(f, "unexpected NA value in {:?}", self.sexp_type)
234 }
235}
236
237impl std::error::Error for SexpNaError {}
238
239#[derive(Debug, Clone)]
240pub enum SexpError {
242 Type(SexpTypeError),
244 Length(SexpLengthError),
246 Na(SexpNaError),
248 InvalidValue(String),
250 MissingField(String),
252 DuplicateName(String),
254 #[cfg(feature = "either")]
258 EitherConversion {
259 left_error: String,
261 right_error: String,
263 },
264}
265
266impl std::fmt::Display for SexpError {
267 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
268 match self {
269 SexpError::Type(e) => write!(f, "{}", e),
270 SexpError::Length(e) => write!(f, "{}", e),
271 SexpError::Na(e) => write!(f, "{}", e),
272 SexpError::InvalidValue(msg) => write!(f, "invalid value: {}", msg),
273 SexpError::MissingField(name) => write!(f, "missing field: {}", name),
274 SexpError::DuplicateName(name) => write!(f, "duplicate name in list: {:?}", name),
275 #[cfg(feature = "either")]
276 SexpError::EitherConversion {
277 left_error,
278 right_error,
279 } => write!(
280 f,
281 "failed to convert to Either: Left failed ({}), Right failed ({})",
282 left_error, right_error
283 ),
284 }
285 }
286}
287
288impl std::error::Error for SexpError {
289 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
290 match self {
291 SexpError::Type(e) => Some(e),
292 SexpError::Length(e) => Some(e),
293 SexpError::Na(e) => Some(e),
294 SexpError::InvalidValue(_) => None,
295 SexpError::MissingField(_) => None,
296 SexpError::DuplicateName(_) => None,
297 #[cfg(feature = "either")]
298 SexpError::EitherConversion { .. } => None,
299 }
300 }
301}
302
303impl From<SexpTypeError> for SexpError {
304 fn from(e: SexpTypeError) -> Self {
305 SexpError::Type(e)
306 }
307}
308
309impl From<SexpLengthError> for SexpError {
310 fn from(e: SexpLengthError) -> Self {
311 SexpError::Length(e)
312 }
313}
314
315impl From<SexpNaError> for SexpError {
316 fn from(e: SexpNaError) -> Self {
317 SexpError::Na(e)
318 }
319}
320
321pub trait TryFromSexp: Sized {
339 type Error;
341
342 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error>;
346
347 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
355 Self::try_from_sexp(sexp)
357 }
358}
359
360impl<T> TryFromSexp for Box<[T]>
369where
370 Vec<T>: TryFromSexp,
371{
372 type Error = <Vec<T> as TryFromSexp>::Error;
373
374 #[inline]
375 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
376 <Vec<T> as TryFromSexp>::try_from_sexp(sexp).map(|v| v.into_boxed_slice())
377 }
378
379 #[inline]
380 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
381 unsafe { <Vec<T> as TryFromSexp>::try_from_sexp_unchecked(sexp) }
382 .map(|v| v.into_boxed_slice())
383 }
384}
385macro_rules! impl_try_from_sexp_scalar_native {
388 ($t:ty, $sexptype:ident) => {
389 impl TryFromSexp for $t {
390 type Error = SexpError;
391
392 #[inline]
393 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
394 let actual = sexp.type_of();
395 if actual != SEXPTYPE::$sexptype {
396 return Err(SexpTypeError {
397 expected: SEXPTYPE::$sexptype,
398 actual,
399 }
400 .into());
401 }
402 let len = sexp.len();
403 if len != 1 {
404 return Err(SexpLengthError {
405 expected: 1,
406 actual: len,
407 }
408 .into());
409 }
410 unsafe { sexp.as_slice::<$t>() }
411 .first()
412 .cloned()
413 .ok_or_else(|| {
414 SexpLengthError {
415 expected: 1,
416 actual: 0,
417 }
418 .into()
419 })
420 }
421
422 #[inline]
423 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
424 let actual = sexp.type_of();
425 if actual != SEXPTYPE::$sexptype {
426 return Err(SexpTypeError {
427 expected: SEXPTYPE::$sexptype,
428 actual,
429 }
430 .into());
431 }
432 let len = unsafe { sexp.len_unchecked() };
433 if len != 1 {
434 return Err(SexpLengthError {
435 expected: 1,
436 actual: len,
437 }
438 .into());
439 }
440 unsafe { sexp.as_slice_unchecked::<$t>() }
441 .first()
442 .cloned()
443 .ok_or_else(|| {
444 SexpLengthError {
445 expected: 1,
446 actual: 0,
447 }
448 .into()
449 })
450 }
451 }
452 };
453}
454
455impl TryFromSexp for i32 {
458 type Error = SexpError;
459
460 #[inline]
461 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
462 let actual = sexp.type_of();
463 if actual != SEXPTYPE::INTSXP {
464 return Err(SexpTypeError {
465 expected: SEXPTYPE::INTSXP,
466 actual,
467 }
468 .into());
469 }
470 let len = sexp.len();
471 if len != 1 {
472 return Err(SexpLengthError {
473 expected: 1,
474 actual: len,
475 }
476 .into());
477 }
478 let v = unsafe { sexp.as_slice::<i32>() }
479 .first()
480 .cloned()
481 .ok_or_else(|| {
482 SexpError::from(SexpLengthError {
483 expected: 1,
484 actual: 0,
485 })
486 })?;
487 if v == crate::altrep_traits::NA_INTEGER {
488 return Err(SexpNaError {
489 sexp_type: SEXPTYPE::INTSXP,
490 }
491 .into());
492 }
493 Ok(v)
494 }
495
496 #[inline]
497 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
498 let actual = sexp.type_of();
499 if actual != SEXPTYPE::INTSXP {
500 return Err(SexpTypeError {
501 expected: SEXPTYPE::INTSXP,
502 actual,
503 }
504 .into());
505 }
506 let len = unsafe { sexp.len_unchecked() };
507 if len != 1 {
508 return Err(SexpLengthError {
509 expected: 1,
510 actual: len,
511 }
512 .into());
513 }
514 let v = unsafe { sexp.as_slice_unchecked::<i32>() }
515 .first()
516 .cloned()
517 .ok_or_else(|| {
518 SexpError::from(SexpLengthError {
519 expected: 1,
520 actual: 0,
521 })
522 })?;
523 if v == crate::altrep_traits::NA_INTEGER {
524 return Err(SexpNaError {
525 sexp_type: SEXPTYPE::INTSXP,
526 }
527 .into());
528 }
529 Ok(v)
530 }
531}
532
533impl_try_from_sexp_scalar_native!(f64, REALSXP);
534impl_try_from_sexp_scalar_native!(u8, RAWSXP);
535impl_try_from_sexp_scalar_native!(RLogical, LGLSXP);
536impl_try_from_sexp_scalar_native!(crate::Rcomplex, CPLXSXP);
537
538impl TryFromSexp for SEXP {
563 type Error = SexpError;
564
565 #[inline]
572 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
573 Ok(unsafe { crate::altrep_sexp::ensure_materialized(sexp) })
574 }
575
576 #[inline]
577 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
578 Ok(unsafe { crate::altrep_sexp::ensure_materialized(sexp) })
579 }
580}
581
582impl TryFromSexp for Option<SEXP> {
583 type Error = SexpError;
584
585 #[inline]
586 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
587 if sexp.type_of() == SEXPTYPE::NILSXP {
588 Ok(None)
589 } else {
590 Ok(Some(unsafe {
591 crate::altrep_sexp::ensure_materialized(sexp)
592 }))
593 }
594 }
595
596 #[inline]
597 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
598 Self::try_from_sexp(sexp)
599 }
600}
601mod logical;
604
605mod coerced_scalars;
606pub(crate) use coerced_scalars::coerce_value;
607
608mod references;
609
610impl<T> TryFromSexp for &[T]
618where
619 T: crate::RNativeType + Copy,
620{
621 type Error = SexpTypeError;
622
623 #[inline]
624 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
625 let actual = sexp.type_of();
626 if actual != T::SEXP_TYPE {
627 return Err(SexpTypeError {
628 expected: T::SEXP_TYPE,
629 actual,
630 });
631 }
632 Ok(unsafe { sexp.as_slice::<T>() })
633 }
634
635 #[inline]
636 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
637 let actual = sexp.type_of();
638 if actual != T::SEXP_TYPE {
639 return Err(SexpTypeError {
640 expected: T::SEXP_TYPE,
641 actual,
642 });
643 }
644 Ok(unsafe { sexp.as_slice_unchecked::<T>() })
645 }
646}
647
648impl<T> TryFromSexp for &mut [T]
660where
661 T: crate::RNativeType + Copy,
662{
663 type Error = SexpTypeError;
664
665 #[inline]
666 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
667 let actual = sexp.type_of();
668 if actual != T::SEXP_TYPE {
669 return Err(SexpTypeError {
670 expected: T::SEXP_TYPE,
671 actual,
672 });
673 }
674 let len = sexp.len();
675 let ptr = unsafe { T::dataptr_mut(sexp) };
676 Ok(unsafe { r_slice_mut(ptr, len) })
677 }
678
679 #[inline]
680 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
681 let actual = sexp.type_of();
682 if actual != T::SEXP_TYPE {
683 return Err(SexpTypeError {
684 expected: T::SEXP_TYPE,
685 actual,
686 });
687 }
688 let len = unsafe { sexp.len_unchecked() };
689 let ptr = unsafe { T::dataptr_mut(sexp) };
690 Ok(unsafe { r_slice_mut(ptr, len) })
691 }
692}
693
694impl<T> TryFromSexp for Option<&[T]>
696where
697 T: crate::RNativeType + Copy,
698{
699 type Error = SexpError;
700
701 #[inline]
702 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
703 if sexp.type_of() == SEXPTYPE::NILSXP {
704 return Ok(None);
705 }
706 let slice: &[T] = TryFromSexp::try_from_sexp(sexp).map_err(SexpError::from)?;
707 Ok(Some(slice))
708 }
709
710 #[inline]
711 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
712 if sexp.type_of() == SEXPTYPE::NILSXP {
713 return Ok(None);
714 }
715 let slice: &[T] =
716 unsafe { TryFromSexp::try_from_sexp_unchecked(sexp).map_err(SexpError::from)? };
717 Ok(Some(slice))
718 }
719}
720
721impl<T> TryFromSexp for Option<&mut [T]>
723where
724 T: crate::RNativeType + Copy,
725{
726 type Error = SexpError;
727
728 #[inline]
729 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
730 if sexp.type_of() == SEXPTYPE::NILSXP {
731 return Ok(None);
732 }
733 let slice: &mut [T] = TryFromSexp::try_from_sexp(sexp).map_err(SexpError::from)?;
734 Ok(Some(slice))
735 }
736
737 #[inline]
738 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
739 if sexp.type_of() == SEXPTYPE::NILSXP {
740 return Ok(None);
741 }
742 let slice: &mut [T] =
743 unsafe { TryFromSexp::try_from_sexp_unchecked(sexp).map_err(SexpError::from)? };
744 Ok(Some(slice))
745 }
746}
747mod strings;
750
751impl<T> TryFromSexp for Result<T, ()>
754where
755 T: TryFromSexp,
756 T::Error: Into<SexpError>,
757{
758 type Error = SexpError;
759
760 #[inline]
761 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
762 if sexp.type_of() == SEXPTYPE::NILSXP {
763 return Ok(Err(()));
764 }
765 let value = T::try_from_sexp(sexp).map_err(Into::into)?;
766 Ok(Ok(value))
767 }
768
769 #[inline]
770 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
771 if sexp.type_of() == SEXPTYPE::NILSXP {
772 return Ok(Err(()));
773 }
774 let value = unsafe { T::try_from_sexp_unchecked(sexp).map_err(Into::into)? };
775 Ok(Ok(value))
776 }
777}
778mod na_vectors;
781
782mod collections;
783
784mod tuples;
785
786impl<T, const N: usize> TryFromSexp for [T; N]
793where
794 T: crate::RNativeType + Copy,
795{
796 type Error = SexpError;
797
798 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
799 let slice: &[T] = TryFromSexp::try_from_sexp(sexp)?;
800 if slice.len() != N {
801 return Err(SexpLengthError {
802 expected: N,
803 actual: slice.len(),
804 }
805 .into());
806 }
807
808 let mut arr = std::mem::MaybeUninit::<[T; N]>::uninit();
810 unsafe {
811 let dst: &mut [T] = std::slice::from_raw_parts_mut(arr.as_mut_ptr().cast::<T>(), N);
814 dst.copy_from_slice(&slice[..N]);
815 Ok(arr.assume_init())
816 }
817 }
818
819 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
820 Self::try_from_sexp(sexp)
821 }
822}
823use std::collections::VecDeque;
828
829impl<T> TryFromSexp for VecDeque<T>
831where
832 T: crate::RNativeType + Copy,
833{
834 type Error = SexpTypeError;
835
836 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
837 let slice: &[T] = TryFromSexp::try_from_sexp(sexp)?;
838 Ok(VecDeque::from(slice.to_vec()))
839 }
840
841 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
842 let slice: &[T] = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
843 Ok(VecDeque::from(slice.to_vec()))
844 }
845}
846use std::collections::BinaryHeap;
851
852impl<T> TryFromSexp for BinaryHeap<T>
856where
857 T: crate::RNativeType + Copy + Ord,
858{
859 type Error = SexpTypeError;
860
861 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
862 let slice: &[T] = TryFromSexp::try_from_sexp(sexp)?;
863 Ok(BinaryHeap::from(slice.to_vec()))
864 }
865
866 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
867 let slice: &[T] = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
868 Ok(BinaryHeap::from(slice.to_vec()))
869 }
870}
871mod cow_and_paths;
874
875impl<T> TryFromSexp for Option<Vec<T>>
882where
883 Vec<T>: TryFromSexp,
884 <Vec<T> as TryFromSexp>::Error: Into<SexpError>,
885{
886 type Error = SexpError;
887
888 #[inline]
889 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
890 if sexp.type_of() == SEXPTYPE::NILSXP {
891 Ok(None)
892 } else {
893 Vec::<T>::try_from_sexp(sexp).map(Some).map_err(Into::into)
894 }
895 }
896
897 #[inline]
898 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
899 if sexp.type_of() == SEXPTYPE::NILSXP {
900 Ok(None)
901 } else {
902 unsafe {
903 Vec::<T>::try_from_sexp_unchecked(sexp)
904 .map(Some)
905 .map_err(Into::into)
906 }
907 }
908 }
909}
910
911macro_rules! impl_option_map_try_from_sexp {
912 ($(#[$meta:meta])* $map_ty:ident) => {
913 $(#[$meta])*
914 impl<V: TryFromSexp> TryFromSexp for Option<$map_ty<String, V>>
915 where
916 V::Error: Into<SexpError>,
917 {
918 type Error = SexpError;
919
920 #[inline]
921 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
922 if sexp.type_of() == SEXPTYPE::NILSXP {
923 Ok(None)
924 } else {
925 $map_ty::<String, V>::try_from_sexp(sexp).map(Some)
926 }
927 }
928 }
929 };
930}
931
932impl_option_map_try_from_sexp!(
933 HashMap
935);
936impl_option_map_try_from_sexp!(
937 BTreeMap
939);
940
941macro_rules! impl_option_set_try_from_sexp {
942 ($(#[$meta:meta])* $set_ty:ident) => {
943 $(#[$meta])*
944 impl<T> TryFromSexp for Option<$set_ty<T>>
945 where
946 $set_ty<T>: TryFromSexp,
947 <$set_ty<T> as TryFromSexp>::Error: Into<SexpError>,
948 {
949 type Error = SexpError;
950
951 #[inline]
952 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
953 if sexp.type_of() == SEXPTYPE::NILSXP {
954 Ok(None)
955 } else {
956 $set_ty::<T>::try_from_sexp(sexp)
957 .map(Some)
958 .map_err(Into::into)
959 }
960 }
961 }
962 };
963}
964
965impl_option_set_try_from_sexp!(
966 HashSet
968);
969impl_option_set_try_from_sexp!(
970 BTreeSet
972);
973impl<T> TryFromSexp for Vec<Vec<T>>
981where
982 Vec<T>: TryFromSexp,
983 <Vec<T> as TryFromSexp>::Error: Into<SexpError>,
984{
985 type Error = SexpError;
986
987 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
988 map_vecsxp_with(sexp, |_i, elem| {
989 Vec::<T>::try_from_sexp(elem).map_err(Into::into)
990 })
991 }
992
993 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
994 unsafe {
995 map_vecsxp_with_unchecked(sexp, |_i, elem| {
996 Vec::<T>::try_from_sexp_unchecked(elem).map_err(Into::into)
997 })
998 }
999 }
1000}
1001use crate::coerce::Coerced;
1006
1007impl<T, R> TryFromSexp for Coerced<T, R>
1021where
1022 R: TryFromSexp,
1023 R: TryCoerce<T>,
1024 <R as TryFromSexp>::Error: Into<SexpError>,
1025 <R as TryCoerce<T>>::Error: std::fmt::Display,
1026{
1027 type Error = SexpError;
1028
1029 #[inline]
1030 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1031 let r_val: R = R::try_from_sexp(sexp).map_err(Into::into)?;
1032 let value: T = r_val
1033 .try_coerce()
1034 .map_err(|e| SexpError::InvalidValue(format!("{e}")))?;
1035 Ok(Coerced::new(value))
1036 }
1037
1038 #[inline]
1039 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1040 let r_val: R = unsafe { R::try_from_sexp_unchecked(sexp).map_err(Into::into)? };
1041 let value: T = r_val
1042 .try_coerce()
1043 .map_err(|e| SexpError::InvalidValue(format!("{e}")))?;
1044 Ok(Coerced::new(value))
1045 }
1046}
1047#[inline]
1063fn coerce_slice_to_vec<R, T>(slice: &[R], container: &str) -> Result<Vec<T>, SexpError>
1064where
1065 R: Copy + TryCoerce<T>,
1066 <R as TryCoerce<T>>::Error: std::fmt::Display,
1067{
1068 let mut result = Vec::with_capacity(slice.len());
1069 let mut errors = BatchedErrors::default();
1070 for (i, v) in slice.iter().copied().enumerate() {
1071 match v.try_coerce() {
1072 Ok(x) => result.push(x),
1073 Err(e) => errors.push(|| format!("invalid value at index {i}: {e}")),
1074 }
1075 }
1076 if errors.is_empty() {
1077 Ok(result)
1078 } else {
1079 Err(errors.into_error(container))
1080 }
1081}
1082
1083#[inline]
1095fn collect_coerced<U>(
1096 container: &str,
1097 len: usize,
1098 iter: impl Iterator<Item = Result<U, SexpError>>,
1099) -> Result<Vec<U>, SexpError> {
1100 let mut result = Vec::with_capacity(len);
1101 let mut errors = BatchedErrors::default();
1102 for (i, item) in iter.enumerate() {
1103 match item {
1104 Ok(v) => result.push(v),
1105 Err(SexpError::InvalidValue(msg)) => {
1106 errors.push(|| format!("invalid value at index {i}: {msg}"))
1107 }
1108 Err(other) => errors.push(|| format!("invalid value at index {i}: {other}")),
1109 }
1110 }
1111 if errors.is_empty() {
1112 Ok(result)
1113 } else {
1114 Err(errors.into_error(container))
1115 }
1116}
1117
1118#[inline]
1131pub(crate) fn from_numeric_vec_with<U, FI, FD, FR, FL>(
1132 sexp: SEXP,
1133 container: &str,
1134 map_i32: FI,
1135 map_f64: FD,
1136 map_u8: FR,
1137 map_lgl: FL,
1138) -> Result<Vec<U>, SexpError>
1139where
1140 FI: Fn(i32) -> Result<U, SexpError>,
1141 FD: Fn(f64) -> Result<U, SexpError>,
1142 FR: Fn(u8) -> Result<U, SexpError>,
1143 FL: Fn(RLogical) -> Result<U, SexpError>,
1144{
1145 let actual = sexp.type_of();
1146 match actual {
1147 SEXPTYPE::INTSXP => {
1148 let slice: &[i32] = unsafe { sexp.as_slice() };
1149 collect_coerced(container, slice.len(), slice.iter().copied().map(map_i32))
1150 }
1151 SEXPTYPE::REALSXP => {
1152 let slice: &[f64] = unsafe { sexp.as_slice() };
1153 collect_coerced(container, slice.len(), slice.iter().copied().map(map_f64))
1154 }
1155 SEXPTYPE::RAWSXP => {
1156 let slice: &[u8] = unsafe { sexp.as_slice() };
1157 collect_coerced(container, slice.len(), slice.iter().copied().map(map_u8))
1158 }
1159 SEXPTYPE::LGLSXP => {
1160 let slice: &[RLogical] = unsafe { sexp.as_slice() };
1161 collect_coerced(container, slice.len(), slice.iter().copied().map(map_lgl))
1162 }
1163 _ => Err(SexpError::InvalidValue(format!(
1164 "expected integer, numeric, logical, or raw; got {:?}",
1165 actual
1166 ))),
1167 }
1168}
1169
1170#[inline]
1185pub(crate) fn map_strsxp_with<U>(
1186 sexp: SEXP,
1187 mut map: impl FnMut(SEXP , usize) -> Result<U, SexpError>,
1188) -> Result<Vec<U>, SexpError> {
1189 let actual = sexp.type_of();
1190 if actual != SEXPTYPE::STRSXP {
1191 return Err(SexpTypeError {
1192 expected: SEXPTYPE::STRSXP,
1193 actual,
1194 }
1195 .into());
1196 }
1197
1198 let len = sexp.len();
1199 let mut result = Vec::with_capacity(len);
1200 for i in 0..len {
1201 let charsxp = sexp.string_elt(i as crate::R_xlen_t);
1202 result.push(map(charsxp, i)?);
1203 }
1204 Ok(result)
1205}
1206
1207#[inline]
1215pub(crate) fn scalar_charsxp(sexp: SEXP) -> Result<SEXP, SexpError> {
1216 let actual = sexp.type_of();
1217 if actual != SEXPTYPE::STRSXP {
1218 return Err(SexpTypeError {
1219 expected: SEXPTYPE::STRSXP,
1220 actual,
1221 }
1222 .into());
1223 }
1224
1225 let len = sexp.len();
1226 if len != 1 {
1227 return Err(SexpLengthError {
1228 expected: 1,
1229 actual: len,
1230 }
1231 .into());
1232 }
1233
1234 Ok(sexp.string_elt(0))
1235}
1236
1237#[inline]
1245pub(crate) unsafe fn scalar_charsxp_unchecked(sexp: SEXP) -> Result<SEXP, SexpError> {
1246 let actual = sexp.type_of();
1247 if actual != SEXPTYPE::STRSXP {
1248 return Err(SexpTypeError {
1249 expected: SEXPTYPE::STRSXP,
1250 actual,
1251 }
1252 .into());
1253 }
1254
1255 let len = unsafe { sexp.len_unchecked() };
1256 if len != 1 {
1257 return Err(SexpLengthError {
1258 expected: 1,
1259 actual: len,
1260 }
1261 .into());
1262 }
1263
1264 Ok(unsafe { sexp.string_elt_unchecked(0) })
1265}
1266
1267#[inline]
1275pub(crate) fn map_vecsxp_with<U>(
1276 sexp: SEXP,
1277 mut map: impl FnMut(usize, SEXP) -> Result<U, SexpError>,
1278) -> Result<Vec<U>, SexpError> {
1279 let actual = sexp.type_of();
1280 if actual != SEXPTYPE::VECSXP {
1281 return Err(SexpTypeError {
1282 expected: SEXPTYPE::VECSXP,
1283 actual,
1284 }
1285 .into());
1286 }
1287
1288 let len = sexp.len();
1289 let mut result = Vec::with_capacity(len);
1290 for i in 0..len {
1291 let elem = sexp.vector_elt(i as crate::R_xlen_t);
1292 result.push(map(i, elem)?);
1293 }
1294 Ok(result)
1295}
1296
1297#[inline]
1305pub(crate) unsafe fn map_vecsxp_with_unchecked<U>(
1306 sexp: SEXP,
1307 mut map: impl FnMut(usize, SEXP) -> Result<U, SexpError>,
1308) -> Result<Vec<U>, SexpError> {
1309 let actual = sexp.type_of();
1310 if actual != SEXPTYPE::VECSXP {
1311 return Err(SexpTypeError {
1312 expected: SEXPTYPE::VECSXP,
1313 actual,
1314 }
1315 .into());
1316 }
1317
1318 let len = unsafe { sexp.len_unchecked() };
1319 let mut result = Vec::with_capacity(len);
1320 for i in 0..len {
1321 let elem = unsafe { sexp.vector_elt_unchecked(i as crate::R_xlen_t) };
1322 result.push(map(i, elem)?);
1323 }
1324 Ok(result)
1325}
1326
1327#[inline]
1334fn try_from_sexp_numeric_vec<T>(sexp: SEXP, container: &str) -> Result<Vec<T>, SexpError>
1335where
1336 i32: TryCoerce<T>,
1337 f64: TryCoerce<T>,
1338 u8: TryCoerce<T>,
1339 <i32 as TryCoerce<T>>::Error: std::fmt::Display,
1340 <f64 as TryCoerce<T>>::Error: std::fmt::Display,
1341 <u8 as TryCoerce<T>>::Error: std::fmt::Display,
1342{
1343 from_numeric_vec_with(
1344 sexp,
1345 container,
1346 coerce_value,
1347 coerce_value,
1348 coerce_value,
1349 |v: RLogical| coerce_value(v.to_i32()),
1350 )
1351}
1352
1353macro_rules! impl_vec_try_from_sexp_numeric {
1355 ($target:ty) => {
1356 impl TryFromSexp for Vec<$target> {
1357 type Error = SexpError;
1358
1359 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1360 try_from_sexp_numeric_vec(sexp, concat!("Vec<", stringify!($target), ">"))
1361 }
1362
1363 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1364 try_from_sexp_numeric_vec(sexp, concat!("Vec<", stringify!($target), ">"))
1365 }
1366 }
1367 };
1368}
1369
1370impl_vec_try_from_sexp_numeric!(i8);
1371impl_vec_try_from_sexp_numeric!(i16);
1372impl_vec_try_from_sexp_numeric!(i64);
1373impl_vec_try_from_sexp_numeric!(isize);
1374impl_vec_try_from_sexp_numeric!(u16);
1375impl_vec_try_from_sexp_numeric!(u32);
1376impl_vec_try_from_sexp_numeric!(u64);
1377impl_vec_try_from_sexp_numeric!(usize);
1378impl_vec_try_from_sexp_numeric!(f32);
1379
1380impl TryFromSexp for Vec<bool> {
1382 type Error = SexpError;
1383
1384 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1385 let actual = sexp.type_of();
1386 if actual != SEXPTYPE::LGLSXP {
1387 return Err(SexpTypeError {
1388 expected: SEXPTYPE::LGLSXP,
1389 actual,
1390 }
1391 .into());
1392 }
1393 let slice: &[RLogical] = unsafe { sexp.as_slice() };
1394 coerce_slice_to_vec(slice, "Vec<bool>")
1395 }
1396
1397 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1398 Self::try_from_sexp(sexp)
1399 }
1400}
1401#[inline]
1410fn try_from_sexp_numeric_set<T, S>(sexp: SEXP, container: &str) -> Result<S, SexpError>
1411where
1412 S: std::iter::FromIterator<T>,
1413 i32: TryCoerce<T>,
1414 f64: TryCoerce<T>,
1415 u8: TryCoerce<T>,
1416 <i32 as TryCoerce<T>>::Error: std::fmt::Display,
1417 <f64 as TryCoerce<T>>::Error: std::fmt::Display,
1418 <u8 as TryCoerce<T>>::Error: std::fmt::Display,
1419{
1420 let vec = try_from_sexp_numeric_vec(sexp, container)?;
1421 Ok(vec.into_iter().collect())
1422}
1423
1424macro_rules! impl_set_try_from_sexp_numeric {
1425 ($set_ty:ident, $target:ty) => {
1426 impl TryFromSexp for $set_ty<$target> {
1427 type Error = SexpError;
1428
1429 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1430 try_from_sexp_numeric_set(
1431 sexp,
1432 concat!(stringify!($set_ty), "<", stringify!($target), ">"),
1433 )
1434 }
1435
1436 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1437 try_from_sexp_numeric_set(
1438 sexp,
1439 concat!(stringify!($set_ty), "<", stringify!($target), ">"),
1440 )
1441 }
1442 }
1443 };
1444}
1445
1446impl_set_try_from_sexp_numeric!(HashSet, i8);
1447impl_set_try_from_sexp_numeric!(HashSet, i16);
1448impl_set_try_from_sexp_numeric!(HashSet, i64);
1449impl_set_try_from_sexp_numeric!(HashSet, isize);
1450impl_set_try_from_sexp_numeric!(HashSet, u16);
1451impl_set_try_from_sexp_numeric!(HashSet, u32);
1452impl_set_try_from_sexp_numeric!(HashSet, u64);
1453impl_set_try_from_sexp_numeric!(HashSet, usize);
1454
1455impl_set_try_from_sexp_numeric!(BTreeSet, i8);
1456impl_set_try_from_sexp_numeric!(BTreeSet, i16);
1457impl_set_try_from_sexp_numeric!(BTreeSet, i64);
1458impl_set_try_from_sexp_numeric!(BTreeSet, isize);
1459impl_set_try_from_sexp_numeric!(BTreeSet, u16);
1460impl_set_try_from_sexp_numeric!(BTreeSet, u32);
1461impl_set_try_from_sexp_numeric!(BTreeSet, u64);
1462impl_set_try_from_sexp_numeric!(BTreeSet, usize);
1463
1464macro_rules! impl_set_try_from_sexp_bool {
1465 ($set_ty:ident) => {
1466 impl TryFromSexp for $set_ty<bool> {
1467 type Error = SexpError;
1468
1469 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1470 let vec: Vec<bool> = TryFromSexp::try_from_sexp(sexp)?;
1471 Ok(vec.into_iter().collect())
1472 }
1473
1474 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1475 Self::try_from_sexp(sexp)
1476 }
1477 }
1478 };
1479}
1480
1481impl_set_try_from_sexp_bool!(HashSet);
1482impl_set_try_from_sexp_bool!(BTreeSet);
1483use crate::externalptr::{ExternalPtr, TypeMismatchError, TypedExternal};
1488
1489fn type_mismatch_to_sexp_error(e: TypeMismatchError) -> SexpError {
1493 match e {
1494 TypeMismatchError::NullPointer => {
1495 SexpError::InvalidValue("external pointer is null".to_string())
1496 }
1497 TypeMismatchError::InvalidTypeId => {
1498 SexpError::InvalidValue("external pointer has no valid type id".to_string())
1499 }
1500 TypeMismatchError::Mismatch { expected, found } => SexpError::InvalidValue(format!(
1501 "type mismatch: expected `{}`, found `{}`",
1502 expected, found
1503 )),
1504 }
1505}
1506
1507fn not_a_handle_error(actual: SEXPTYPE) -> SexpError {
1512 SexpError::InvalidValue(format!(
1513 "expected an external pointer or a miniextendr class object wrapping one, got {:?}",
1514 actual
1515 ))
1516}
1517
1518impl<T: TypedExternal + Send> TryFromSexp for ExternalPtr<T> {
1534 type Error = SexpError;
1535
1536 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1537 let actual = sexp.type_of();
1538 if actual != SEXPTYPE::EXTPTRSXP {
1539 return match unsafe { crate::externalptr::unwrap_class_handle(sexp) } {
1543 Some(inner) => unsafe { ExternalPtr::wrap_sexp_with_error(inner) }
1544 .map_err(type_mismatch_to_sexp_error),
1545 None => Err(not_a_handle_error(actual)),
1546 };
1547 }
1548
1549 unsafe { ExternalPtr::wrap_sexp_with_error(sexp) }.map_err(type_mismatch_to_sexp_error)
1551 }
1552
1553 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1554 let actual = sexp.type_of();
1555 if actual != SEXPTYPE::EXTPTRSXP {
1556 return match unsafe { crate::externalptr::unwrap_class_handle(sexp) } {
1557 Some(inner) => {
1558 unsafe { ExternalPtr::wrap_sexp_unchecked(inner) }.ok_or_else(|| {
1559 SexpError::InvalidValue(
1560 "failed to convert external pointer: type mismatch or null pointer"
1561 .to_string(),
1562 )
1563 })
1564 }
1565 None => Err(not_a_handle_error(actual)),
1566 };
1567 }
1568
1569 unsafe { ExternalPtr::wrap_sexp_unchecked(sexp) }.ok_or_else(|| {
1571 SexpError::InvalidValue(
1572 "failed to convert external pointer: type mismatch or null pointer".to_string(),
1573 )
1574 })
1575 }
1576}
1577
1578impl<T: TypedExternal + Send> TryFromSexp for Option<ExternalPtr<T>> {
1579 type Error = SexpError;
1580
1581 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1582 if sexp.type_of() == SEXPTYPE::NILSXP {
1583 return Ok(None);
1584 }
1585 let ptr: ExternalPtr<T> = TryFromSexp::try_from_sexp(sexp)?;
1586 Ok(Some(ptr))
1587 }
1588
1589 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1590 if sexp.type_of() == SEXPTYPE::NILSXP {
1591 return Ok(None);
1592 }
1593 let ptr: ExternalPtr<T> = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
1594 Ok(Some(ptr))
1595 }
1596}
1597
1598impl<T: TypedExternal + Send> TryFromSexp for Vec<ExternalPtr<T>> {
1608 type Error = SexpError;
1609
1610 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1611 map_vecsxp_with(sexp, |_i, elem| {
1612 <ExternalPtr<T> as TryFromSexp>::try_from_sexp(elem)
1613 })
1614 }
1615
1616 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1617 unsafe {
1618 map_vecsxp_with_unchecked(sexp, |_i, elem| {
1619 <ExternalPtr<T> as TryFromSexp>::try_from_sexp_unchecked(elem)
1620 })
1621 }
1622 }
1623}
1624
1625impl<T: TypedExternal + Send> TryFromSexp for Vec<Option<ExternalPtr<T>>> {
1629 type Error = SexpError;
1630
1631 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1632 map_vecsxp_with(sexp, |_i, elem| {
1633 <Option<ExternalPtr<T>> as TryFromSexp>::try_from_sexp(elem)
1634 })
1635 }
1636
1637 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1638 unsafe {
1639 map_vecsxp_with_unchecked(sexp, |_i, elem| {
1640 <Option<ExternalPtr<T>> as TryFromSexp>::try_from_sexp_unchecked(elem)
1641 })
1642 }
1643 }
1644}
1645#[cfg(feature = "connections")]
1650mod connections_from_r {
1651 use std::ffi::CStr;
1652
1653 use crate::connection::{RNullConnection, RStderr, RStdin, RStdout, Rconn};
1654 use crate::from_r::{SexpError, TryFromSexp};
1655 use crate::{Rboolean, SEXP};
1656
1657 unsafe fn conn_description(sexp: SEXP) -> Option<String> {
1663 unsafe {
1664 let handle = crate::sys::R_GetConnection(sexp);
1665 let conn = handle.cast::<Rconn>().cast_const();
1666 if (*conn).description.is_null() {
1667 None
1668 } else {
1669 Some(
1670 CStr::from_ptr((*conn).description)
1671 .to_string_lossy()
1672 .into_owned(),
1673 )
1674 }
1675 }
1676 }
1677
1678 unsafe fn conn_class(sexp: SEXP) -> Option<String> {
1679 unsafe {
1680 let handle = crate::sys::R_GetConnection(sexp);
1681 let conn = handle.cast::<Rconn>().cast_const();
1682 if (*conn).class.is_null() {
1683 None
1684 } else {
1685 Some(CStr::from_ptr((*conn).class).to_string_lossy().into_owned())
1686 }
1687 }
1688 }
1689
1690 unsafe fn conn_canwrite(sexp: SEXP) -> bool {
1691 unsafe {
1692 let handle = crate::sys::R_GetConnection(sexp);
1693 let conn = handle.cast::<Rconn>().cast_const();
1694 (*conn).canwrite != Rboolean::FALSE
1695 }
1696 }
1697
1698 unsafe fn conn_isopen(sexp: SEXP) -> bool {
1699 unsafe {
1700 let handle = crate::sys::R_GetConnection(sexp);
1701 let conn = handle.cast::<Rconn>().cast_const();
1702 (*conn).isopen != Rboolean::FALSE
1703 }
1704 }
1705
1706 unsafe fn validate_terminal(sexp: SEXP, expected_desc: &str) -> Result<(), SexpError> {
1708 let desc = unsafe { conn_description(sexp) }.unwrap_or_default();
1709 if desc != expected_desc {
1710 return Err(SexpError::InvalidValue(format!(
1711 "expected terminal connection with description {:?}, got {:?}",
1712 expected_desc, desc
1713 )));
1714 }
1715 let cls = unsafe { conn_class(sexp) }.unwrap_or_default();
1716 if cls != "terminal" {
1717 return Err(SexpError::InvalidValue(format!(
1718 "expected class \"terminal\", got {:?}",
1719 cls
1720 )));
1721 }
1722 Ok(())
1723 }
1724
1725 impl TryFromSexp for RStdin {
1726 type Error = SexpError;
1727
1728 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1729 unsafe { validate_terminal(sexp, "stdin") }?;
1730 Ok(RStdin)
1731 }
1732
1733 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1734 Self::try_from_sexp(sexp)
1735 }
1736 }
1737
1738 impl TryFromSexp for RStdout {
1739 type Error = SexpError;
1740
1741 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1742 unsafe { validate_terminal(sexp, "stdout") }?;
1743 Ok(RStdout)
1744 }
1745
1746 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1747 Self::try_from_sexp(sexp)
1748 }
1749 }
1750
1751 impl TryFromSexp for RStderr {
1752 type Error = SexpError;
1753
1754 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1755 unsafe { validate_terminal(sexp, "stderr") }?;
1756 Ok(RStderr)
1757 }
1758
1759 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1760 Self::try_from_sexp(sexp)
1761 }
1762 }
1763
1764 impl TryFromSexp for RNullConnection {
1771 type Error = SexpError;
1772
1773 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1774 if !unsafe { conn_isopen(sexp) } {
1775 return Err(SexpError::InvalidValue(
1776 "expected an open connection".to_string(),
1777 ));
1778 }
1779 if !unsafe { conn_canwrite(sexp) } {
1780 return Err(SexpError::InvalidValue(
1781 "expected a write-capable connection".to_string(),
1782 ));
1783 }
1784 unsafe { crate::sys::R_PreserveObject(sexp) };
1786 Ok(unsafe { RNullConnection::from_preserved_sexp(sexp) })
1787 }
1788
1789 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1790 Self::try_from_sexp(sexp)
1791 }
1792 }
1793}
1794
1795#[cfg(feature = "connections")]
1800mod txt_progress_bar_from_r {
1801 use crate::from_r::{SexpError, TryFromSexp};
1802 use crate::sys::R_PreserveObject;
1803 use crate::txt_progress_bar::RTxtProgressBar;
1804 use crate::{SEXP, SexpExt};
1805
1806 impl TryFromSexp for RTxtProgressBar {
1807 type Error = SexpError;
1808
1809 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1810 if !sexp.inherits_class(c"txtProgressBar") {
1812 return Err(SexpError::InvalidValue(
1813 "expected a SEXP with class \"txtProgressBar\"".to_string(),
1814 ));
1815 }
1816 unsafe { R_PreserveObject(sexp) };
1818 Ok(unsafe { RTxtProgressBar::from_preserved_sexp(sexp) })
1819 }
1820
1821 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1822 Self::try_from_sexp(sexp)
1823 }
1824 }
1825}
1826
1827#[macro_export]
1835macro_rules! impl_option_try_from_sexp {
1836 ($t:ty) => {
1837 impl $crate::from_r::TryFromSexp for Option<$t> {
1838 type Error = $crate::from_r::SexpError;
1839
1840 fn try_from_sexp(sexp: $crate::SEXP) -> Result<Self, Self::Error> {
1841 use $crate::{SEXPTYPE, SexpExt};
1842 if sexp.type_of() == SEXPTYPE::NILSXP {
1843 return Ok(None);
1844 }
1845 <$t as $crate::from_r::TryFromSexp>::try_from_sexp(sexp).map(Some)
1846 }
1847
1848 unsafe fn try_from_sexp_unchecked(sexp: $crate::SEXP) -> Result<Self, Self::Error> {
1849 use $crate::{SEXPTYPE, SexpExt};
1850 if sexp.type_of() == SEXPTYPE::NILSXP {
1851 return Ok(None);
1852 }
1853 unsafe {
1854 <$t as $crate::from_r::TryFromSexp>::try_from_sexp_unchecked(sexp).map(Some)
1855 }
1856 }
1857 }
1858 };
1859}
1860
1861#[macro_export]
1865macro_rules! impl_vec_try_from_sexp_list {
1866 ($t:ty) => {
1867 impl $crate::from_r::TryFromSexp for Vec<$t> {
1868 type Error = $crate::from_r::SexpError;
1869
1870 fn try_from_sexp(sexp: $crate::SEXP) -> Result<Self, Self::Error> {
1871 use $crate::from_r::SexpTypeError;
1872 use $crate::{SEXPTYPE, SexpExt};
1873
1874 let actual = sexp.type_of();
1875 if actual != SEXPTYPE::VECSXP {
1876 return Err(SexpTypeError {
1877 expected: SEXPTYPE::VECSXP,
1878 actual,
1879 }
1880 .into());
1881 }
1882
1883 let len = sexp.len();
1884 let mut result = Vec::with_capacity(len);
1885 for i in 0..len {
1886 let elem = sexp.vector_elt(i as $crate::R_xlen_t);
1887 result.push(<$t as $crate::from_r::TryFromSexp>::try_from_sexp(elem)?);
1888 }
1889 Ok(result)
1890 }
1891
1892 unsafe fn try_from_sexp_unchecked(sexp: $crate::SEXP) -> Result<Self, Self::Error> {
1893 use $crate::from_r::SexpTypeError;
1894 use $crate::{SEXPTYPE, SexpExt};
1895
1896 let actual = sexp.type_of();
1897 if actual != SEXPTYPE::VECSXP {
1898 return Err(SexpTypeError {
1899 expected: SEXPTYPE::VECSXP,
1900 actual,
1901 }
1902 .into());
1903 }
1904
1905 let len = unsafe { sexp.len_unchecked() };
1906 let mut result = Vec::with_capacity(len);
1907 for i in 0..len {
1908 let elem = unsafe { sexp.vector_elt_unchecked(i as $crate::R_xlen_t) };
1909 result.push(unsafe {
1910 <$t as $crate::from_r::TryFromSexp>::try_from_sexp_unchecked(elem)?
1911 });
1912 }
1913 Ok(result)
1914 }
1915 }
1916 };
1917}
1918
1919#[macro_export]
1923macro_rules! impl_vec_option_try_from_sexp_list {
1924 ($t:ty) => {
1925 impl $crate::from_r::TryFromSexp for Vec<Option<$t>> {
1926 type Error = $crate::from_r::SexpError;
1927
1928 fn try_from_sexp(sexp: $crate::SEXP) -> Result<Self, Self::Error> {
1929 use $crate::from_r::SexpTypeError;
1930 use $crate::{SEXPTYPE, SexpExt};
1931
1932 let actual = sexp.type_of();
1933 if actual != SEXPTYPE::VECSXP {
1934 return Err(SexpTypeError {
1935 expected: SEXPTYPE::VECSXP,
1936 actual,
1937 }
1938 .into());
1939 }
1940
1941 let len = sexp.len();
1942 let mut result = Vec::with_capacity(len);
1943 for i in 0..len {
1944 let elem = sexp.vector_elt(i as $crate::R_xlen_t);
1945 if elem == $crate::SEXP::nil() {
1946 result.push(None);
1947 } else {
1948 result.push(Some(<$t as $crate::from_r::TryFromSexp>::try_from_sexp(
1949 elem,
1950 )?));
1951 }
1952 }
1953 Ok(result)
1954 }
1955
1956 unsafe fn try_from_sexp_unchecked(sexp: $crate::SEXP) -> Result<Self, Self::Error> {
1957 use $crate::from_r::SexpTypeError;
1958 use $crate::{SEXPTYPE, SexpExt};
1959
1960 let actual = sexp.type_of();
1961 if actual != SEXPTYPE::VECSXP {
1962 return Err(SexpTypeError {
1963 expected: SEXPTYPE::VECSXP,
1964 actual,
1965 }
1966 .into());
1967 }
1968
1969 let len = unsafe { sexp.len_unchecked() };
1970 let mut result = Vec::with_capacity(len);
1971 for i in 0..len {
1972 let elem = unsafe { sexp.vector_elt_unchecked(i as $crate::R_xlen_t) };
1973 if elem == $crate::SEXP::nil() {
1974 result.push(None);
1975 } else {
1976 result.push(Some(unsafe {
1977 <$t as $crate::from_r::TryFromSexp>::try_from_sexp_unchecked(elem)?
1978 }));
1979 }
1980 }
1981 Ok(result)
1982 }
1983 }
1984 };
1985}
1986
1987pub(crate) const BATCHED_ERROR_CAP: usize = 10;
1994
1995#[doc(hidden)]
2015#[derive(Default)]
2016pub struct BatchedErrors {
2017 listed: Vec<String>,
2018 total: usize,
2019}
2020
2021impl BatchedErrors {
2022 #[inline]
2026 pub fn push(&mut self, msg: impl FnOnce() -> String) {
2027 if self.listed.len() < BATCHED_ERROR_CAP {
2028 self.listed.push(msg());
2029 }
2030 self.total += 1;
2031 }
2032
2033 #[inline]
2035 pub fn is_empty(&self) -> bool {
2036 self.total == 0
2037 }
2038
2039 pub fn into_error(self, container: &str) -> SexpError {
2042 debug_assert!(self.total > 0, "batching zero conversion errors");
2043 let mut msg = format!("{container} conversion failed: {}", self.listed.join("; "));
2044 if self.total > self.listed.len() {
2045 use std::fmt::Write;
2046 let _ = write!(msg, "; and {} more", self.total - self.listed.len());
2047 }
2048 SexpError::InvalidValue(msg)
2049 }
2050}
2051
2052#[macro_export]
2080macro_rules! try_from_sexp_via_str_parse {
2081 ($ty:ty, $label:literal, |$s:ident| $parse:expr) => {
2082 impl $crate::from_r::TryFromSexp for $ty {
2083 type Error = $crate::from_r::SexpError;
2084
2085 fn try_from_sexp(sexp: $crate::SEXP) -> Result<Self, Self::Error> {
2086 let opt: Option<String> = $crate::from_r::TryFromSexp::try_from_sexp(sexp)?;
2087 let s = opt.ok_or($crate::from_r::SexpError::Na($crate::from_r::SexpNaError {
2088 sexp_type: $crate::SEXPTYPE::STRSXP,
2089 }))?;
2090 let $s: &str = &s;
2091 ($parse).map_err(|e| {
2092 $crate::from_r::SexpError::InvalidValue(format!(
2093 concat!("invalid ", $label, ": {}"),
2094 e
2095 ))
2096 })
2097 }
2098 }
2099
2100 impl $crate::from_r::TryFromSexp for Option<$ty> {
2101 type Error = $crate::from_r::SexpError;
2102
2103 fn try_from_sexp(sexp: $crate::SEXP) -> Result<Self, Self::Error> {
2104 let opt: Option<String> = $crate::from_r::TryFromSexp::try_from_sexp(sexp)?;
2105 match opt {
2106 None => Ok(None),
2107 Some(s) => {
2108 let $s: &str = &s;
2109 ($parse).map(Some).map_err(|e| {
2110 $crate::from_r::SexpError::InvalidValue(format!(
2111 concat!("invalid ", $label, ": {}"),
2112 e
2113 ))
2114 })
2115 }
2116 }
2117 }
2118 }
2119
2120 impl $crate::from_r::TryFromSexp for Vec<$ty> {
2121 type Error = $crate::from_r::SexpError;
2122
2123 fn try_from_sexp(sexp: $crate::SEXP) -> Result<Self, Self::Error> {
2124 let values: Vec<Option<String>> = $crate::from_r::TryFromSexp::try_from_sexp(sexp)?;
2125 let mut result = Vec::with_capacity(values.len());
2126 let mut errors = $crate::from_r::BatchedErrors::default();
2127 for (i, opt) in values.into_iter().enumerate() {
2128 match opt {
2129 None => errors.push(|| {
2130 format!(
2131 concat!(
2132 "NA at index {} not allowed for Vec<",
2133 stringify!($ty),
2134 ">"
2135 ),
2136 i
2137 )
2138 }),
2139 Some(s) => {
2140 let $s: &str = &s;
2141 match ($parse) {
2142 Ok(v) => result.push(v),
2143 Err(e) => errors.push(|| {
2144 format!(concat!("invalid ", $label, " at index {}: {}"), i, e)
2145 }),
2146 }
2147 }
2148 }
2149 }
2150 if errors.is_empty() {
2151 Ok(result)
2152 } else {
2153 Err(errors.into_error(concat!("Vec<", stringify!($ty), ">")))
2154 }
2155 }
2156 }
2157
2158 impl $crate::from_r::TryFromSexp for Vec<Option<$ty>> {
2159 type Error = $crate::from_r::SexpError;
2160
2161 fn try_from_sexp(sexp: $crate::SEXP) -> Result<Self, Self::Error> {
2162 let values: Vec<Option<String>> = $crate::from_r::TryFromSexp::try_from_sexp(sexp)?;
2163 let mut result = Vec::with_capacity(values.len());
2164 let mut errors = $crate::from_r::BatchedErrors::default();
2165 for (i, opt) in values.into_iter().enumerate() {
2166 match opt {
2167 None => result.push(None),
2168 Some(s) => {
2169 let $s: &str = &s;
2170 match ($parse) {
2171 Ok(v) => result.push(Some(v)),
2172 Err(e) => errors.push(|| {
2173 format!(concat!("invalid ", $label, " at index {}: {}"), i, e)
2174 }),
2175 }
2176 }
2177 }
2178 }
2179 if errors.is_empty() {
2180 Ok(result)
2181 } else {
2182 Err(errors.into_error(concat!("Vec<Option<", stringify!($ty), ">>")))
2183 }
2184 }
2185 }
2186 };
2187}
2188