miniextendr_api/from_r/
collections.rs1use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
8
9use crate::ffi::{RLogical, SEXP, SEXPTYPE, SexpExt};
10use crate::from_r::{SexpError, SexpTypeError, TryFromSexp, charsxp_to_str};
11
12macro_rules! impl_map_try_from_sexp {
13 ($(#[$meta:meta])* $map_ty:ident, $create:expr) => {
14 $(#[$meta])*
15 impl<V: TryFromSexp> TryFromSexp for $map_ty<String, V>
16 where
17 V::Error: Into<SexpError>,
18 {
19 type Error = SexpError;
20
21 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
22 named_list_to_map(sexp, $create)
23 }
24 }
25 };
26}
27
28impl_map_try_from_sexp!(
29 HashMap, HashMap::with_capacity
34);
35impl_map_try_from_sexp!(
36 BTreeMap, |_| BTreeMap::new()
41);
42
43fn named_list_to_map<V, M, F>(sexp: SEXP, create_map: F) -> Result<M, SexpError>
67where
68 V: TryFromSexp,
69 V::Error: Into<SexpError>,
70 M: Extend<(String, V)>,
71 F: FnOnce(usize) -> M,
72{
73 let actual = sexp.type_of();
74 if actual != SEXPTYPE::VECSXP {
75 return Err(SexpTypeError {
76 expected: SEXPTYPE::VECSXP,
77 actual,
78 }
79 .into());
80 }
81
82 let len = sexp.len();
83 let mut map = create_map(len);
84
85 let names = sexp.get_names();
87 let has_names = names.type_of() == SEXPTYPE::STRSXP && names.len() == len;
88
89 let mut seen = HashSet::with_capacity(len);
91
92 for i in 0..len {
93 let key = if has_names {
94 let charsxp = names.string_elt(i as crate::ffi::R_xlen_t);
95 if charsxp == SEXP::na_string() {
96 String::new()
97 } else {
98 unsafe { charsxp_to_str(charsxp) }.to_owned()
99 }
100 } else {
101 i.to_string()
103 };
104
105 if !key.is_empty() && !seen.insert(key.clone()) {
107 return Err(SexpError::DuplicateName(key));
108 }
109
110 let elem = sexp.vector_elt(i as crate::ffi::R_xlen_t);
111 let value = V::try_from_sexp(elem).map_err(|e| e.into())?;
112 map.extend(std::iter::once((key, value)));
113 }
114
115 Ok(map)
116}
117
118macro_rules! impl_vec_map_try_from_sexp {
119 ($(#[$meta:meta])* $map_ty:ident) => {
120 $(#[$meta])*
121 impl<V: TryFromSexp> TryFromSexp for Vec<$map_ty<String, V>>
122 where
123 V::Error: Into<SexpError>,
124 {
125 type Error = SexpError;
126
127 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
128 list_to_vec_of_maps::<$map_ty<String, V>>(sexp)
129 }
130 }
131 };
132}
133
134impl_vec_map_try_from_sexp!(
135 HashMap
137);
138impl_vec_map_try_from_sexp!(
139 BTreeMap
141);
142
143fn list_to_vec_of_maps<M>(sexp: SEXP) -> Result<Vec<M>, SexpError>
146where
147 M: TryFromSexp,
148 M::Error: Into<SexpError>,
149{
150 let actual = sexp.type_of();
151 if actual != SEXPTYPE::VECSXP {
152 return Err(SexpTypeError {
153 expected: SEXPTYPE::VECSXP,
154 actual,
155 }
156 .into());
157 }
158
159 let len = sexp.len();
160 let mut result = Vec::with_capacity(len);
161
162 for i in 0..len {
163 let elem = sexp.vector_elt(i as crate::ffi::R_xlen_t);
164 let map = M::try_from_sexp(elem).map_err(Into::into)?;
165 result.push(map);
166 }
167
168 Ok(result)
169}
170
171macro_rules! impl_set_try_from_sexp_native {
172 ($set:ident<$t:ty>) => {
173 impl TryFromSexp for $set<$t> {
174 type Error = SexpTypeError;
175
176 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
177 let slice: &[$t] = TryFromSexp::try_from_sexp(sexp)?;
178 Ok(slice.iter().copied().collect())
179 }
180 }
181 };
182}
183
184impl_set_try_from_sexp_native!(HashSet<i32>);
185impl_set_try_from_sexp_native!(HashSet<u8>);
186impl_set_try_from_sexp_native!(HashSet<RLogical>);
187impl_set_try_from_sexp_native!(BTreeSet<i32>);
188impl_set_try_from_sexp_native!(BTreeSet<u8>);
189
190macro_rules! impl_vec_try_from_sexp_native {
191 ($t:ty) => {
192 impl TryFromSexp for Vec<$t> {
193 type Error = SexpTypeError;
194
195 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
196 let slice: &[$t] = TryFromSexp::try_from_sexp(sexp)?;
197 Ok(slice.to_vec())
198 }
199 }
200 };
201}
202
203impl_vec_try_from_sexp_native!(i32);
204impl_vec_try_from_sexp_native!(f64);
205impl_vec_try_from_sexp_native!(u8);
206impl_vec_try_from_sexp_native!(RLogical);
207impl_vec_try_from_sexp_native!(crate::ffi::Rcomplex);
208
209macro_rules! impl_boxed_slice_try_from_sexp_native {
210 ($t:ty) => {
211 impl TryFromSexp for Box<[$t]> {
212 type Error = SexpTypeError;
213
214 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
215 let slice: &[$t] = TryFromSexp::try_from_sexp(sexp)?;
216 Ok(slice.into())
217 }
218 }
219 };
220}
221
222impl_boxed_slice_try_from_sexp_native!(i32);
223impl_boxed_slice_try_from_sexp_native!(f64);
224impl_boxed_slice_try_from_sexp_native!(u8);
225impl_boxed_slice_try_from_sexp_native!(RLogical);
226impl_boxed_slice_try_from_sexp_native!(crate::ffi::Rcomplex);
227