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]
656where
657 T: crate::RNativeType + Copy,
658{
659 type Error = SexpTypeError;
660
661 #[inline]
662 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
663 let actual = sexp.type_of();
664 if actual != T::SEXP_TYPE {
665 return Err(SexpTypeError {
666 expected: T::SEXP_TYPE,
667 actual,
668 });
669 }
670 let len = sexp.len();
671 let ptr = unsafe { T::dataptr_mut(sexp) };
672 Ok(unsafe { r_slice_mut(ptr, len) })
673 }
674
675 #[inline]
676 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
677 let actual = sexp.type_of();
678 if actual != T::SEXP_TYPE {
679 return Err(SexpTypeError {
680 expected: T::SEXP_TYPE,
681 actual,
682 });
683 }
684 let len = unsafe { sexp.len_unchecked() };
685 let ptr = unsafe { T::dataptr_mut(sexp) };
686 Ok(unsafe { r_slice_mut(ptr, len) })
687 }
688}
689
690impl<T> TryFromSexp for Option<&[T]>
692where
693 T: crate::RNativeType + Copy,
694{
695 type Error = SexpError;
696
697 #[inline]
698 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
699 if sexp.type_of() == SEXPTYPE::NILSXP {
700 return Ok(None);
701 }
702 let slice: &[T] = TryFromSexp::try_from_sexp(sexp).map_err(SexpError::from)?;
703 Ok(Some(slice))
704 }
705
706 #[inline]
707 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
708 if sexp.type_of() == SEXPTYPE::NILSXP {
709 return Ok(None);
710 }
711 let slice: &[T] =
712 unsafe { TryFromSexp::try_from_sexp_unchecked(sexp).map_err(SexpError::from)? };
713 Ok(Some(slice))
714 }
715}
716
717impl<T> TryFromSexp for Option<&mut [T]>
719where
720 T: crate::RNativeType + Copy,
721{
722 type Error = SexpError;
723
724 #[inline]
725 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
726 if sexp.type_of() == SEXPTYPE::NILSXP {
727 return Ok(None);
728 }
729 let slice: &mut [T] = TryFromSexp::try_from_sexp(sexp).map_err(SexpError::from)?;
730 Ok(Some(slice))
731 }
732
733 #[inline]
734 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
735 if sexp.type_of() == SEXPTYPE::NILSXP {
736 return Ok(None);
737 }
738 let slice: &mut [T] =
739 unsafe { TryFromSexp::try_from_sexp_unchecked(sexp).map_err(SexpError::from)? };
740 Ok(Some(slice))
741 }
742}
743mod strings;
746
747impl<T> TryFromSexp for Result<T, ()>
750where
751 T: TryFromSexp,
752 T::Error: Into<SexpError>,
753{
754 type Error = SexpError;
755
756 #[inline]
757 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
758 if sexp.type_of() == SEXPTYPE::NILSXP {
759 return Ok(Err(()));
760 }
761 let value = T::try_from_sexp(sexp).map_err(Into::into)?;
762 Ok(Ok(value))
763 }
764
765 #[inline]
766 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
767 if sexp.type_of() == SEXPTYPE::NILSXP {
768 return Ok(Err(()));
769 }
770 let value = unsafe { T::try_from_sexp_unchecked(sexp).map_err(Into::into)? };
771 Ok(Ok(value))
772 }
773}
774mod na_vectors;
777
778mod collections;
779
780mod tuples;
781
782impl<T, const N: usize> TryFromSexp for [T; N]
789where
790 T: crate::RNativeType + Copy,
791{
792 type Error = SexpError;
793
794 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
795 let slice: &[T] = TryFromSexp::try_from_sexp(sexp)?;
796 if slice.len() != N {
797 return Err(SexpLengthError {
798 expected: N,
799 actual: slice.len(),
800 }
801 .into());
802 }
803
804 let mut arr = std::mem::MaybeUninit::<[T; N]>::uninit();
806 unsafe {
807 let dst: &mut [T] = std::slice::from_raw_parts_mut(arr.as_mut_ptr().cast::<T>(), N);
810 dst.copy_from_slice(&slice[..N]);
811 Ok(arr.assume_init())
812 }
813 }
814
815 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
816 Self::try_from_sexp(sexp)
817 }
818}
819use std::collections::VecDeque;
824
825impl<T> TryFromSexp for VecDeque<T>
827where
828 T: crate::RNativeType + Copy,
829{
830 type Error = SexpTypeError;
831
832 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
833 let slice: &[T] = TryFromSexp::try_from_sexp(sexp)?;
834 Ok(VecDeque::from(slice.to_vec()))
835 }
836
837 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
838 let slice: &[T] = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
839 Ok(VecDeque::from(slice.to_vec()))
840 }
841}
842use std::collections::BinaryHeap;
847
848impl<T> TryFromSexp for BinaryHeap<T>
852where
853 T: crate::RNativeType + Copy + Ord,
854{
855 type Error = SexpTypeError;
856
857 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
858 let slice: &[T] = TryFromSexp::try_from_sexp(sexp)?;
859 Ok(BinaryHeap::from(slice.to_vec()))
860 }
861
862 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
863 let slice: &[T] = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
864 Ok(BinaryHeap::from(slice.to_vec()))
865 }
866}
867mod cow_and_paths;
870
871impl<T> TryFromSexp for Option<Vec<T>>
878where
879 Vec<T>: TryFromSexp,
880 <Vec<T> as TryFromSexp>::Error: Into<SexpError>,
881{
882 type Error = SexpError;
883
884 #[inline]
885 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
886 if sexp.type_of() == SEXPTYPE::NILSXP {
887 Ok(None)
888 } else {
889 Vec::<T>::try_from_sexp(sexp).map(Some).map_err(Into::into)
890 }
891 }
892
893 #[inline]
894 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
895 if sexp.type_of() == SEXPTYPE::NILSXP {
896 Ok(None)
897 } else {
898 unsafe {
899 Vec::<T>::try_from_sexp_unchecked(sexp)
900 .map(Some)
901 .map_err(Into::into)
902 }
903 }
904 }
905}
906
907macro_rules! impl_option_map_try_from_sexp {
908 ($(#[$meta:meta])* $map_ty:ident) => {
909 $(#[$meta])*
910 impl<V: TryFromSexp> TryFromSexp for Option<$map_ty<String, V>>
911 where
912 V::Error: Into<SexpError>,
913 {
914 type Error = SexpError;
915
916 #[inline]
917 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
918 if sexp.type_of() == SEXPTYPE::NILSXP {
919 Ok(None)
920 } else {
921 $map_ty::<String, V>::try_from_sexp(sexp).map(Some)
922 }
923 }
924 }
925 };
926}
927
928impl_option_map_try_from_sexp!(
929 HashMap
931);
932impl_option_map_try_from_sexp!(
933 BTreeMap
935);
936
937macro_rules! impl_option_set_try_from_sexp {
938 ($(#[$meta:meta])* $set_ty:ident) => {
939 $(#[$meta])*
940 impl<T> TryFromSexp for Option<$set_ty<T>>
941 where
942 $set_ty<T>: TryFromSexp,
943 <$set_ty<T> as TryFromSexp>::Error: Into<SexpError>,
944 {
945 type Error = SexpError;
946
947 #[inline]
948 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
949 if sexp.type_of() == SEXPTYPE::NILSXP {
950 Ok(None)
951 } else {
952 $set_ty::<T>::try_from_sexp(sexp)
953 .map(Some)
954 .map_err(Into::into)
955 }
956 }
957 }
958 };
959}
960
961impl_option_set_try_from_sexp!(
962 HashSet
964);
965impl_option_set_try_from_sexp!(
966 BTreeSet
968);
969impl<T> TryFromSexp for Vec<Vec<T>>
977where
978 Vec<T>: TryFromSexp,
979 <Vec<T> as TryFromSexp>::Error: Into<SexpError>,
980{
981 type Error = SexpError;
982
983 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
984 map_vecsxp_with(sexp, |_i, elem| {
985 Vec::<T>::try_from_sexp(elem).map_err(Into::into)
986 })
987 }
988
989 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
990 unsafe {
991 map_vecsxp_with_unchecked(sexp, |_i, elem| {
992 Vec::<T>::try_from_sexp_unchecked(elem).map_err(Into::into)
993 })
994 }
995 }
996}
997use crate::coerce::Coerced;
1002
1003impl<T, R> TryFromSexp for Coerced<T, R>
1017where
1018 R: TryFromSexp,
1019 R: TryCoerce<T>,
1020 <R as TryFromSexp>::Error: Into<SexpError>,
1021 <R as TryCoerce<T>>::Error: std::fmt::Debug,
1022{
1023 type Error = SexpError;
1024
1025 #[inline]
1026 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1027 let r_val: R = R::try_from_sexp(sexp).map_err(Into::into)?;
1028 let value: T = r_val
1029 .try_coerce()
1030 .map_err(|e| SexpError::InvalidValue(format!("{e:?}")))?;
1031 Ok(Coerced::new(value))
1032 }
1033
1034 #[inline]
1035 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1036 let r_val: R = unsafe { R::try_from_sexp_unchecked(sexp).map_err(Into::into)? };
1037 let value: T = r_val
1038 .try_coerce()
1039 .map_err(|e| SexpError::InvalidValue(format!("{e:?}")))?;
1040 Ok(Coerced::new(value))
1041 }
1042}
1043#[inline]
1053fn coerce_slice_to_vec<R, T>(slice: &[R]) -> Result<Vec<T>, SexpError>
1054where
1055 R: Copy + TryCoerce<T>,
1056 <R as TryCoerce<T>>::Error: std::fmt::Debug,
1057{
1058 slice
1059 .iter()
1060 .copied()
1061 .map(|v| {
1062 v.try_coerce()
1063 .map_err(|e| SexpError::InvalidValue(format!("{e:?}")))
1064 })
1065 .collect()
1066}
1067
1068#[inline]
1077pub(crate) fn from_numeric_vec_with<U, FI, FD, FR, FL>(
1078 sexp: SEXP,
1079 map_i32: FI,
1080 map_f64: FD,
1081 map_u8: FR,
1082 map_lgl: FL,
1083) -> Result<Vec<U>, SexpError>
1084where
1085 FI: Fn(i32) -> Result<U, SexpError>,
1086 FD: Fn(f64) -> Result<U, SexpError>,
1087 FR: Fn(u8) -> Result<U, SexpError>,
1088 FL: Fn(RLogical) -> Result<U, SexpError>,
1089{
1090 let actual = sexp.type_of();
1091 match actual {
1092 SEXPTYPE::INTSXP => {
1093 let slice: &[i32] = unsafe { sexp.as_slice() };
1094 slice.iter().copied().map(map_i32).collect()
1095 }
1096 SEXPTYPE::REALSXP => {
1097 let slice: &[f64] = unsafe { sexp.as_slice() };
1098 slice.iter().copied().map(map_f64).collect()
1099 }
1100 SEXPTYPE::RAWSXP => {
1101 let slice: &[u8] = unsafe { sexp.as_slice() };
1102 slice.iter().copied().map(map_u8).collect()
1103 }
1104 SEXPTYPE::LGLSXP => {
1105 let slice: &[RLogical] = unsafe { sexp.as_slice() };
1106 slice.iter().copied().map(map_lgl).collect()
1107 }
1108 _ => Err(SexpError::InvalidValue(format!(
1109 "expected integer, numeric, logical, or raw; got {:?}",
1110 actual
1111 ))),
1112 }
1113}
1114
1115#[inline]
1130pub(crate) fn map_strsxp_with<U>(
1131 sexp: SEXP,
1132 mut map: impl FnMut(SEXP , usize) -> Result<U, SexpError>,
1133) -> Result<Vec<U>, SexpError> {
1134 let actual = sexp.type_of();
1135 if actual != SEXPTYPE::STRSXP {
1136 return Err(SexpTypeError {
1137 expected: SEXPTYPE::STRSXP,
1138 actual,
1139 }
1140 .into());
1141 }
1142
1143 let len = sexp.len();
1144 let mut result = Vec::with_capacity(len);
1145 for i in 0..len {
1146 let charsxp = sexp.string_elt(i as crate::R_xlen_t);
1147 result.push(map(charsxp, i)?);
1148 }
1149 Ok(result)
1150}
1151
1152#[inline]
1160pub(crate) fn scalar_charsxp(sexp: SEXP) -> Result<SEXP, SexpError> {
1161 let actual = sexp.type_of();
1162 if actual != SEXPTYPE::STRSXP {
1163 return Err(SexpTypeError {
1164 expected: SEXPTYPE::STRSXP,
1165 actual,
1166 }
1167 .into());
1168 }
1169
1170 let len = sexp.len();
1171 if len != 1 {
1172 return Err(SexpLengthError {
1173 expected: 1,
1174 actual: len,
1175 }
1176 .into());
1177 }
1178
1179 Ok(sexp.string_elt(0))
1180}
1181
1182#[inline]
1190pub(crate) unsafe fn scalar_charsxp_unchecked(sexp: SEXP) -> Result<SEXP, SexpError> {
1191 let actual = sexp.type_of();
1192 if actual != SEXPTYPE::STRSXP {
1193 return Err(SexpTypeError {
1194 expected: SEXPTYPE::STRSXP,
1195 actual,
1196 }
1197 .into());
1198 }
1199
1200 let len = unsafe { sexp.len_unchecked() };
1201 if len != 1 {
1202 return Err(SexpLengthError {
1203 expected: 1,
1204 actual: len,
1205 }
1206 .into());
1207 }
1208
1209 Ok(unsafe { sexp.string_elt_unchecked(0) })
1210}
1211
1212#[inline]
1220pub(crate) fn map_vecsxp_with<U>(
1221 sexp: SEXP,
1222 mut map: impl FnMut(usize, SEXP) -> Result<U, SexpError>,
1223) -> Result<Vec<U>, SexpError> {
1224 let actual = sexp.type_of();
1225 if actual != SEXPTYPE::VECSXP {
1226 return Err(SexpTypeError {
1227 expected: SEXPTYPE::VECSXP,
1228 actual,
1229 }
1230 .into());
1231 }
1232
1233 let len = sexp.len();
1234 let mut result = Vec::with_capacity(len);
1235 for i in 0..len {
1236 let elem = sexp.vector_elt(i as crate::R_xlen_t);
1237 result.push(map(i, elem)?);
1238 }
1239 Ok(result)
1240}
1241
1242#[inline]
1250pub(crate) unsafe fn map_vecsxp_with_unchecked<U>(
1251 sexp: SEXP,
1252 mut map: impl FnMut(usize, SEXP) -> Result<U, SexpError>,
1253) -> Result<Vec<U>, SexpError> {
1254 let actual = sexp.type_of();
1255 if actual != SEXPTYPE::VECSXP {
1256 return Err(SexpTypeError {
1257 expected: SEXPTYPE::VECSXP,
1258 actual,
1259 }
1260 .into());
1261 }
1262
1263 let len = unsafe { sexp.len_unchecked() };
1264 let mut result = Vec::with_capacity(len);
1265 for i in 0..len {
1266 let elem = unsafe { sexp.vector_elt_unchecked(i as crate::R_xlen_t) };
1267 result.push(map(i, elem)?);
1268 }
1269 Ok(result)
1270}
1271
1272#[inline]
1277fn try_from_sexp_numeric_vec<T>(sexp: SEXP) -> Result<Vec<T>, SexpError>
1278where
1279 i32: TryCoerce<T>,
1280 f64: TryCoerce<T>,
1281 u8: TryCoerce<T>,
1282 <i32 as TryCoerce<T>>::Error: std::fmt::Debug,
1283 <f64 as TryCoerce<T>>::Error: std::fmt::Debug,
1284 <u8 as TryCoerce<T>>::Error: std::fmt::Debug,
1285{
1286 from_numeric_vec_with(
1287 sexp,
1288 coerce_value,
1289 coerce_value,
1290 coerce_value,
1291 |v: RLogical| coerce_value(v.to_i32()),
1292 )
1293}
1294
1295macro_rules! impl_vec_try_from_sexp_numeric {
1297 ($target:ty) => {
1298 impl TryFromSexp for Vec<$target> {
1299 type Error = SexpError;
1300
1301 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1302 try_from_sexp_numeric_vec(sexp)
1303 }
1304
1305 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1306 try_from_sexp_numeric_vec(sexp)
1307 }
1308 }
1309 };
1310}
1311
1312impl_vec_try_from_sexp_numeric!(i8);
1313impl_vec_try_from_sexp_numeric!(i16);
1314impl_vec_try_from_sexp_numeric!(i64);
1315impl_vec_try_from_sexp_numeric!(isize);
1316impl_vec_try_from_sexp_numeric!(u16);
1317impl_vec_try_from_sexp_numeric!(u32);
1318impl_vec_try_from_sexp_numeric!(u64);
1319impl_vec_try_from_sexp_numeric!(usize);
1320impl_vec_try_from_sexp_numeric!(f32);
1321
1322impl TryFromSexp for Vec<bool> {
1324 type Error = SexpError;
1325
1326 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1327 let actual = sexp.type_of();
1328 if actual != SEXPTYPE::LGLSXP {
1329 return Err(SexpTypeError {
1330 expected: SEXPTYPE::LGLSXP,
1331 actual,
1332 }
1333 .into());
1334 }
1335 let slice: &[RLogical] = unsafe { sexp.as_slice() };
1336 coerce_slice_to_vec(slice)
1337 }
1338
1339 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1340 Self::try_from_sexp(sexp)
1341 }
1342}
1343#[inline]
1349fn try_from_sexp_numeric_set<T, S>(sexp: SEXP) -> Result<S, SexpError>
1350where
1351 S: std::iter::FromIterator<T>,
1352 i32: TryCoerce<T>,
1353 f64: TryCoerce<T>,
1354 u8: TryCoerce<T>,
1355 <i32 as TryCoerce<T>>::Error: std::fmt::Debug,
1356 <f64 as TryCoerce<T>>::Error: std::fmt::Debug,
1357 <u8 as TryCoerce<T>>::Error: std::fmt::Debug,
1358{
1359 let vec = try_from_sexp_numeric_vec(sexp)?;
1360 Ok(vec.into_iter().collect())
1361}
1362
1363macro_rules! impl_set_try_from_sexp_numeric {
1364 ($set_ty:ident, $target:ty) => {
1365 impl TryFromSexp for $set_ty<$target> {
1366 type Error = SexpError;
1367
1368 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1369 try_from_sexp_numeric_set(sexp)
1370 }
1371
1372 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1373 try_from_sexp_numeric_set(sexp)
1374 }
1375 }
1376 };
1377}
1378
1379impl_set_try_from_sexp_numeric!(HashSet, i8);
1380impl_set_try_from_sexp_numeric!(HashSet, i16);
1381impl_set_try_from_sexp_numeric!(HashSet, i64);
1382impl_set_try_from_sexp_numeric!(HashSet, isize);
1383impl_set_try_from_sexp_numeric!(HashSet, u16);
1384impl_set_try_from_sexp_numeric!(HashSet, u32);
1385impl_set_try_from_sexp_numeric!(HashSet, u64);
1386impl_set_try_from_sexp_numeric!(HashSet, usize);
1387
1388impl_set_try_from_sexp_numeric!(BTreeSet, i8);
1389impl_set_try_from_sexp_numeric!(BTreeSet, i16);
1390impl_set_try_from_sexp_numeric!(BTreeSet, i64);
1391impl_set_try_from_sexp_numeric!(BTreeSet, isize);
1392impl_set_try_from_sexp_numeric!(BTreeSet, u16);
1393impl_set_try_from_sexp_numeric!(BTreeSet, u32);
1394impl_set_try_from_sexp_numeric!(BTreeSet, u64);
1395impl_set_try_from_sexp_numeric!(BTreeSet, usize);
1396
1397macro_rules! impl_set_try_from_sexp_bool {
1398 ($set_ty:ident) => {
1399 impl TryFromSexp for $set_ty<bool> {
1400 type Error = SexpError;
1401
1402 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1403 let vec: Vec<bool> = TryFromSexp::try_from_sexp(sexp)?;
1404 Ok(vec.into_iter().collect())
1405 }
1406
1407 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1408 Self::try_from_sexp(sexp)
1409 }
1410 }
1411 };
1412}
1413
1414impl_set_try_from_sexp_bool!(HashSet);
1415impl_set_try_from_sexp_bool!(BTreeSet);
1416use crate::externalptr::{ExternalPtr, TypeMismatchError, TypedExternal};
1421
1422fn type_mismatch_to_sexp_error(e: TypeMismatchError) -> SexpError {
1426 match e {
1427 TypeMismatchError::NullPointer => {
1428 SexpError::InvalidValue("external pointer is null".to_string())
1429 }
1430 TypeMismatchError::InvalidTypeId => {
1431 SexpError::InvalidValue("external pointer has no valid type id".to_string())
1432 }
1433 TypeMismatchError::Mismatch { expected, found } => SexpError::InvalidValue(format!(
1434 "type mismatch: expected `{}`, found `{}`",
1435 expected, found
1436 )),
1437 }
1438}
1439
1440fn not_a_handle_error(actual: SEXPTYPE) -> SexpError {
1445 SexpError::InvalidValue(format!(
1446 "expected an external pointer or a miniextendr class object wrapping one, got {:?}",
1447 actual
1448 ))
1449}
1450
1451impl<T: TypedExternal + Send> TryFromSexp for ExternalPtr<T> {
1467 type Error = SexpError;
1468
1469 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1470 let actual = sexp.type_of();
1471 if actual != SEXPTYPE::EXTPTRSXP {
1472 return match unsafe { crate::externalptr::unwrap_class_handle(sexp) } {
1476 Some(inner) => unsafe { ExternalPtr::wrap_sexp_with_error(inner) }
1477 .map_err(type_mismatch_to_sexp_error),
1478 None => Err(not_a_handle_error(actual)),
1479 };
1480 }
1481
1482 unsafe { ExternalPtr::wrap_sexp_with_error(sexp) }.map_err(type_mismatch_to_sexp_error)
1484 }
1485
1486 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1487 let actual = sexp.type_of();
1488 if actual != SEXPTYPE::EXTPTRSXP {
1489 return match unsafe { crate::externalptr::unwrap_class_handle(sexp) } {
1490 Some(inner) => {
1491 unsafe { ExternalPtr::wrap_sexp_unchecked(inner) }.ok_or_else(|| {
1492 SexpError::InvalidValue(
1493 "failed to convert external pointer: type mismatch or null pointer"
1494 .to_string(),
1495 )
1496 })
1497 }
1498 None => Err(not_a_handle_error(actual)),
1499 };
1500 }
1501
1502 unsafe { ExternalPtr::wrap_sexp_unchecked(sexp) }.ok_or_else(|| {
1504 SexpError::InvalidValue(
1505 "failed to convert external pointer: type mismatch or null pointer".to_string(),
1506 )
1507 })
1508 }
1509}
1510
1511impl<T: TypedExternal + Send> TryFromSexp for Option<ExternalPtr<T>> {
1512 type Error = SexpError;
1513
1514 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1515 if sexp.type_of() == SEXPTYPE::NILSXP {
1516 return Ok(None);
1517 }
1518 let ptr: ExternalPtr<T> = TryFromSexp::try_from_sexp(sexp)?;
1519 Ok(Some(ptr))
1520 }
1521
1522 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1523 if sexp.type_of() == SEXPTYPE::NILSXP {
1524 return Ok(None);
1525 }
1526 let ptr: ExternalPtr<T> = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
1527 Ok(Some(ptr))
1528 }
1529}
1530
1531impl<T: TypedExternal + Send> TryFromSexp for Vec<ExternalPtr<T>> {
1541 type Error = SexpError;
1542
1543 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1544 map_vecsxp_with(sexp, |_i, elem| {
1545 <ExternalPtr<T> as TryFromSexp>::try_from_sexp(elem)
1546 })
1547 }
1548
1549 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1550 unsafe {
1551 map_vecsxp_with_unchecked(sexp, |_i, elem| {
1552 <ExternalPtr<T> as TryFromSexp>::try_from_sexp_unchecked(elem)
1553 })
1554 }
1555 }
1556}
1557
1558impl<T: TypedExternal + Send> TryFromSexp for Vec<Option<ExternalPtr<T>>> {
1562 type Error = SexpError;
1563
1564 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1565 map_vecsxp_with(sexp, |_i, elem| {
1566 <Option<ExternalPtr<T>> as TryFromSexp>::try_from_sexp(elem)
1567 })
1568 }
1569
1570 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1571 unsafe {
1572 map_vecsxp_with_unchecked(sexp, |_i, elem| {
1573 <Option<ExternalPtr<T>> as TryFromSexp>::try_from_sexp_unchecked(elem)
1574 })
1575 }
1576 }
1577}
1578#[cfg(feature = "connections")]
1583mod connections_from_r {
1584 use std::ffi::CStr;
1585
1586 use crate::connection::{RNullConnection, RStderr, RStdin, RStdout, Rconn};
1587 use crate::from_r::{SexpError, TryFromSexp};
1588 use crate::{Rboolean, SEXP};
1589
1590 unsafe fn conn_description(sexp: SEXP) -> Option<String> {
1596 unsafe {
1597 let handle = crate::sys::R_GetConnection(sexp);
1598 let conn = handle.cast::<Rconn>().cast_const();
1599 if (*conn).description.is_null() {
1600 None
1601 } else {
1602 Some(
1603 CStr::from_ptr((*conn).description)
1604 .to_string_lossy()
1605 .into_owned(),
1606 )
1607 }
1608 }
1609 }
1610
1611 unsafe fn conn_class(sexp: SEXP) -> Option<String> {
1612 unsafe {
1613 let handle = crate::sys::R_GetConnection(sexp);
1614 let conn = handle.cast::<Rconn>().cast_const();
1615 if (*conn).class.is_null() {
1616 None
1617 } else {
1618 Some(CStr::from_ptr((*conn).class).to_string_lossy().into_owned())
1619 }
1620 }
1621 }
1622
1623 unsafe fn conn_canwrite(sexp: SEXP) -> bool {
1624 unsafe {
1625 let handle = crate::sys::R_GetConnection(sexp);
1626 let conn = handle.cast::<Rconn>().cast_const();
1627 (*conn).canwrite != Rboolean::FALSE
1628 }
1629 }
1630
1631 unsafe fn conn_isopen(sexp: SEXP) -> bool {
1632 unsafe {
1633 let handle = crate::sys::R_GetConnection(sexp);
1634 let conn = handle.cast::<Rconn>().cast_const();
1635 (*conn).isopen != Rboolean::FALSE
1636 }
1637 }
1638
1639 unsafe fn validate_terminal(sexp: SEXP, expected_desc: &str) -> Result<(), SexpError> {
1641 let desc = unsafe { conn_description(sexp) }.unwrap_or_default();
1642 if desc != expected_desc {
1643 return Err(SexpError::InvalidValue(format!(
1644 "expected terminal connection with description {:?}, got {:?}",
1645 expected_desc, desc
1646 )));
1647 }
1648 let cls = unsafe { conn_class(sexp) }.unwrap_or_default();
1649 if cls != "terminal" {
1650 return Err(SexpError::InvalidValue(format!(
1651 "expected class \"terminal\", got {:?}",
1652 cls
1653 )));
1654 }
1655 Ok(())
1656 }
1657
1658 impl TryFromSexp for RStdin {
1659 type Error = SexpError;
1660
1661 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1662 unsafe { validate_terminal(sexp, "stdin") }?;
1663 Ok(RStdin)
1664 }
1665
1666 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1667 Self::try_from_sexp(sexp)
1668 }
1669 }
1670
1671 impl TryFromSexp for RStdout {
1672 type Error = SexpError;
1673
1674 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1675 unsafe { validate_terminal(sexp, "stdout") }?;
1676 Ok(RStdout)
1677 }
1678
1679 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1680 Self::try_from_sexp(sexp)
1681 }
1682 }
1683
1684 impl TryFromSexp for RStderr {
1685 type Error = SexpError;
1686
1687 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1688 unsafe { validate_terminal(sexp, "stderr") }?;
1689 Ok(RStderr)
1690 }
1691
1692 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1693 Self::try_from_sexp(sexp)
1694 }
1695 }
1696
1697 impl TryFromSexp for RNullConnection {
1704 type Error = SexpError;
1705
1706 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1707 if !unsafe { conn_isopen(sexp) } {
1708 return Err(SexpError::InvalidValue(
1709 "expected an open connection".to_string(),
1710 ));
1711 }
1712 if !unsafe { conn_canwrite(sexp) } {
1713 return Err(SexpError::InvalidValue(
1714 "expected a write-capable connection".to_string(),
1715 ));
1716 }
1717 unsafe { crate::sys::R_PreserveObject(sexp) };
1719 Ok(unsafe { RNullConnection::from_preserved_sexp(sexp) })
1720 }
1721
1722 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1723 Self::try_from_sexp(sexp)
1724 }
1725 }
1726}
1727
1728#[cfg(feature = "connections")]
1733mod txt_progress_bar_from_r {
1734 use crate::from_r::{SexpError, TryFromSexp};
1735 use crate::sys::R_PreserveObject;
1736 use crate::txt_progress_bar::RTxtProgressBar;
1737 use crate::{SEXP, SexpExt};
1738
1739 impl TryFromSexp for RTxtProgressBar {
1740 type Error = SexpError;
1741
1742 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1743 if !sexp.inherits_class(c"txtProgressBar") {
1745 return Err(SexpError::InvalidValue(
1746 "expected a SEXP with class \"txtProgressBar\"".to_string(),
1747 ));
1748 }
1749 unsafe { R_PreserveObject(sexp) };
1751 Ok(unsafe { RTxtProgressBar::from_preserved_sexp(sexp) })
1752 }
1753
1754 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1755 Self::try_from_sexp(sexp)
1756 }
1757 }
1758}
1759
1760#[macro_export]
1768macro_rules! impl_option_try_from_sexp {
1769 ($t:ty) => {
1770 impl $crate::from_r::TryFromSexp for Option<$t> {
1771 type Error = $crate::from_r::SexpError;
1772
1773 fn try_from_sexp(sexp: $crate::SEXP) -> Result<Self, Self::Error> {
1774 use $crate::{SEXPTYPE, SexpExt};
1775 if sexp.type_of() == SEXPTYPE::NILSXP {
1776 return Ok(None);
1777 }
1778 <$t as $crate::from_r::TryFromSexp>::try_from_sexp(sexp).map(Some)
1779 }
1780
1781 unsafe fn try_from_sexp_unchecked(sexp: $crate::SEXP) -> Result<Self, Self::Error> {
1782 use $crate::{SEXPTYPE, SexpExt};
1783 if sexp.type_of() == SEXPTYPE::NILSXP {
1784 return Ok(None);
1785 }
1786 unsafe {
1787 <$t as $crate::from_r::TryFromSexp>::try_from_sexp_unchecked(sexp).map(Some)
1788 }
1789 }
1790 }
1791 };
1792}
1793
1794#[macro_export]
1798macro_rules! impl_vec_try_from_sexp_list {
1799 ($t:ty) => {
1800 impl $crate::from_r::TryFromSexp for Vec<$t> {
1801 type Error = $crate::from_r::SexpError;
1802
1803 fn try_from_sexp(sexp: $crate::SEXP) -> Result<Self, Self::Error> {
1804 use $crate::from_r::SexpTypeError;
1805 use $crate::{SEXPTYPE, SexpExt};
1806
1807 let actual = sexp.type_of();
1808 if actual != SEXPTYPE::VECSXP {
1809 return Err(SexpTypeError {
1810 expected: SEXPTYPE::VECSXP,
1811 actual,
1812 }
1813 .into());
1814 }
1815
1816 let len = sexp.len();
1817 let mut result = Vec::with_capacity(len);
1818 for i in 0..len {
1819 let elem = sexp.vector_elt(i as $crate::R_xlen_t);
1820 result.push(<$t as $crate::from_r::TryFromSexp>::try_from_sexp(elem)?);
1821 }
1822 Ok(result)
1823 }
1824
1825 unsafe fn try_from_sexp_unchecked(sexp: $crate::SEXP) -> Result<Self, Self::Error> {
1826 use $crate::from_r::SexpTypeError;
1827 use $crate::{SEXPTYPE, SexpExt};
1828
1829 let actual = sexp.type_of();
1830 if actual != SEXPTYPE::VECSXP {
1831 return Err(SexpTypeError {
1832 expected: SEXPTYPE::VECSXP,
1833 actual,
1834 }
1835 .into());
1836 }
1837
1838 let len = unsafe { sexp.len_unchecked() };
1839 let mut result = Vec::with_capacity(len);
1840 for i in 0..len {
1841 let elem = unsafe { sexp.vector_elt_unchecked(i as $crate::R_xlen_t) };
1842 result.push(unsafe {
1843 <$t as $crate::from_r::TryFromSexp>::try_from_sexp_unchecked(elem)?
1844 });
1845 }
1846 Ok(result)
1847 }
1848 }
1849 };
1850}
1851
1852#[macro_export]
1856macro_rules! impl_vec_option_try_from_sexp_list {
1857 ($t:ty) => {
1858 impl $crate::from_r::TryFromSexp for Vec<Option<$t>> {
1859 type Error = $crate::from_r::SexpError;
1860
1861 fn try_from_sexp(sexp: $crate::SEXP) -> Result<Self, Self::Error> {
1862 use $crate::from_r::SexpTypeError;
1863 use $crate::{SEXPTYPE, SexpExt};
1864
1865 let actual = sexp.type_of();
1866 if actual != SEXPTYPE::VECSXP {
1867 return Err(SexpTypeError {
1868 expected: SEXPTYPE::VECSXP,
1869 actual,
1870 }
1871 .into());
1872 }
1873
1874 let len = sexp.len();
1875 let mut result = Vec::with_capacity(len);
1876 for i in 0..len {
1877 let elem = sexp.vector_elt(i as $crate::R_xlen_t);
1878 if elem == $crate::SEXP::nil() {
1879 result.push(None);
1880 } else {
1881 result.push(Some(<$t as $crate::from_r::TryFromSexp>::try_from_sexp(
1882 elem,
1883 )?));
1884 }
1885 }
1886 Ok(result)
1887 }
1888
1889 unsafe fn try_from_sexp_unchecked(sexp: $crate::SEXP) -> Result<Self, Self::Error> {
1890 use $crate::from_r::SexpTypeError;
1891 use $crate::{SEXPTYPE, SexpExt};
1892
1893 let actual = sexp.type_of();
1894 if actual != SEXPTYPE::VECSXP {
1895 return Err(SexpTypeError {
1896 expected: SEXPTYPE::VECSXP,
1897 actual,
1898 }
1899 .into());
1900 }
1901
1902 let len = unsafe { sexp.len_unchecked() };
1903 let mut result = Vec::with_capacity(len);
1904 for i in 0..len {
1905 let elem = unsafe { sexp.vector_elt_unchecked(i as $crate::R_xlen_t) };
1906 if elem == $crate::SEXP::nil() {
1907 result.push(None);
1908 } else {
1909 result.push(Some(unsafe {
1910 <$t as $crate::from_r::TryFromSexp>::try_from_sexp_unchecked(elem)?
1911 }));
1912 }
1913 }
1914 Ok(result)
1915 }
1916 }
1917 };
1918}
1919
1920const BATCHED_ERROR_CAP: usize = 10;
1923
1924#[doc(hidden)]
1938pub fn batch_conversion_errors(container: &str, errors: Vec<String>) -> SexpError {
1939 debug_assert!(!errors.is_empty(), "batching zero conversion errors");
1940 let total = errors.len();
1941 let mut msg = format!(
1942 "{container} conversion failed: {}",
1943 errors[..total.min(BATCHED_ERROR_CAP)].join("; ")
1944 );
1945 if total > BATCHED_ERROR_CAP {
1946 use std::fmt::Write;
1947 let _ = write!(msg, "; and {} more", total - BATCHED_ERROR_CAP);
1948 }
1949 SexpError::InvalidValue(msg)
1950}
1951
1952#[macro_export]
1980macro_rules! try_from_sexp_via_str_parse {
1981 ($ty:ty, $label:literal, |$s:ident| $parse:expr) => {
1982 impl $crate::from_r::TryFromSexp for $ty {
1983 type Error = $crate::from_r::SexpError;
1984
1985 fn try_from_sexp(sexp: $crate::SEXP) -> Result<Self, Self::Error> {
1986 let opt: Option<String> = $crate::from_r::TryFromSexp::try_from_sexp(sexp)?;
1987 let s = opt.ok_or($crate::from_r::SexpError::Na($crate::from_r::SexpNaError {
1988 sexp_type: $crate::SEXPTYPE::STRSXP,
1989 }))?;
1990 let $s: &str = &s;
1991 ($parse).map_err(|e| {
1992 $crate::from_r::SexpError::InvalidValue(format!(
1993 concat!("invalid ", $label, ": {}"),
1994 e
1995 ))
1996 })
1997 }
1998 }
1999
2000 impl $crate::from_r::TryFromSexp for Option<$ty> {
2001 type Error = $crate::from_r::SexpError;
2002
2003 fn try_from_sexp(sexp: $crate::SEXP) -> Result<Self, Self::Error> {
2004 let opt: Option<String> = $crate::from_r::TryFromSexp::try_from_sexp(sexp)?;
2005 match opt {
2006 None => Ok(None),
2007 Some(s) => {
2008 let $s: &str = &s;
2009 ($parse).map(Some).map_err(|e| {
2010 $crate::from_r::SexpError::InvalidValue(format!(
2011 concat!("invalid ", $label, ": {}"),
2012 e
2013 ))
2014 })
2015 }
2016 }
2017 }
2018 }
2019
2020 impl $crate::from_r::TryFromSexp for Vec<$ty> {
2021 type Error = $crate::from_r::SexpError;
2022
2023 fn try_from_sexp(sexp: $crate::SEXP) -> Result<Self, Self::Error> {
2024 let values: Vec<Option<String>> = $crate::from_r::TryFromSexp::try_from_sexp(sexp)?;
2025 let mut result = Vec::with_capacity(values.len());
2026 let mut errors: Vec<String> = Vec::new();
2027 for (i, opt) in values.into_iter().enumerate() {
2028 match opt {
2029 None => errors.push(format!(
2030 concat!("NA at index {} not allowed for Vec<", stringify!($ty), ">"),
2031 i
2032 )),
2033 Some(s) => {
2034 let $s: &str = &s;
2035 match ($parse) {
2036 Ok(v) => result.push(v),
2037 Err(e) => errors.push(format!(
2038 concat!("invalid ", $label, " at index {}: {}"),
2039 i, e
2040 )),
2041 }
2042 }
2043 }
2044 }
2045 if errors.is_empty() {
2046 Ok(result)
2047 } else {
2048 Err($crate::from_r::batch_conversion_errors(
2049 concat!("Vec<", stringify!($ty), ">"),
2050 errors,
2051 ))
2052 }
2053 }
2054 }
2055
2056 impl $crate::from_r::TryFromSexp for Vec<Option<$ty>> {
2057 type Error = $crate::from_r::SexpError;
2058
2059 fn try_from_sexp(sexp: $crate::SEXP) -> Result<Self, Self::Error> {
2060 let values: Vec<Option<String>> = $crate::from_r::TryFromSexp::try_from_sexp(sexp)?;
2061 let mut result = Vec::with_capacity(values.len());
2062 let mut errors: Vec<String> = Vec::new();
2063 for (i, opt) in values.into_iter().enumerate() {
2064 match opt {
2065 None => result.push(None),
2066 Some(s) => {
2067 let $s: &str = &s;
2068 match ($parse) {
2069 Ok(v) => result.push(Some(v)),
2070 Err(e) => errors.push(format!(
2071 concat!("invalid ", $label, " at index {}: {}"),
2072 i, e
2073 )),
2074 }
2075 }
2076 }
2077 }
2078 if errors.is_empty() {
2079 Ok(result)
2080 } else {
2081 Err($crate::from_r::batch_conversion_errors(
2082 concat!("Vec<Option<", stringify!($ty), ">>"),
2083 errors,
2084 ))
2085 }
2086 }
2087 }
2088 };
2089}
2090