1#![allow(rustdoc::private_intra_doc_links)]
2use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
39
40use crate::altrep_traits::NA_REAL;
41use crate::coerce::TryCoerce;
42use crate::ffi::{RLogical, SEXP, SEXPTYPE, SexpExt};
43
44#[inline]
50pub(crate) fn is_na_real(value: f64) -> bool {
51 value.to_bits() == NA_REAL.to_bits()
52}
53
54#[inline]
67pub(crate) unsafe fn charsxp_to_str(charsxp: SEXP) -> &'static str {
68 unsafe { charsxp_to_str_impl(charsxp.r_char(), charsxp) }
69}
70
71#[inline]
73pub(crate) unsafe fn charsxp_to_str_unchecked(charsxp: SEXP) -> &'static str {
74 unsafe { charsxp_to_str_impl(charsxp.r_char_unchecked(), charsxp) }
75}
76
77#[inline]
81unsafe fn charsxp_to_str_impl(ptr: *const std::os::raw::c_char, charsxp: SEXP) -> &'static str {
82 unsafe {
83 let len: usize = charsxp.len();
84 let bytes = r_slice(ptr.cast::<u8>(), len);
85 debug_assert!(
88 std::str::from_utf8(bytes).is_ok(),
89 "CHARSXP contains non-UTF-8 bytes (locale assertion may have been skipped)"
90 );
91 std::str::from_utf8_unchecked(bytes)
92 }
93}
94
95#[inline]
98pub(crate) unsafe fn charsxp_to_cow(charsxp: SEXP) -> std::borrow::Cow<'static, str> {
99 std::borrow::Cow::Borrowed(unsafe { charsxp_to_str(charsxp) })
100}
101
102#[inline(always)]
115pub(crate) unsafe fn r_slice<'a, T>(ptr: *const T, len: usize) -> &'a [T] {
116 if len == 0 {
117 &[]
118 } else {
119 unsafe { std::slice::from_raw_parts(ptr, len) }
120 }
121}
122
123#[inline(always)]
129pub(crate) unsafe fn r_slice_mut<'a, T>(ptr: *mut T, len: usize) -> &'a mut [T] {
130 if len == 0 {
131 &mut []
132 } else {
133 unsafe { std::slice::from_raw_parts_mut(ptr, len) }
134 }
135}
136
137#[derive(Debug, Clone, Copy)]
138pub struct SexpTypeError {
140 pub expected: SEXPTYPE,
142 pub actual: SEXPTYPE,
144}
145
146impl std::fmt::Display for SexpTypeError {
147 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
148 write!(
149 f,
150 "type mismatch: expected {:?}, got {:?}",
151 self.expected, self.actual
152 )
153 }
154}
155
156impl std::error::Error for SexpTypeError {}
157
158#[derive(Debug, Clone, Copy)]
159pub struct SexpLengthError {
161 pub expected: usize,
163 pub actual: usize,
165}
166
167impl std::fmt::Display for SexpLengthError {
168 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
169 write!(
170 f,
171 "length mismatch: expected {}, got {}",
172 self.expected, self.actual
173 )
174 }
175}
176
177impl std::error::Error for SexpLengthError {}
178
179#[derive(Debug, Clone, Copy)]
180pub struct SexpNaError {
182 pub sexp_type: SEXPTYPE,
184}
185
186impl std::fmt::Display for SexpNaError {
187 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
188 write!(f, "unexpected NA value in {:?}", self.sexp_type)
189 }
190}
191
192impl std::error::Error for SexpNaError {}
193
194#[derive(Debug, Clone)]
195pub enum SexpError {
197 Type(SexpTypeError),
199 Length(SexpLengthError),
201 Na(SexpNaError),
203 InvalidValue(String),
205 MissingField(String),
207 DuplicateName(String),
209 #[cfg(feature = "either")]
213 EitherConversion {
214 left_error: String,
216 right_error: String,
218 },
219}
220
221impl std::fmt::Display for SexpError {
222 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
223 match self {
224 SexpError::Type(e) => write!(f, "{}", e),
225 SexpError::Length(e) => write!(f, "{}", e),
226 SexpError::Na(e) => write!(f, "{}", e),
227 SexpError::InvalidValue(msg) => write!(f, "invalid value: {}", msg),
228 SexpError::MissingField(name) => write!(f, "missing field: {}", name),
229 SexpError::DuplicateName(name) => write!(f, "duplicate name in list: {:?}", name),
230 #[cfg(feature = "either")]
231 SexpError::EitherConversion {
232 left_error,
233 right_error,
234 } => write!(
235 f,
236 "failed to convert to Either: Left failed ({}), Right failed ({})",
237 left_error, right_error
238 ),
239 }
240 }
241}
242
243impl std::error::Error for SexpError {
244 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
245 match self {
246 SexpError::Type(e) => Some(e),
247 SexpError::Length(e) => Some(e),
248 SexpError::Na(e) => Some(e),
249 SexpError::InvalidValue(_) => None,
250 SexpError::MissingField(_) => None,
251 SexpError::DuplicateName(_) => None,
252 #[cfg(feature = "either")]
253 SexpError::EitherConversion { .. } => None,
254 }
255 }
256}
257
258impl From<SexpTypeError> for SexpError {
259 fn from(e: SexpTypeError) -> Self {
260 SexpError::Type(e)
261 }
262}
263
264impl From<SexpLengthError> for SexpError {
265 fn from(e: SexpLengthError) -> Self {
266 SexpError::Length(e)
267 }
268}
269
270impl From<SexpNaError> for SexpError {
271 fn from(e: SexpNaError) -> Self {
272 SexpError::Na(e)
273 }
274}
275
276pub trait TryFromSexp: Sized {
290 type Error;
292
293 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error>;
297
298 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
306 Self::try_from_sexp(sexp)
308 }
309}
310
311macro_rules! impl_try_from_sexp_scalar_native {
312 ($t:ty, $sexptype:ident) => {
313 impl TryFromSexp for $t {
314 type Error = SexpError;
315
316 #[inline]
317 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
318 let actual = sexp.type_of();
319 if actual != SEXPTYPE::$sexptype {
320 return Err(SexpTypeError {
321 expected: SEXPTYPE::$sexptype,
322 actual,
323 }
324 .into());
325 }
326 let len = sexp.len();
327 if len != 1 {
328 return Err(SexpLengthError {
329 expected: 1,
330 actual: len,
331 }
332 .into());
333 }
334 unsafe { sexp.as_slice::<$t>() }
335 .first()
336 .cloned()
337 .ok_or_else(|| {
338 SexpLengthError {
339 expected: 1,
340 actual: 0,
341 }
342 .into()
343 })
344 }
345
346 #[inline]
347 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
348 let actual = sexp.type_of();
349 if actual != SEXPTYPE::$sexptype {
350 return Err(SexpTypeError {
351 expected: SEXPTYPE::$sexptype,
352 actual,
353 }
354 .into());
355 }
356 let len = unsafe { sexp.len_unchecked() };
357 if len != 1 {
358 return Err(SexpLengthError {
359 expected: 1,
360 actual: len,
361 }
362 .into());
363 }
364 unsafe { sexp.as_slice_unchecked::<$t>() }
365 .first()
366 .cloned()
367 .ok_or_else(|| {
368 SexpLengthError {
369 expected: 1,
370 actual: 0,
371 }
372 .into()
373 })
374 }
375 }
376 };
377}
378
379impl TryFromSexp for i32 {
382 type Error = SexpError;
383
384 #[inline]
385 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
386 let actual = sexp.type_of();
387 if actual != SEXPTYPE::INTSXP {
388 return Err(SexpTypeError {
389 expected: SEXPTYPE::INTSXP,
390 actual,
391 }
392 .into());
393 }
394 let len = sexp.len();
395 if len != 1 {
396 return Err(SexpLengthError {
397 expected: 1,
398 actual: len,
399 }
400 .into());
401 }
402 let v = unsafe { sexp.as_slice::<i32>() }
403 .first()
404 .cloned()
405 .ok_or_else(|| {
406 SexpError::from(SexpLengthError {
407 expected: 1,
408 actual: 0,
409 })
410 })?;
411 if v == crate::altrep_traits::NA_INTEGER {
412 return Err(SexpNaError {
413 sexp_type: SEXPTYPE::INTSXP,
414 }
415 .into());
416 }
417 Ok(v)
418 }
419
420 #[inline]
421 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
422 let actual = sexp.type_of();
423 if actual != SEXPTYPE::INTSXP {
424 return Err(SexpTypeError {
425 expected: SEXPTYPE::INTSXP,
426 actual,
427 }
428 .into());
429 }
430 let len = unsafe { sexp.len_unchecked() };
431 if len != 1 {
432 return Err(SexpLengthError {
433 expected: 1,
434 actual: len,
435 }
436 .into());
437 }
438 let v = unsafe { sexp.as_slice_unchecked::<i32>() }
439 .first()
440 .cloned()
441 .ok_or_else(|| {
442 SexpError::from(SexpLengthError {
443 expected: 1,
444 actual: 0,
445 })
446 })?;
447 if v == crate::altrep_traits::NA_INTEGER {
448 return Err(SexpNaError {
449 sexp_type: SEXPTYPE::INTSXP,
450 }
451 .into());
452 }
453 Ok(v)
454 }
455}
456
457impl_try_from_sexp_scalar_native!(f64, REALSXP);
458impl_try_from_sexp_scalar_native!(u8, RAWSXP);
459impl_try_from_sexp_scalar_native!(RLogical, LGLSXP);
460impl_try_from_sexp_scalar_native!(crate::ffi::Rcomplex, CPLXSXP);
461
462impl TryFromSexp for SEXP {
489 type Error = SexpError;
490
491 #[inline]
498 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
499 Ok(unsafe { crate::altrep_sexp::ensure_materialized(sexp) })
500 }
501
502 #[inline]
503 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
504 Ok(unsafe { crate::altrep_sexp::ensure_materialized(sexp) })
505 }
506}
507
508impl TryFromSexp for Option<SEXP> {
509 type Error = SexpError;
510
511 #[inline]
512 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
513 if sexp.type_of() == SEXPTYPE::NILSXP {
514 Ok(None)
515 } else {
516 Ok(Some(unsafe {
517 crate::altrep_sexp::ensure_materialized(sexp)
518 }))
519 }
520 }
521
522 #[inline]
523 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
524 Self::try_from_sexp(sexp)
525 }
526}
527mod logical;
530
531mod coerced_scalars;
532pub(crate) use coerced_scalars::coerce_value;
533
534mod references;
535
536impl<T> TryFromSexp for &[T]
544where
545 T: crate::ffi::RNativeType + Copy,
546{
547 type Error = SexpTypeError;
548
549 #[inline]
550 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
551 let actual = sexp.type_of();
552 if actual != T::SEXP_TYPE {
553 return Err(SexpTypeError {
554 expected: T::SEXP_TYPE,
555 actual,
556 });
557 }
558 Ok(unsafe { sexp.as_slice::<T>() })
559 }
560
561 #[inline]
562 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
563 let actual = sexp.type_of();
564 if actual != T::SEXP_TYPE {
565 return Err(SexpTypeError {
566 expected: T::SEXP_TYPE,
567 actual,
568 });
569 }
570 Ok(unsafe { sexp.as_slice_unchecked::<T>() })
571 }
572}
573
574impl<T> TryFromSexp for &mut [T]
582where
583 T: crate::ffi::RNativeType + Copy,
584{
585 type Error = SexpTypeError;
586
587 #[inline]
588 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
589 let actual = sexp.type_of();
590 if actual != T::SEXP_TYPE {
591 return Err(SexpTypeError {
592 expected: T::SEXP_TYPE,
593 actual,
594 });
595 }
596 let len = sexp.len();
597 let ptr = unsafe { T::dataptr_mut(sexp) };
598 Ok(unsafe { r_slice_mut(ptr, len) })
599 }
600
601 #[inline]
602 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
603 let actual = sexp.type_of();
604 if actual != T::SEXP_TYPE {
605 return Err(SexpTypeError {
606 expected: T::SEXP_TYPE,
607 actual,
608 });
609 }
610 let len = unsafe { sexp.len_unchecked() };
611 let ptr = unsafe { T::dataptr_mut(sexp) };
612 Ok(unsafe { r_slice_mut(ptr, len) })
613 }
614}
615
616impl<T> TryFromSexp for Option<&[T]>
618where
619 T: crate::ffi::RNativeType + Copy,
620{
621 type Error = SexpError;
622
623 #[inline]
624 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
625 if sexp.type_of() == SEXPTYPE::NILSXP {
626 return Ok(None);
627 }
628 let slice: &[T] = TryFromSexp::try_from_sexp(sexp).map_err(SexpError::from)?;
629 Ok(Some(slice))
630 }
631
632 #[inline]
633 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
634 if sexp.type_of() == SEXPTYPE::NILSXP {
635 return Ok(None);
636 }
637 let slice: &[T] =
638 unsafe { TryFromSexp::try_from_sexp_unchecked(sexp).map_err(SexpError::from)? };
639 Ok(Some(slice))
640 }
641}
642
643impl<T> TryFromSexp for Option<&mut [T]>
645where
646 T: crate::ffi::RNativeType + Copy,
647{
648 type Error = SexpError;
649
650 #[inline]
651 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
652 if sexp.type_of() == SEXPTYPE::NILSXP {
653 return Ok(None);
654 }
655 let slice: &mut [T] = TryFromSexp::try_from_sexp(sexp).map_err(SexpError::from)?;
656 Ok(Some(slice))
657 }
658
659 #[inline]
660 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
661 if sexp.type_of() == SEXPTYPE::NILSXP {
662 return Ok(None);
663 }
664 let slice: &mut [T] =
665 unsafe { TryFromSexp::try_from_sexp_unchecked(sexp).map_err(SexpError::from)? };
666 Ok(Some(slice))
667 }
668}
669mod strings;
672
673impl<T> TryFromSexp for Result<T, ()>
676where
677 T: TryFromSexp,
678 T::Error: Into<SexpError>,
679{
680 type Error = SexpError;
681
682 #[inline]
683 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
684 if sexp.type_of() == SEXPTYPE::NILSXP {
685 return Ok(Err(()));
686 }
687 let value = T::try_from_sexp(sexp).map_err(Into::into)?;
688 Ok(Ok(value))
689 }
690
691 #[inline]
692 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
693 if sexp.type_of() == SEXPTYPE::NILSXP {
694 return Ok(Err(()));
695 }
696 let value = unsafe { T::try_from_sexp_unchecked(sexp).map_err(Into::into)? };
697 Ok(Ok(value))
698 }
699}
700mod na_vectors;
703
704mod collections;
705
706impl<T, const N: usize> TryFromSexp for [T; N]
713where
714 T: crate::ffi::RNativeType + Copy,
715{
716 type Error = SexpError;
717
718 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
719 let slice: &[T] = TryFromSexp::try_from_sexp(sexp)?;
720 if slice.len() != N {
721 return Err(SexpLengthError {
722 expected: N,
723 actual: slice.len(),
724 }
725 .into());
726 }
727
728 let mut arr = std::mem::MaybeUninit::<[T; N]>::uninit();
730 unsafe {
731 let dst: &mut [T] = std::slice::from_raw_parts_mut(arr.as_mut_ptr().cast::<T>(), N);
734 dst.copy_from_slice(&slice[..N]);
735 Ok(arr.assume_init())
736 }
737 }
738
739 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
740 Self::try_from_sexp(sexp)
741 }
742}
743use std::collections::VecDeque;
748
749impl<T> TryFromSexp for VecDeque<T>
751where
752 T: crate::ffi::RNativeType + Copy,
753{
754 type Error = SexpTypeError;
755
756 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
757 let slice: &[T] = TryFromSexp::try_from_sexp(sexp)?;
758 Ok(VecDeque::from(slice.to_vec()))
759 }
760
761 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
762 let slice: &[T] = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
763 Ok(VecDeque::from(slice.to_vec()))
764 }
765}
766use std::collections::BinaryHeap;
771
772impl<T> TryFromSexp for BinaryHeap<T>
776where
777 T: crate::ffi::RNativeType + Copy + Ord,
778{
779 type Error = SexpTypeError;
780
781 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
782 let slice: &[T] = TryFromSexp::try_from_sexp(sexp)?;
783 Ok(BinaryHeap::from(slice.to_vec()))
784 }
785
786 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
787 let slice: &[T] = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
788 Ok(BinaryHeap::from(slice.to_vec()))
789 }
790}
791mod cow_and_paths;
794
795impl<T> TryFromSexp for Option<Vec<T>>
802where
803 Vec<T>: TryFromSexp,
804 <Vec<T> as TryFromSexp>::Error: Into<SexpError>,
805{
806 type Error = SexpError;
807
808 #[inline]
809 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
810 if sexp.type_of() == SEXPTYPE::NILSXP {
811 Ok(None)
812 } else {
813 Vec::<T>::try_from_sexp(sexp).map(Some).map_err(Into::into)
814 }
815 }
816
817 #[inline]
818 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
819 if sexp.type_of() == SEXPTYPE::NILSXP {
820 Ok(None)
821 } else {
822 unsafe {
823 Vec::<T>::try_from_sexp_unchecked(sexp)
824 .map(Some)
825 .map_err(Into::into)
826 }
827 }
828 }
829}
830
831macro_rules! impl_option_map_try_from_sexp {
832 ($(#[$meta:meta])* $map_ty:ident) => {
833 $(#[$meta])*
834 impl<V: TryFromSexp> TryFromSexp for Option<$map_ty<String, V>>
835 where
836 V::Error: Into<SexpError>,
837 {
838 type Error = SexpError;
839
840 #[inline]
841 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
842 if sexp.type_of() == SEXPTYPE::NILSXP {
843 Ok(None)
844 } else {
845 $map_ty::<String, V>::try_from_sexp(sexp).map(Some)
846 }
847 }
848 }
849 };
850}
851
852impl_option_map_try_from_sexp!(
853 HashMap
855);
856impl_option_map_try_from_sexp!(
857 BTreeMap
859);
860
861macro_rules! impl_option_set_try_from_sexp {
862 ($(#[$meta:meta])* $set_ty:ident) => {
863 $(#[$meta])*
864 impl<T> TryFromSexp for Option<$set_ty<T>>
865 where
866 $set_ty<T>: TryFromSexp,
867 <$set_ty<T> as TryFromSexp>::Error: Into<SexpError>,
868 {
869 type Error = SexpError;
870
871 #[inline]
872 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
873 if sexp.type_of() == SEXPTYPE::NILSXP {
874 Ok(None)
875 } else {
876 $set_ty::<T>::try_from_sexp(sexp)
877 .map(Some)
878 .map_err(Into::into)
879 }
880 }
881 }
882 };
883}
884
885impl_option_set_try_from_sexp!(
886 HashSet
888);
889impl_option_set_try_from_sexp!(
890 BTreeSet
892);
893impl<T> TryFromSexp for Vec<Vec<T>>
901where
902 Vec<T>: TryFromSexp,
903 <Vec<T> as TryFromSexp>::Error: Into<SexpError>,
904{
905 type Error = SexpError;
906
907 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
908 let actual = sexp.type_of();
909 if actual != SEXPTYPE::VECSXP {
910 return Err(SexpTypeError {
911 expected: SEXPTYPE::VECSXP,
912 actual,
913 }
914 .into());
915 }
916
917 let len = sexp.len();
918 let mut result = Vec::with_capacity(len);
919
920 for i in 0..len {
921 let elem = sexp.vector_elt(i as crate::ffi::R_xlen_t);
922 let inner: Vec<T> = Vec::<T>::try_from_sexp(elem).map_err(Into::into)?;
923 result.push(inner);
924 }
925
926 Ok(result)
927 }
928
929 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
930 let actual = sexp.type_of();
931 if actual != SEXPTYPE::VECSXP {
932 return Err(SexpTypeError {
933 expected: SEXPTYPE::VECSXP,
934 actual,
935 }
936 .into());
937 }
938
939 let len = sexp.len();
940 let mut result = Vec::with_capacity(len);
941
942 for i in 0..len {
943 let elem = sexp.vector_elt(i as crate::ffi::R_xlen_t);
944 let inner: Vec<T> =
945 unsafe { Vec::<T>::try_from_sexp_unchecked(elem).map_err(Into::into)? };
946 result.push(inner);
947 }
948
949 Ok(result)
950 }
951}
952use crate::coerce::Coerced;
957
958impl<T, R> TryFromSexp for Coerced<T, R>
972where
973 R: TryFromSexp,
974 R: TryCoerce<T>,
975 <R as TryFromSexp>::Error: Into<SexpError>,
976 <R as TryCoerce<T>>::Error: std::fmt::Debug,
977{
978 type Error = SexpError;
979
980 #[inline]
981 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
982 let r_val: R = R::try_from_sexp(sexp).map_err(Into::into)?;
983 let value: T = r_val
984 .try_coerce()
985 .map_err(|e| SexpError::InvalidValue(format!("{e:?}")))?;
986 Ok(Coerced::new(value))
987 }
988
989 #[inline]
990 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
991 let r_val: R = unsafe { R::try_from_sexp_unchecked(sexp).map_err(Into::into)? };
992 let value: T = r_val
993 .try_coerce()
994 .map_err(|e| SexpError::InvalidValue(format!("{e:?}")))?;
995 Ok(Coerced::new(value))
996 }
997}
998#[inline]
1008fn coerce_slice_to_vec<R, T>(slice: &[R]) -> Result<Vec<T>, SexpError>
1009where
1010 R: Copy + TryCoerce<T>,
1011 <R as TryCoerce<T>>::Error: std::fmt::Debug,
1012{
1013 slice
1014 .iter()
1015 .copied()
1016 .map(|v| {
1017 v.try_coerce()
1018 .map_err(|e| SexpError::InvalidValue(format!("{e:?}")))
1019 })
1020 .collect()
1021}
1022
1023#[inline]
1025fn try_from_sexp_numeric_vec<T>(sexp: SEXP) -> Result<Vec<T>, SexpError>
1026where
1027 i32: TryCoerce<T>,
1028 f64: TryCoerce<T>,
1029 u8: TryCoerce<T>,
1030 <i32 as TryCoerce<T>>::Error: std::fmt::Debug,
1031 <f64 as TryCoerce<T>>::Error: std::fmt::Debug,
1032 <u8 as TryCoerce<T>>::Error: std::fmt::Debug,
1033{
1034 let actual = sexp.type_of();
1035 match actual {
1036 SEXPTYPE::INTSXP => {
1037 let slice: &[i32] = unsafe { sexp.as_slice() };
1038 coerce_slice_to_vec(slice)
1039 }
1040 SEXPTYPE::REALSXP => {
1041 let slice: &[f64] = unsafe { sexp.as_slice() };
1042 coerce_slice_to_vec(slice)
1043 }
1044 SEXPTYPE::RAWSXP => {
1045 let slice: &[u8] = unsafe { sexp.as_slice() };
1046 coerce_slice_to_vec(slice)
1047 }
1048 SEXPTYPE::LGLSXP => {
1049 let slice: &[RLogical] = unsafe { sexp.as_slice() };
1050 slice.iter().map(|v| coerce_value(v.to_i32())).collect()
1051 }
1052 _ => Err(SexpError::InvalidValue(format!(
1053 "expected integer, numeric, logical, or raw; got {:?}",
1054 actual
1055 ))),
1056 }
1057}
1058
1059macro_rules! impl_vec_try_from_sexp_numeric {
1061 ($target:ty) => {
1062 impl TryFromSexp for Vec<$target> {
1063 type Error = SexpError;
1064
1065 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1066 try_from_sexp_numeric_vec(sexp)
1067 }
1068
1069 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1070 try_from_sexp_numeric_vec(sexp)
1071 }
1072 }
1073 };
1074}
1075
1076impl_vec_try_from_sexp_numeric!(i8);
1077impl_vec_try_from_sexp_numeric!(i16);
1078impl_vec_try_from_sexp_numeric!(i64);
1079impl_vec_try_from_sexp_numeric!(isize);
1080impl_vec_try_from_sexp_numeric!(u16);
1081impl_vec_try_from_sexp_numeric!(u32);
1082impl_vec_try_from_sexp_numeric!(u64);
1083impl_vec_try_from_sexp_numeric!(usize);
1084impl_vec_try_from_sexp_numeric!(f32);
1085
1086impl TryFromSexp for Vec<bool> {
1088 type Error = SexpError;
1089
1090 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1091 let actual = sexp.type_of();
1092 if actual != SEXPTYPE::LGLSXP {
1093 return Err(SexpTypeError {
1094 expected: SEXPTYPE::LGLSXP,
1095 actual,
1096 }
1097 .into());
1098 }
1099 let slice: &[RLogical] = unsafe { sexp.as_slice() };
1100 coerce_slice_to_vec(slice)
1101 }
1102
1103 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1104 Self::try_from_sexp(sexp)
1105 }
1106}
1107
1108impl TryFromSexp for Box<[bool]> {
1109 type Error = SexpError;
1110
1111 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1112 let vec: Vec<bool> = TryFromSexp::try_from_sexp(sexp)?;
1113 Ok(vec.into_boxed_slice())
1114 }
1115}
1116#[inline]
1122fn try_from_sexp_numeric_set<T, S>(sexp: SEXP) -> Result<S, SexpError>
1123where
1124 S: std::iter::FromIterator<T>,
1125 i32: TryCoerce<T>,
1126 f64: TryCoerce<T>,
1127 u8: TryCoerce<T>,
1128 <i32 as TryCoerce<T>>::Error: std::fmt::Debug,
1129 <f64 as TryCoerce<T>>::Error: std::fmt::Debug,
1130 <u8 as TryCoerce<T>>::Error: std::fmt::Debug,
1131{
1132 let vec = try_from_sexp_numeric_vec(sexp)?;
1133 Ok(vec.into_iter().collect())
1134}
1135
1136macro_rules! impl_set_try_from_sexp_numeric {
1137 ($set_ty:ident, $target:ty) => {
1138 impl TryFromSexp for $set_ty<$target> {
1139 type Error = SexpError;
1140
1141 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1142 try_from_sexp_numeric_set(sexp)
1143 }
1144
1145 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1146 try_from_sexp_numeric_set(sexp)
1147 }
1148 }
1149 };
1150}
1151
1152impl_set_try_from_sexp_numeric!(HashSet, i8);
1153impl_set_try_from_sexp_numeric!(HashSet, i16);
1154impl_set_try_from_sexp_numeric!(HashSet, i64);
1155impl_set_try_from_sexp_numeric!(HashSet, isize);
1156impl_set_try_from_sexp_numeric!(HashSet, u16);
1157impl_set_try_from_sexp_numeric!(HashSet, u32);
1158impl_set_try_from_sexp_numeric!(HashSet, u64);
1159impl_set_try_from_sexp_numeric!(HashSet, usize);
1160
1161impl_set_try_from_sexp_numeric!(BTreeSet, i8);
1162impl_set_try_from_sexp_numeric!(BTreeSet, i16);
1163impl_set_try_from_sexp_numeric!(BTreeSet, i64);
1164impl_set_try_from_sexp_numeric!(BTreeSet, isize);
1165impl_set_try_from_sexp_numeric!(BTreeSet, u16);
1166impl_set_try_from_sexp_numeric!(BTreeSet, u32);
1167impl_set_try_from_sexp_numeric!(BTreeSet, u64);
1168impl_set_try_from_sexp_numeric!(BTreeSet, usize);
1169
1170macro_rules! impl_set_try_from_sexp_bool {
1171 ($set_ty:ident) => {
1172 impl TryFromSexp for $set_ty<bool> {
1173 type Error = SexpError;
1174
1175 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1176 let vec: Vec<bool> = TryFromSexp::try_from_sexp(sexp)?;
1177 Ok(vec.into_iter().collect())
1178 }
1179
1180 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1181 Self::try_from_sexp(sexp)
1182 }
1183 }
1184 };
1185}
1186
1187impl_set_try_from_sexp_bool!(HashSet);
1188impl_set_try_from_sexp_bool!(BTreeSet);
1189use crate::externalptr::{ExternalPtr, TypeMismatchError, TypedExternal};
1194
1195impl<T: TypedExternal + Send> TryFromSexp for ExternalPtr<T> {
1211 type Error = SexpError;
1212
1213 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1214 let actual = sexp.type_of();
1215 if actual != SEXPTYPE::EXTPTRSXP {
1216 return Err(SexpTypeError {
1217 expected: SEXPTYPE::EXTPTRSXP,
1218 actual,
1219 }
1220 .into());
1221 }
1222
1223 unsafe { ExternalPtr::wrap_sexp_with_error(sexp) }.map_err(|e| match e {
1225 TypeMismatchError::NullPointer => {
1226 SexpError::InvalidValue("external pointer is null".to_string())
1227 }
1228 TypeMismatchError::InvalidTypeId => {
1229 SexpError::InvalidValue("external pointer has no valid type id".to_string())
1230 }
1231 TypeMismatchError::Mismatch { expected, found } => SexpError::InvalidValue(format!(
1232 "type mismatch: expected `{}`, found `{}`",
1233 expected, found
1234 )),
1235 })
1236 }
1237
1238 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1239 let actual = sexp.type_of();
1240 if actual != SEXPTYPE::EXTPTRSXP {
1241 return Err(SexpTypeError {
1242 expected: SEXPTYPE::EXTPTRSXP,
1243 actual,
1244 }
1245 .into());
1246 }
1247
1248 unsafe { ExternalPtr::wrap_sexp_unchecked(sexp) }.ok_or_else(|| {
1250 SexpError::InvalidValue(
1251 "failed to convert external pointer: type mismatch or null pointer".to_string(),
1252 )
1253 })
1254 }
1255}
1256
1257impl<T: TypedExternal + Send> TryFromSexp for Option<ExternalPtr<T>> {
1258 type Error = SexpError;
1259
1260 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1261 if sexp.type_of() == SEXPTYPE::NILSXP {
1262 return Ok(None);
1263 }
1264 let ptr: ExternalPtr<T> = TryFromSexp::try_from_sexp(sexp)?;
1265 Ok(Some(ptr))
1266 }
1267
1268 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1269 if sexp.type_of() == SEXPTYPE::NILSXP {
1270 return Ok(None);
1271 }
1272 let ptr: ExternalPtr<T> = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
1273 Ok(Some(ptr))
1274 }
1275}
1276#[cfg(feature = "connections")]
1281mod connections_from_r {
1282 use std::ffi::CStr;
1283
1284 use crate::connection::{RNullConnection, RStderr, RStdin, RStdout, Rconn};
1285 use crate::ffi::{Rboolean, SEXP};
1286 use crate::from_r::{SexpError, TryFromSexp};
1287
1288 unsafe fn conn_description(sexp: SEXP) -> Option<String> {
1294 unsafe {
1295 let handle = crate::ffi::R_GetConnection(sexp);
1296 let conn = handle.cast::<Rconn>().cast_const();
1297 if (*conn).description.is_null() {
1298 None
1299 } else {
1300 Some(
1301 CStr::from_ptr((*conn).description)
1302 .to_string_lossy()
1303 .into_owned(),
1304 )
1305 }
1306 }
1307 }
1308
1309 unsafe fn conn_class(sexp: SEXP) -> Option<String> {
1310 unsafe {
1311 let handle = crate::ffi::R_GetConnection(sexp);
1312 let conn = handle.cast::<Rconn>().cast_const();
1313 if (*conn).class.is_null() {
1314 None
1315 } else {
1316 Some(CStr::from_ptr((*conn).class).to_string_lossy().into_owned())
1317 }
1318 }
1319 }
1320
1321 unsafe fn conn_canwrite(sexp: SEXP) -> bool {
1322 unsafe {
1323 let handle = crate::ffi::R_GetConnection(sexp);
1324 let conn = handle.cast::<Rconn>().cast_const();
1325 (*conn).canwrite != Rboolean::FALSE
1326 }
1327 }
1328
1329 unsafe fn conn_isopen(sexp: SEXP) -> bool {
1330 unsafe {
1331 let handle = crate::ffi::R_GetConnection(sexp);
1332 let conn = handle.cast::<Rconn>().cast_const();
1333 (*conn).isopen != Rboolean::FALSE
1334 }
1335 }
1336
1337 unsafe fn validate_terminal(sexp: SEXP, expected_desc: &str) -> Result<(), SexpError> {
1339 let desc = unsafe { conn_description(sexp) }.unwrap_or_default();
1340 if desc != expected_desc {
1341 return Err(SexpError::InvalidValue(format!(
1342 "expected terminal connection with description {:?}, got {:?}",
1343 expected_desc, desc
1344 )));
1345 }
1346 let cls = unsafe { conn_class(sexp) }.unwrap_or_default();
1347 if cls != "terminal" {
1348 return Err(SexpError::InvalidValue(format!(
1349 "expected class \"terminal\", got {:?}",
1350 cls
1351 )));
1352 }
1353 Ok(())
1354 }
1355
1356 impl TryFromSexp for RStdin {
1357 type Error = SexpError;
1358
1359 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1360 unsafe { validate_terminal(sexp, "stdin") }?;
1361 Ok(RStdin)
1362 }
1363
1364 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1365 Self::try_from_sexp(sexp)
1366 }
1367 }
1368
1369 impl TryFromSexp for RStdout {
1370 type Error = SexpError;
1371
1372 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1373 unsafe { validate_terminal(sexp, "stdout") }?;
1374 Ok(RStdout)
1375 }
1376
1377 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1378 Self::try_from_sexp(sexp)
1379 }
1380 }
1381
1382 impl TryFromSexp for RStderr {
1383 type Error = SexpError;
1384
1385 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1386 unsafe { validate_terminal(sexp, "stderr") }?;
1387 Ok(RStderr)
1388 }
1389
1390 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1391 Self::try_from_sexp(sexp)
1392 }
1393 }
1394
1395 impl TryFromSexp for RNullConnection {
1402 type Error = SexpError;
1403
1404 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1405 if !unsafe { conn_isopen(sexp) } {
1406 return Err(SexpError::InvalidValue(
1407 "expected an open connection".to_string(),
1408 ));
1409 }
1410 if !unsafe { conn_canwrite(sexp) } {
1411 return Err(SexpError::InvalidValue(
1412 "expected a write-capable connection".to_string(),
1413 ));
1414 }
1415 unsafe { crate::ffi::R_PreserveObject(sexp) };
1417 Ok(unsafe { RNullConnection::from_preserved_sexp(sexp) })
1418 }
1419
1420 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1421 Self::try_from_sexp(sexp)
1422 }
1423 }
1424}
1425
1426#[cfg(feature = "connections")]
1431mod txt_progress_bar_from_r {
1432 use crate::ffi::{R_PreserveObject, SEXP, SexpExt};
1433 use crate::from_r::{SexpError, TryFromSexp};
1434 use crate::txt_progress_bar::RTxtProgressBar;
1435
1436 impl TryFromSexp for RTxtProgressBar {
1437 type Error = SexpError;
1438
1439 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1440 if !sexp.inherits_class(c"txtProgressBar") {
1442 return Err(SexpError::InvalidValue(
1443 "expected a SEXP with class \"txtProgressBar\"".to_string(),
1444 ));
1445 }
1446 unsafe { R_PreserveObject(sexp) };
1448 Ok(unsafe { RTxtProgressBar::from_preserved_sexp(sexp) })
1449 }
1450
1451 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
1452 Self::try_from_sexp(sexp)
1453 }
1454 }
1455}
1456
1457#[macro_export]
1465macro_rules! impl_option_try_from_sexp {
1466 ($t:ty) => {
1467 impl $crate::from_r::TryFromSexp for Option<$t> {
1468 type Error = $crate::from_r::SexpError;
1469
1470 fn try_from_sexp(sexp: $crate::ffi::SEXP) -> Result<Self, Self::Error> {
1471 use $crate::ffi::{SEXPTYPE, SexpExt};
1472 if sexp.type_of() == SEXPTYPE::NILSXP {
1473 return Ok(None);
1474 }
1475 <$t as $crate::from_r::TryFromSexp>::try_from_sexp(sexp).map(Some)
1476 }
1477
1478 unsafe fn try_from_sexp_unchecked(
1479 sexp: $crate::ffi::SEXP,
1480 ) -> Result<Self, Self::Error> {
1481 use $crate::ffi::{SEXPTYPE, SexpExt};
1482 if sexp.type_of() == SEXPTYPE::NILSXP {
1483 return Ok(None);
1484 }
1485 unsafe {
1486 <$t as $crate::from_r::TryFromSexp>::try_from_sexp_unchecked(sexp).map(Some)
1487 }
1488 }
1489 }
1490 };
1491}
1492
1493#[macro_export]
1497macro_rules! impl_vec_try_from_sexp_list {
1498 ($t:ty) => {
1499 impl $crate::from_r::TryFromSexp for Vec<$t> {
1500 type Error = $crate::from_r::SexpError;
1501
1502 fn try_from_sexp(sexp: $crate::ffi::SEXP) -> Result<Self, Self::Error> {
1503 use $crate::ffi::{SEXPTYPE, SexpExt};
1504 use $crate::from_r::SexpTypeError;
1505
1506 let actual = sexp.type_of();
1507 if actual != SEXPTYPE::VECSXP {
1508 return Err(SexpTypeError {
1509 expected: SEXPTYPE::VECSXP,
1510 actual,
1511 }
1512 .into());
1513 }
1514
1515 let len = sexp.len();
1516 let mut result = Vec::with_capacity(len);
1517 for i in 0..len {
1518 let elem = sexp.vector_elt(i as $crate::ffi::R_xlen_t);
1519 result.push(<$t as $crate::from_r::TryFromSexp>::try_from_sexp(elem)?);
1520 }
1521 Ok(result)
1522 }
1523
1524 unsafe fn try_from_sexp_unchecked(
1525 sexp: $crate::ffi::SEXP,
1526 ) -> Result<Self, Self::Error> {
1527 use $crate::ffi::{SEXPTYPE, SexpExt};
1528 use $crate::from_r::SexpTypeError;
1529
1530 let actual = sexp.type_of();
1531 if actual != SEXPTYPE::VECSXP {
1532 return Err(SexpTypeError {
1533 expected: SEXPTYPE::VECSXP,
1534 actual,
1535 }
1536 .into());
1537 }
1538
1539 let len = unsafe { sexp.len_unchecked() };
1540 let mut result = Vec::with_capacity(len);
1541 for i in 0..len {
1542 let elem = unsafe { sexp.vector_elt_unchecked(i as $crate::ffi::R_xlen_t) };
1543 result.push(unsafe {
1544 <$t as $crate::from_r::TryFromSexp>::try_from_sexp_unchecked(elem)?
1545 });
1546 }
1547 Ok(result)
1548 }
1549 }
1550 };
1551}
1552
1553#[macro_export]
1557macro_rules! impl_vec_option_try_from_sexp_list {
1558 ($t:ty) => {
1559 impl $crate::from_r::TryFromSexp for Vec<Option<$t>> {
1560 type Error = $crate::from_r::SexpError;
1561
1562 fn try_from_sexp(sexp: $crate::ffi::SEXP) -> Result<Self, Self::Error> {
1563 use $crate::ffi::{SEXPTYPE, SexpExt};
1564 use $crate::from_r::SexpTypeError;
1565
1566 let actual = sexp.type_of();
1567 if actual != SEXPTYPE::VECSXP {
1568 return Err(SexpTypeError {
1569 expected: SEXPTYPE::VECSXP,
1570 actual,
1571 }
1572 .into());
1573 }
1574
1575 let len = sexp.len();
1576 let mut result = Vec::with_capacity(len);
1577 for i in 0..len {
1578 let elem = sexp.vector_elt(i as $crate::ffi::R_xlen_t);
1579 if elem == $crate::ffi::SEXP::nil() {
1580 result.push(None);
1581 } else {
1582 result.push(Some(<$t as $crate::from_r::TryFromSexp>::try_from_sexp(
1583 elem,
1584 )?));
1585 }
1586 }
1587 Ok(result)
1588 }
1589
1590 unsafe fn try_from_sexp_unchecked(
1591 sexp: $crate::ffi::SEXP,
1592 ) -> Result<Self, Self::Error> {
1593 use $crate::ffi::{SEXPTYPE, SexpExt};
1594 use $crate::from_r::SexpTypeError;
1595
1596 let actual = sexp.type_of();
1597 if actual != SEXPTYPE::VECSXP {
1598 return Err(SexpTypeError {
1599 expected: SEXPTYPE::VECSXP,
1600 actual,
1601 }
1602 .into());
1603 }
1604
1605 let len = unsafe { sexp.len_unchecked() };
1606 let mut result = Vec::with_capacity(len);
1607 for i in 0..len {
1608 let elem = unsafe { sexp.vector_elt_unchecked(i as $crate::ffi::R_xlen_t) };
1609 if elem == $crate::ffi::SEXP::nil() {
1610 result.push(None);
1611 } else {
1612 result.push(Some(unsafe {
1613 <$t as $crate::from_r::TryFromSexp>::try_from_sexp_unchecked(elem)?
1614 }));
1615 }
1616 }
1617 Ok(result)
1618 }
1619 }
1620 };
1621}
1622