miniextendr_api/from_r/
collections.rs1use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
18
19use crate::from_r::{SexpError, SexpTypeError, TryFromSexp, charsxp_to_str, map_vecsxp_with};
20use crate::{RLogical, SEXP, SEXPTYPE, SexpExt};
21
22macro_rules! impl_map_try_from_sexp {
23 ($(#[$meta:meta])* $map_ty:ident, $create:expr) => {
24 $(#[$meta])*
25 impl<V: TryFromSexp> TryFromSexp for $map_ty<String, V>
26 where
27 V::Error: Into<SexpError>,
28 {
29 type Error = SexpError;
30
31 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
32 named_list_to_map(sexp, $create)
33 }
34 }
35 };
36}
37
38impl_map_try_from_sexp!(
39 HashMap, HashMap::with_capacity
44);
45impl_map_try_from_sexp!(
46 BTreeMap, |_| BTreeMap::new()
51);
52
53fn named_list_to_map<V, M, F>(sexp: SEXP, create_map: F) -> Result<M, SexpError>
77where
78 V: TryFromSexp,
79 V::Error: Into<SexpError>,
80 M: Extend<(String, V)>,
81 F: FnOnce(usize) -> M,
82{
83 let actual = sexp.type_of();
84 if actual != SEXPTYPE::VECSXP {
85 return Err(SexpTypeError {
86 expected: SEXPTYPE::VECSXP,
87 actual,
88 }
89 .into());
90 }
91
92 let len = sexp.len();
93 let mut map = create_map(len);
94
95 let names = sexp.get_names();
97 let has_names = names.type_of() == SEXPTYPE::STRSXP && names.len() == len;
98
99 let mut seen = HashSet::with_capacity(len);
101
102 for i in 0..len {
103 let key = if has_names {
104 let charsxp = names.string_elt(i as crate::R_xlen_t);
105 if charsxp == SEXP::na_string() {
106 String::new()
107 } else {
108 unsafe { charsxp_to_str(charsxp) }.to_owned()
109 }
110 } else {
111 i.to_string()
113 };
114
115 if !key.is_empty() && !seen.insert(key.clone()) {
117 return Err(SexpError::DuplicateName(key));
118 }
119
120 let elem = sexp.vector_elt(i as crate::R_xlen_t);
121 let value = V::try_from_sexp(elem).map_err(|e| e.into())?;
122 map.extend(std::iter::once((key, value)));
123 }
124
125 Ok(map)
126}
127
128macro_rules! impl_vec_map_try_from_sexp {
129 ($(#[$meta:meta])* $map_ty:ident) => {
130 $(#[$meta])*
131 impl<V: TryFromSexp> TryFromSexp for Vec<$map_ty<String, V>>
132 where
133 V::Error: Into<SexpError>,
134 {
135 type Error = SexpError;
136
137 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
138 list_to_vec_of_maps::<$map_ty<String, V>>(sexp)
139 }
140 }
141 };
142}
143
144impl_vec_map_try_from_sexp!(
145 HashMap
147);
148impl_vec_map_try_from_sexp!(
149 BTreeMap
151);
152
153fn list_to_vec_of_maps<M>(sexp: SEXP) -> Result<Vec<M>, SexpError>
156where
157 M: TryFromSexp,
158 M::Error: Into<SexpError>,
159{
160 map_vecsxp_with(sexp, |_i, elem| M::try_from_sexp(elem).map_err(Into::into))
161}
162
163macro_rules! impl_set_try_from_sexp_native {
164 ($set:ident<$t:ty>) => {
165 impl TryFromSexp for $set<$t> {
166 type Error = SexpTypeError;
167
168 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
169 let slice: &[$t] = TryFromSexp::try_from_sexp(sexp)?;
170 Ok(slice.iter().copied().collect())
171 }
172 }
173 };
174}
175
176impl_set_try_from_sexp_native!(HashSet<i32>);
177impl_set_try_from_sexp_native!(HashSet<u8>);
178impl_set_try_from_sexp_native!(HashSet<RLogical>);
179impl_set_try_from_sexp_native!(BTreeSet<i32>);
180impl_set_try_from_sexp_native!(BTreeSet<u8>);
181
182macro_rules! impl_vec_try_from_sexp_native {
183 ($t:ty) => {
184 impl TryFromSexp for Vec<$t> {
185 type Error = SexpTypeError;
186
187 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
188 let slice: &[$t] = TryFromSexp::try_from_sexp(sexp)?;
189 Ok(slice.to_vec())
190 }
191 }
192 };
193}
194
195impl_vec_try_from_sexp_native!(i32);
196impl_vec_try_from_sexp_native!(f64);
197impl_vec_try_from_sexp_native!(u8);
198impl_vec_try_from_sexp_native!(RLogical);
199impl_vec_try_from_sexp_native!(crate::Rcomplex);
200