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};
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 use crate::ffi::Rf_translateCharUTF8;
74
75 let actual = sexp.type_of();
76 if actual != SEXPTYPE::VECSXP {
77 return Err(SexpTypeError {
78 expected: SEXPTYPE::VECSXP,
79 actual,
80 }
81 .into());
82 }
83
84 let len = sexp.len();
85 let mut map = create_map(len);
86
87 let names = sexp.get_names();
89 let has_names = names.type_of() == SEXPTYPE::STRSXP && names.len() == len;
90
91 let mut seen = HashSet::with_capacity(len);
93
94 for i in 0..len {
95 let key = if has_names {
96 let charsxp = names.string_elt(i as crate::ffi::R_xlen_t);
97 if charsxp == SEXP::na_string() {
98 String::new()
99 } else {
100 let c_str = unsafe { Rf_translateCharUTF8(charsxp) };
101 if c_str.is_null() {
102 String::new()
103 } else {
104 unsafe { std::ffi::CStr::from_ptr(c_str) }
105 .to_str()
106 .unwrap_or("")
107 .to_owned()
108 }
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::ffi::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 let actual = sexp.type_of();
161 if actual != SEXPTYPE::VECSXP {
162 return Err(SexpTypeError {
163 expected: SEXPTYPE::VECSXP,
164 actual,
165 }
166 .into());
167 }
168
169 let len = sexp.len();
170 let mut result = Vec::with_capacity(len);
171
172 for i in 0..len {
173 let elem = sexp.vector_elt(i as crate::ffi::R_xlen_t);
174 let map = M::try_from_sexp(elem).map_err(Into::into)?;
175 result.push(map);
176 }
177
178 Ok(result)
179}
180
181macro_rules! impl_set_try_from_sexp_native {
182 ($set:ident<$t:ty>) => {
183 impl TryFromSexp for $set<$t> {
184 type Error = SexpTypeError;
185
186 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
187 let slice: &[$t] = TryFromSexp::try_from_sexp(sexp)?;
188 Ok(slice.iter().copied().collect())
189 }
190 }
191 };
192}
193
194impl_set_try_from_sexp_native!(HashSet<i32>);
195impl_set_try_from_sexp_native!(HashSet<u8>);
196impl_set_try_from_sexp_native!(HashSet<RLogical>);
197impl_set_try_from_sexp_native!(BTreeSet<i32>);
198impl_set_try_from_sexp_native!(BTreeSet<u8>);
199
200macro_rules! impl_vec_try_from_sexp_native {
201 ($t:ty) => {
202 impl TryFromSexp for Vec<$t> {
203 type Error = SexpTypeError;
204
205 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
206 let slice: &[$t] = TryFromSexp::try_from_sexp(sexp)?;
207 Ok(slice.to_vec())
208 }
209 }
210 };
211}
212
213impl_vec_try_from_sexp_native!(i32);
214impl_vec_try_from_sexp_native!(f64);
215impl_vec_try_from_sexp_native!(u8);
216impl_vec_try_from_sexp_native!(RLogical);
217impl_vec_try_from_sexp_native!(crate::ffi::Rcomplex);
218
219macro_rules! impl_boxed_slice_try_from_sexp_native {
220 ($t:ty) => {
221 impl TryFromSexp for Box<[$t]> {
222 type Error = SexpTypeError;
223
224 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
225 let slice: &[$t] = TryFromSexp::try_from_sexp(sexp)?;
226 Ok(slice.into())
227 }
228 }
229 };
230}
231
232impl_boxed_slice_try_from_sexp_native!(i32);
233impl_boxed_slice_try_from_sexp_native!(f64);
234impl_boxed_slice_try_from_sexp_native!(u8);
235impl_boxed_slice_try_from_sexp_native!(RLogical);
236impl_boxed_slice_try_from_sexp_native!(crate::ffi::Rcomplex);
237