1#![allow(rustdoc::private_intra_doc_links)]
2use crate::ffi::SEXPTYPE::{LISTSXP, STRSXP, VECSXP};
21use crate::ffi::{self, SEXP, SexpExt};
22use crate::from_r::{SexpError, SexpLengthError, SexpTypeError, TryFromSexp};
23use crate::gc_protect::OwnedProtect;
24use crate::into_r::IntoR;
25use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
26use std::hash::Hash;
27
28#[derive(Clone, Copy, Debug)]
40pub struct List(SEXP);
41
42#[derive(Debug)]
47pub struct ListMut(SEXP);
48
49impl List {
50 #[inline]
52 pub fn is_list(self) -> bool {
53 self.0.is_pair_list()
54 }
55
56 #[inline]
63 pub const unsafe fn from_raw(sexp: SEXP) -> Self {
64 List(sexp)
65 }
66
67 #[inline]
69 pub const fn as_sexp(self) -> SEXP {
70 self.0
71 }
72
73 #[inline]
75 pub fn len(self) -> isize {
76 unsafe { ffi::Rf_xlength(self.0) }
77 }
78
79 #[inline]
81 pub fn is_empty(self) -> bool {
82 self.len() == 0
83 }
84
85 #[inline]
87 pub fn get(self, idx: isize) -> Option<SEXP> {
88 if idx < 0 || idx >= self.len() {
89 return None;
90 }
91 Some(self.0.vector_elt(idx))
92 }
93
94 #[inline]
98 pub fn get_index<T>(self, idx: isize) -> Option<T>
99 where
100 T: TryFromSexp<Error = SexpError>,
101 {
102 let sexp = self.get(idx)?;
103 T::try_from_sexp(sexp).ok()
104 }
105
106 pub fn get_named<T>(self, name: &str) -> Option<T>
110 where
111 T: TryFromSexp<Error = SexpError>,
112 {
113 let names_sexp = self.names()?;
114 let n = self.len();
115
116 for i in 0..n {
118 let name_sexp = names_sexp.string_elt(i);
119 if name_sexp == SEXP::na_string() {
120 continue;
121 }
122 let name_ptr = name_sexp.r_char();
123 let name_cstr = unsafe { std::ffi::CStr::from_ptr(name_ptr) };
124 if let Ok(s) = name_cstr.to_str() {
125 if s == name {
126 let elem = self.0.vector_elt(i);
127 return T::try_from_sexp(elem).ok();
128 }
129 }
130 }
131 None
132 }
133
134 #[inline]
138 fn get_attr_opt(self, name: SEXP) -> Option<SEXP> {
139 let attr = self.0.get_attr(name);
140 if attr.is_nil() { None } else { Some(attr) }
141 }
142
143 #[inline]
145 pub fn names(self) -> Option<SEXP> {
146 self.get_attr_opt(SEXP::names_symbol())
147 }
148
149 #[inline]
151 pub fn get_class(self) -> Option<SEXP> {
152 self.get_attr_opt(SEXP::class_symbol())
153 }
154
155 #[inline]
157 pub fn get_dim(self) -> Option<SEXP> {
158 self.get_attr_opt(SEXP::dim_symbol())
159 }
160
161 #[inline]
163 pub fn get_dimnames(self) -> Option<SEXP> {
164 self.get_attr_opt(SEXP::dimnames_symbol())
165 }
166
167 #[inline]
169 pub fn get_rownames(self) -> Option<SEXP> {
170 let rownames = unsafe { ffi::Rf_GetRowNames(self.0) };
171 if rownames.is_nil() {
172 None
173 } else {
174 Some(rownames)
175 }
176 }
177
178 #[inline]
180 pub fn get_colnames(self) -> Option<SEXP> {
181 let dimnames = self.0.get_dimnames();
182 if dimnames.is_nil() {
183 return None;
184 }
185 let colnames = unsafe { ffi::Rf_GetColNames(dimnames) };
186 if colnames.is_nil() {
187 None
188 } else {
189 Some(colnames)
190 }
191 }
192
193 #[inline]
195 pub fn get_levels(self) -> Option<SEXP> {
196 self.get_attr_opt(SEXP::levels_symbol())
197 }
198
199 #[inline]
201 pub fn get_tsp(self) -> Option<SEXP> {
202 self.get_attr_opt(SEXP::tsp_symbol())
203 }
204 #[inline]
212 pub fn set_names(self, names: SEXP) -> Self {
213 self.0.set_names(names);
214 self
215 }
216
217 #[inline]
221 pub fn set_class(self, class: SEXP) -> Self {
222 self.0.set_class(class);
223 self
224 }
225
226 #[inline]
230 pub fn set_dim(self, dim: SEXP) -> Self {
231 self.0.set_dim(dim);
232 self
233 }
234
235 #[inline]
239 pub fn set_dimnames(self, dimnames: SEXP) -> Self {
240 self.0.set_dimnames(dimnames);
241 self
242 }
243
244 #[inline]
248 pub fn set_levels(self, levels: SEXP) -> Self {
249 self.0.set_levels(levels);
250 self
251 }
252 #[inline]
268 pub fn set_class_str(self, classes: &[&str]) -> Self {
269 use crate::ffi::SEXPTYPE::STRSXP;
270
271 let n: isize = classes
272 .len()
273 .try_into()
274 .expect("classes length exceeds isize::MAX");
275 unsafe {
276 let class_vec = OwnedProtect::new(ffi::Rf_allocVector(STRSXP, n));
277 for (i, class) in classes.iter().enumerate() {
278 let idx: isize = i.try_into().expect("index exceeds isize::MAX");
279 class_vec.get().set_string_elt(idx, SEXP::charsxp(class));
280 }
281 self.0.set_class(class_vec.get());
282 }
283 self
284 }
285
286 #[inline]
290 pub fn set_data_frame_class(self) -> Self {
291 self.0
292 .set_class(crate::cached_class::data_frame_class_sexp());
293 self
294 }
295
296 #[inline]
308 pub fn set_names_str(self, names: &[&str]) -> Self {
309 use crate::ffi::SEXPTYPE::STRSXP;
310
311 let n: isize = names
312 .len()
313 .try_into()
314 .expect("names length exceeds isize::MAX");
315 unsafe {
316 let names_vec = OwnedProtect::new(ffi::Rf_allocVector(STRSXP, n));
317 for (i, name) in names.iter().enumerate() {
318 let idx: isize = i.try_into().expect("index exceeds isize::MAX");
319 names_vec.get().set_string_elt(idx, SEXP::charsxp(name));
320 }
321 self.0.set_names(names_vec.get());
322 }
323 self
324 }
325
326 #[inline]
343 pub fn set_row_names_int(self, n: usize) -> Self {
344 unsafe {
345 let (row_names, rn) = crate::into_r::alloc_r_vector::<i32>(2);
347 let _guard = OwnedProtect::new(row_names);
348 rn[0] = i32::MIN; let n_i32 = i32::try_from(n).unwrap_or_else(|_| {
350 panic!("row count {n} exceeds i32::MAX");
351 });
352 rn[1] = -n_i32;
353 self.0.set_row_names(row_names);
354 }
355 self
356 }
357
358 #[inline]
373 pub fn set_row_names_str(self, row_names: &[&str]) -> Self {
374 use crate::ffi::SEXPTYPE::STRSXP;
375
376 let n: isize = row_names
377 .len()
378 .try_into()
379 .expect("row_names length exceeds isize::MAX");
380 unsafe {
381 let names_vec = OwnedProtect::new(ffi::Rf_allocVector(STRSXP, n));
382 for (i, name) in row_names.iter().enumerate() {
383 let idx: isize = i.try_into().expect("index exceeds isize::MAX");
384 names_vec.get().set_string_elt(idx, SEXP::charsxp(name));
385 }
386 self.0.set_row_names(names_vec.get());
387 }
388 self
389 }
390 #[inline]
422 pub unsafe fn set_elt(self, idx: isize, child: SEXP) {
423 assert!(idx >= 0 && idx < self.len(), "index out of bounds");
424 unsafe {
428 let _guard = OwnedProtect::new(child);
429 self.0.set_vector_elt(idx, child);
430 }
431 }
432
433 #[inline]
445 pub unsafe fn set_elt_unchecked(self, idx: isize, child: SEXP) {
446 debug_assert!(idx >= 0 && idx < self.len(), "index out of bounds");
447 self.0.set_vector_elt(idx, child);
449 }
450
451 #[inline]
475 pub unsafe fn set_elt_with<F>(self, idx: isize, f: F)
476 where
477 F: FnOnce() -> SEXP,
478 {
479 assert!(idx >= 0 && idx < self.len(), "index out of bounds");
480 unsafe {
482 let child = OwnedProtect::new(f());
483 self.0.set_vector_elt(idx, child.get());
484 }
485 }
486 }
488
489use crate::gc_protect::ProtectScope;
492
493pub struct ListBuilder<'a> {
516 list: SEXP,
517 _scope: &'a ProtectScope,
518}
519
520impl<'a> ListBuilder<'a> {
521 #[inline]
529 pub unsafe fn new(scope: &'a ProtectScope, len: usize) -> Self {
530 let list = unsafe { scope.alloc_vecsxp(len).into_raw() };
532 Self {
533 list,
534 _scope: scope,
535 }
536 }
537
538 #[inline]
545 pub unsafe fn from_protected(scope: &'a ProtectScope, list: SEXP) -> Self {
546 Self {
547 list,
548 _scope: scope,
549 }
550 }
551
552 #[inline]
562 pub unsafe fn set(&self, idx: isize, child: SEXP) {
563 unsafe {
565 debug_assert!(idx >= 0 && idx < ffi::Rf_xlength(self.list));
566 self.list.set_vector_elt(idx, child);
567 }
568 }
569
570 #[inline]
578 pub unsafe fn set_protected(&self, idx: isize, child: SEXP) {
579 unsafe {
581 debug_assert!(idx >= 0 && idx < ffi::Rf_xlength(self.list));
582 let _guard = OwnedProtect::new(child);
583 self.list.set_vector_elt(idx, child);
584 }
585 }
586
587 #[inline]
589 pub fn as_sexp(&self) -> SEXP {
590 self.list
591 }
592
593 #[inline]
595 pub fn into_list(self) -> List {
596 List(self.list)
597 }
598
599 #[inline]
601 pub fn into_sexp(self) -> SEXP {
602 self.list
603 }
604
605 #[inline]
607 pub fn len(&self) -> isize {
608 unsafe { ffi::Rf_xlength(self.list) }
609 }
610
611 #[inline]
613 pub fn is_empty(&self) -> bool {
614 self.len() == 0
615 }
616}
617mod accumulator;
620mod named;
621
622pub use accumulator::*;
623pub use named::*;
624
625pub trait IntoList {
629 fn into_list(self) -> List;
631}
632
633pub trait TryFromList: Sized {
635 type Error;
637
638 fn try_from_list(list: List) -> Result<Self, Self::Error>;
640}
641
642impl<T: IntoR> IntoList for Vec<T> {
643 fn into_list(self) -> List {
644 let converted: Vec<SEXP> = self.into_iter().map(|v| v.into_sexp()).collect();
645 let n: isize = converted
646 .len()
647 .try_into()
648 .expect("list length exceeds isize::MAX");
649 unsafe {
650 let list = ffi::Rf_allocVector(VECSXP, n);
651 for (i, val) in converted.into_iter().enumerate() {
652 let idx: isize = i.try_into().expect("index exceeds isize::MAX");
653 list.set_vector_elt(idx, val);
654 }
655 List(list)
656 }
657 }
658}
659
660impl<T> TryFromList for Vec<T>
661where
662 T: TryFromSexp<Error = SexpError>,
663{
664 type Error = SexpError;
665
666 fn try_from_list(list: List) -> Result<Self, Self::Error> {
667 let expected: usize = list
668 .len()
669 .try_into()
670 .expect("list length must be non-negative");
671 let mut out = Vec::with_capacity(expected);
672 for i in 0..expected {
673 let idx: isize = i.try_into().expect("index exceeds isize::MAX");
674 let sexp = list.get(idx).ok_or_else(|| {
675 SexpError::from(SexpLengthError {
676 expected,
677 actual: i,
678 })
679 })?;
680 out.push(TryFromSexp::try_from_sexp(sexp)?);
681 }
682 Ok(out)
683 }
684}
685
686impl<K, V> IntoList for HashMap<K, V>
691where
692 K: AsRef<str>,
693 V: IntoR,
694{
695 fn into_list(self) -> List {
696 let pairs: Vec<(K, V)> = self.into_iter().collect();
697 List::from_pairs(pairs)
698 }
699}
700
701impl<V> TryFromList for HashMap<String, V>
702where
703 V: TryFromSexp<Error = SexpError>,
704{
705 type Error = SexpError;
706
707 fn try_from_list(list: List) -> Result<Self, Self::Error> {
708 let n: usize = list
709 .len()
710 .try_into()
711 .expect("list length must be non-negative");
712 let names_sexp = list.names();
713 let mut map = HashMap::with_capacity(n);
714
715 for i in 0..n {
716 let idx: isize = i.try_into().expect("index exceeds isize::MAX");
717 let sexp = list.get(idx).ok_or_else(|| {
718 SexpError::from(SexpLengthError {
719 expected: n,
720 actual: i,
721 })
722 })?;
723 let value: V = TryFromSexp::try_from_sexp(sexp)?;
724
725 let key = if let Some(names) = names_sexp {
726 let name_sexp = names.string_elt(idx);
727 if name_sexp == SEXP::na_string() {
728 format!("{i}")
729 } else {
730 let name_ptr = name_sexp.r_char();
731 let name_cstr = unsafe { std::ffi::CStr::from_ptr(name_ptr) };
732 name_cstr.to_str().unwrap_or(&format!("{i}")).to_string()
733 }
734 } else {
735 format!("{i}")
736 };
737
738 map.insert(key, value);
739 }
740 Ok(map)
741 }
742}
743impl<K, V> IntoList for BTreeMap<K, V>
748where
749 K: AsRef<str>,
750 V: IntoR,
751{
752 fn into_list(self) -> List {
753 let pairs: Vec<(K, V)> = self.into_iter().collect();
754 List::from_pairs(pairs)
755 }
756}
757
758impl<V> TryFromList for BTreeMap<String, V>
759where
760 V: TryFromSexp<Error = SexpError>,
761{
762 type Error = SexpError;
763
764 fn try_from_list(list: List) -> Result<Self, Self::Error> {
765 let n: usize = list
766 .len()
767 .try_into()
768 .expect("list length must be non-negative");
769 let names_sexp = list.names();
770 let mut map = BTreeMap::new();
771
772 for i in 0..n {
773 let idx: isize = i.try_into().expect("index exceeds isize::MAX");
774 let sexp = list.get(idx).ok_or_else(|| {
775 SexpError::from(SexpLengthError {
776 expected: n,
777 actual: i,
778 })
779 })?;
780 let value: V = TryFromSexp::try_from_sexp(sexp)?;
781
782 let key = if let Some(names) = names_sexp {
783 let name_sexp = names.string_elt(idx);
784 if name_sexp == SEXP::na_string() {
785 format!("{i}")
786 } else {
787 let name_ptr = name_sexp.r_char();
788 let name_cstr = unsafe { std::ffi::CStr::from_ptr(name_ptr) };
789 name_cstr.to_str().unwrap_or(&format!("{i}")).to_string()
790 }
791 } else {
792 format!("{i}")
793 };
794
795 map.insert(key, value);
796 }
797 Ok(map)
798 }
799}
800impl<T> IntoList for HashSet<T>
805where
806 T: IntoR,
807{
808 fn into_list(self) -> List {
809 let values: Vec<T> = self.into_iter().collect();
810 values.into_list()
811 }
812}
813
814impl<T> TryFromList for HashSet<T>
815where
816 T: TryFromSexp<Error = SexpError> + Eq + Hash,
817{
818 type Error = SexpError;
819
820 fn try_from_list(list: List) -> Result<Self, Self::Error> {
821 let vec: Vec<T> = TryFromList::try_from_list(list)?;
822 Ok(vec.into_iter().collect())
823 }
824}
825impl<T> IntoList for BTreeSet<T>
830where
831 T: IntoR,
832{
833 fn into_list(self) -> List {
834 let values: Vec<T> = self.into_iter().collect();
835 values.into_list()
836 }
837}
838
839impl<T> TryFromList for BTreeSet<T>
840where
841 T: TryFromSexp<Error = SexpError> + Ord,
842{
843 type Error = SexpError;
844
845 fn try_from_list(list: List) -> Result<Self, Self::Error> {
846 let vec: Vec<T> = TryFromList::try_from_list(list)?;
847 Ok(vec.into_iter().collect())
848 }
849}
850
851impl List {
852 pub fn from_pairs<N, T>(pairs: Vec<(N, T)>) -> Self
854 where
855 N: AsRef<str>,
856 T: IntoR,
857 {
858 let raw: Vec<(N, SEXP)> = pairs.into_iter().map(|(n, v)| (n, v.into_sexp())).collect();
859 Self::from_raw_pairs(raw)
860 }
861
862 pub fn from_values<T: IntoR>(values: Vec<T>) -> Self {
873 values.into_list()
874 }
875
876 pub fn from_raw_values(values: Vec<SEXP>) -> Self {
883 let n: isize = values
884 .len()
885 .try_into()
886 .expect("values length exceeds isize::MAX");
887 unsafe {
888 let list = OwnedProtect::new(ffi::Rf_allocVector(VECSXP, n));
891 for (i, val) in values.into_iter().enumerate() {
892 let idx: isize = i.try_into().expect("index exceeds isize::MAX");
893 list.get().set_vector_elt(idx, val);
894 }
895 List(list.get())
896 }
897 }
898
899 pub fn from_scalars_or_list(elements: &[SEXP]) -> Self {
913 use crate::ffi::SEXPTYPE;
914 use crate::into_r::alloc_r_vector;
915
916 if elements.is_empty() {
917 return Self::from_raw_values(Vec::new());
918 }
919
920 let first_type = elements[0].type_of();
921 let all_scalar_same_type = elements
922 .iter()
923 .all(|&e| unsafe { ffi::Rf_xlength(e) == 1 && e.type_of() == first_type });
924
925 if !all_scalar_same_type {
926 return Self::from_raw_values(elements.to_vec());
927 }
928
929 let n = elements.len();
930 let sexp = match first_type {
931 SEXPTYPE::INTSXP => unsafe {
934 let (v, dst) = alloc_r_vector::<i32>(n);
935 for (slot, &elem) in dst.iter_mut().zip(elements.iter()) {
936 *slot = *elem.as_slice::<i32>().first().expect("scalar has length 1");
937 }
938 v
939 },
940 SEXPTYPE::REALSXP => unsafe {
941 let (v, dst) = alloc_r_vector::<f64>(n);
942 for (slot, &elem) in dst.iter_mut().zip(elements.iter()) {
943 *slot = *elem.as_slice::<f64>().first().expect("scalar has length 1");
944 }
945 v
946 },
947 SEXPTYPE::LGLSXP => unsafe {
948 let (v, dst) = alloc_r_vector::<crate::ffi::RLogical>(n);
949 for (slot, &elem) in dst.iter_mut().zip(elements.iter()) {
950 *slot = *elem
951 .as_slice::<crate::ffi::RLogical>()
952 .first()
953 .expect("scalar has length 1");
954 }
955 v
956 },
957 SEXPTYPE::STRSXP => unsafe {
959 let v = OwnedProtect::new(ffi::Rf_allocVector(SEXPTYPE::STRSXP, n as isize));
960 for (i, &elem) in elements.iter().enumerate() {
961 let idx: isize = i.try_into().expect("index exceeds isize::MAX");
962 v.get().set_string_elt(idx, elem.string_elt(0));
963 }
964 v.get()
965 },
966 _ => return Self::from_raw_values(elements.to_vec()),
967 };
968 List(sexp)
969 }
970
971 pub fn from_raw_pairs<N>(pairs: Vec<(N, SEXP)>) -> Self
979 where
980 N: AsRef<str>,
981 {
982 let n: isize = pairs
983 .len()
984 .try_into()
985 .expect("pairs length exceeds isize::MAX");
986 unsafe {
987 let list = OwnedProtect::new(ffi::Rf_allocVector(VECSXP, n));
990 let names = OwnedProtect::new(ffi::Rf_allocVector(STRSXP, n));
991 for (i, (name, val)) in pairs.into_iter().enumerate() {
992 let idx: isize = i.try_into().expect("index exceeds isize::MAX");
993 list.get().set_vector_elt(idx, val);
994
995 let s = name.as_ref();
996 names.get().set_string_elt(idx, SEXP::charsxp(s));
998 }
999 list.get().set_names(names.get());
1000 List(list.get())
1001 }
1002 }
1003}
1004
1005impl IntoR for List {
1006 type Error = std::convert::Infallible;
1007 fn try_into_sexp(self) -> Result<SEXP, Self::Error> {
1008 Ok(self.into_sexp())
1009 }
1010 unsafe fn try_into_sexp_unchecked(self) -> Result<SEXP, Self::Error> {
1011 self.try_into_sexp()
1012 }
1013 #[inline]
1014 fn into_sexp(self) -> SEXP {
1015 self.0
1016 }
1017}
1018
1019impl IntoR for ListMut {
1020 type Error = std::convert::Infallible;
1021 fn try_into_sexp(self) -> Result<SEXP, Self::Error> {
1022 Ok(self.into_sexp())
1023 }
1024 unsafe fn try_into_sexp_unchecked(self) -> Result<SEXP, Self::Error> {
1025 self.try_into_sexp()
1026 }
1027 #[inline]
1028 fn into_sexp(self) -> SEXP {
1029 self.0
1030 }
1031}
1032
1033#[derive(Debug, Clone)]
1035pub struct DuplicateNameError {
1036 pub name: String,
1038}
1039
1040impl std::fmt::Display for DuplicateNameError {
1041 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1042 write!(f, "list has duplicate name: {:?}", self.name)
1043 }
1044}
1045
1046impl std::error::Error for DuplicateNameError {}
1047
1048#[derive(Debug, Clone)]
1050pub enum ListFromSexpError {
1051 Type(crate::from_r::SexpTypeError),
1053 DuplicateName(DuplicateNameError),
1055}
1056
1057impl std::fmt::Display for ListFromSexpError {
1058 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1059 match self {
1060 ListFromSexpError::Type(e) => write!(f, "{}", e),
1061 ListFromSexpError::DuplicateName(e) => write!(f, "{}", e),
1062 }
1063 }
1064}
1065
1066impl std::error::Error for ListFromSexpError {}
1067
1068impl From<crate::from_r::SexpTypeError> for ListFromSexpError {
1069 fn from(e: crate::from_r::SexpTypeError) -> Self {
1070 ListFromSexpError::Type(e)
1071 }
1072}
1073
1074impl TryFromSexp for List {
1075 type Error = ListFromSexpError;
1076
1077 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1078 let actual = sexp.type_of();
1079
1080 let list_sexp = if actual == VECSXP {
1084 sexp
1085 } else if actual == LISTSXP {
1086 sexp.coerce(VECSXP)
1088 } else {
1089 return Err(crate::from_r::SexpTypeError {
1090 expected: VECSXP,
1091 actual,
1092 }
1093 .into());
1094 };
1095
1096 let names_sexp = list_sexp.get_names();
1098 if names_sexp != SEXP::nil() {
1099 let n = unsafe { ffi::Rf_xlength(list_sexp) };
1100 let n_usize: usize = n.try_into().expect("list length must be non-negative");
1101 let mut seen = HashSet::with_capacity(n_usize);
1102
1103 for i in 0..n {
1104 let name_sexp = names_sexp.string_elt(i);
1105 if name_sexp == SEXP::na_string() {
1107 continue;
1108 }
1109 let name_ptr = name_sexp.r_char();
1111 let name_cstr = unsafe { std::ffi::CStr::from_ptr(name_ptr) };
1112 if let Ok(s) = name_cstr.to_str() {
1113 if s.is_empty() {
1114 continue;
1115 }
1116 if !seen.insert(s) {
1117 return Err(ListFromSexpError::DuplicateName(DuplicateNameError {
1118 name: s.to_string(),
1119 }));
1120 }
1121 }
1122 }
1123 }
1124
1125 Ok(List(list_sexp))
1126 }
1127}
1128
1129impl TryFromSexp for Option<List> {
1130 type Error = SexpError;
1131
1132 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1133 if sexp == SEXP::nil() {
1134 return Ok(None);
1135 }
1136 let list = List::try_from_sexp(sexp).map_err(|e| SexpError::InvalidValue(e.to_string()))?;
1137 Ok(Some(list))
1138 }
1139}
1140
1141impl TryFromSexp for Option<ListMut> {
1142 type Error = SexpError;
1143
1144 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1145 if sexp == SEXP::nil() {
1146 return Ok(None);
1147 }
1148 let list = ListMut::try_from_sexp(sexp)?;
1149 Ok(Some(list))
1150 }
1151}
1152
1153impl TryFromSexp for ListMut {
1154 type Error = SexpError;
1155
1156 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
1157 let actual = sexp.type_of();
1158 if actual != VECSXP {
1159 return Err(SexpTypeError {
1160 expected: VECSXP,
1161 actual,
1162 }
1163 .into());
1164 }
1165 Ok(ListMut(sexp))
1166 }
1167}
1168