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 const NATIVE_BORROW: Option<crate::from_r::NativeBorrow> = crate::from_r::NativeBorrow::in_list(V::NATIVE_BORROW);
30
31 type Error = SexpError;
32 #[inline]
35 fn __mx_has_na(&self) -> bool {
36 self.values().any(V::__mx_has_na)
37 }
38
39 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
40 named_list_to_map(sexp, $create)
41 }
42 }
43 };
44}
45
46#[doc = r" Convert R named list (VECSXP) to HashMap<String, V>."]
#[doc = r""]
#[doc =
r" See `named_list_to_map` for NA/empty name handling (elements with NA/empty"]
#[doc = r#" names map to key `""` and may silently overwrite each other)."#]
impl<V: TryFromSexp> TryFromSexp for HashMap<String, V> where
V::Error: Into<SexpError> {
const NATIVE_BORROW: Option<crate::from_r::NativeBorrow> =
crate::from_r::NativeBorrow::in_list(V::NATIVE_BORROW);
type Error = SexpError;
#[inline]
fn __mx_has_na(&self) -> bool { self.values().any(V::__mx_has_na) }
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
named_list_to_map(sexp, HashMap::with_capacity)
}
}impl_map_try_from_sexp!(
47 HashMap, HashMap::with_capacity
52);
53#[doc = r" Convert R named list (VECSXP) to BTreeMap<String, V>."]
#[doc = r""]
#[doc =
r" See `named_list_to_map` for NA/empty name handling (elements with NA/empty"]
#[doc = r#" names map to key `""` and may silently overwrite each other)."#]
impl<V: TryFromSexp> TryFromSexp for BTreeMap<String, V> where
V::Error: Into<SexpError> {
const NATIVE_BORROW: Option<crate::from_r::NativeBorrow> =
crate::from_r::NativeBorrow::in_list(V::NATIVE_BORROW);
type Error = SexpError;
#[inline]
fn __mx_has_na(&self) -> bool { self.values().any(V::__mx_has_na) }
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
named_list_to_map(sexp, |_| BTreeMap::new())
}
}impl_map_try_from_sexp!(
54 BTreeMap, |_| BTreeMap::new()
59);
60
61fn named_list_to_map<V, M, F>(sexp: SEXP, create_map: F) -> Result<M, SexpError>
85where
86 V: TryFromSexp,
87 V::Error: Into<SexpError>,
88 M: Extend<(String, V)>,
89 F: FnOnce(usize) -> M,
90{
91 let actual = sexp.type_of();
92 if actual != SEXPTYPE::VECSXP {
93 return Err(SexpTypeError {
94 expected: SEXPTYPE::VECSXP,
95 actual,
96 }
97 .into());
98 }
99
100 let len = sexp.len();
101 let mut map = create_map(len);
102
103 let names = sexp.get_names();
105 let has_names = names.type_of() == SEXPTYPE::STRSXP && names.len() == len;
106
107 let mut seen = HashSet::with_capacity(len);
109
110 for i in 0..len {
111 let key = if has_names {
112 let charsxp = names.string_elt(i as crate::R_xlen_t);
113 if charsxp == SEXP::na_string() {
114 String::new()
115 } else {
116 unsafe { charsxp_to_str(charsxp) }.to_owned()
117 }
118 } else {
119 i.to_string()
121 };
122
123 if !key.is_empty() && !seen.insert(key.clone()) {
125 return Err(SexpError::DuplicateName(key));
126 }
127
128 let elem = sexp.vector_elt(i as crate::R_xlen_t);
129 let value = V::try_from_sexp(elem).map_err(|e| e.into())?;
130 map.extend(std::iter::once((key, value)));
131 }
132
133 Ok(map)
134}
135
136macro_rules! impl_vec_map_try_from_sexp {
137 ($(#[$meta:meta])* $map_ty:ident) => {
138 $(#[$meta])*
139 impl<V: TryFromSexp> TryFromSexp for Vec<$map_ty<String, V>>
140 where
141 V::Error: Into<SexpError>,
142 {
143 const NATIVE_BORROW: Option<crate::from_r::NativeBorrow> = crate::from_r::NativeBorrow::in_list(<$map_ty<String, V> as TryFromSexp>::NATIVE_BORROW);
144
145 type Error = SexpError;
146
147 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
148 list_to_vec_of_maps::<$map_ty<String, V>>(sexp)
149 }
150 }
151 };
152}
153
154#[doc = r" Convert R list of named lists to `Vec<HashMap<String, V>>`."]
impl<V: TryFromSexp> TryFromSexp for Vec<HashMap<String, V>> where
V::Error: Into<SexpError> {
const NATIVE_BORROW: Option<crate::from_r::NativeBorrow> =
crate::from_r::NativeBorrow::in_list(<HashMap<String, V> as
TryFromSexp>::NATIVE_BORROW);
type Error = SexpError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
list_to_vec_of_maps::<HashMap<String, V>>(sexp)
}
}impl_vec_map_try_from_sexp!(
155 HashMap
157);
158#[doc = r" Convert R list of named lists to `Vec<BTreeMap<String, V>>`."]
impl<V: TryFromSexp> TryFromSexp for Vec<BTreeMap<String, V>> where
V::Error: Into<SexpError> {
const NATIVE_BORROW: Option<crate::from_r::NativeBorrow> =
crate::from_r::NativeBorrow::in_list(<BTreeMap<String, V> as
TryFromSexp>::NATIVE_BORROW);
type Error = SexpError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
list_to_vec_of_maps::<BTreeMap<String, V>>(sexp)
}
}impl_vec_map_try_from_sexp!(
159 BTreeMap
161);
162
163fn list_to_vec_of_maps<M>(sexp: SEXP) -> Result<Vec<M>, SexpError>
166where
167 M: TryFromSexp,
168 M::Error: Into<SexpError>,
169{
170 map_vecsxp_with(sexp, |_i, elem| M::try_from_sexp(elem).map_err(Into::into))
171}
172
173macro_rules! impl_set_try_from_sexp_native {
174 ($set:ident<$t:ty>) => {
175 impl TryFromSexp for $set<$t> {
176 type Error = SexpTypeError;
177
178 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
179 let slice: &[$t] = TryFromSexp::try_from_sexp(sexp)?;
180 Ok(slice.iter().copied().collect())
181 }
182 }
183 };
184}
185
186impl TryFromSexp for HashSet<i32> {
type Error = SexpTypeError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let slice: &[i32] = TryFromSexp::try_from_sexp(sexp)?;
Ok(slice.iter().copied().collect())
}
}impl_set_try_from_sexp_native!(HashSet<i32>);
187impl TryFromSexp for HashSet<u8> {
type Error = SexpTypeError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let slice: &[u8] = TryFromSexp::try_from_sexp(sexp)?;
Ok(slice.iter().copied().collect())
}
}impl_set_try_from_sexp_native!(HashSet<u8>);
188impl TryFromSexp for HashSet<RLogical> {
type Error = SexpTypeError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let slice: &[RLogical] = TryFromSexp::try_from_sexp(sexp)?;
Ok(slice.iter().copied().collect())
}
}impl_set_try_from_sexp_native!(HashSet<RLogical>);
189impl TryFromSexp for BTreeSet<i32> {
type Error = SexpTypeError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let slice: &[i32] = TryFromSexp::try_from_sexp(sexp)?;
Ok(slice.iter().copied().collect())
}
}impl_set_try_from_sexp_native!(BTreeSet<i32>);
190impl TryFromSexp for BTreeSet<u8> {
type Error = SexpTypeError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let slice: &[u8] = TryFromSexp::try_from_sexp(sexp)?;
Ok(slice.iter().copied().collect())
}
}impl_set_try_from_sexp_native!(BTreeSet<u8>);
191
192macro_rules! impl_vec_try_from_sexp_native {
193 ($t:ty) => {
194 impl TryFromSexp for Vec<$t> {
195 type Error = SexpTypeError;
196
197 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
198 let slice: &[$t] = TryFromSexp::try_from_sexp(sexp)?;
199 Ok(slice.to_vec())
200 }
201 }
202 };
203}
204
205impl TryFromSexp for Vec<i32> {
type Error = SexpTypeError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let slice: &[i32] = TryFromSexp::try_from_sexp(sexp)?;
Ok(slice.to_vec())
}
}impl_vec_try_from_sexp_native!(i32);
206impl TryFromSexp for Vec<f64> {
type Error = SexpTypeError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let slice: &[f64] = TryFromSexp::try_from_sexp(sexp)?;
Ok(slice.to_vec())
}
}impl_vec_try_from_sexp_native!(f64);
207impl TryFromSexp for Vec<u8> {
type Error = SexpTypeError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let slice: &[u8] = TryFromSexp::try_from_sexp(sexp)?;
Ok(slice.to_vec())
}
}impl_vec_try_from_sexp_native!(u8);
208impl TryFromSexp for Vec<RLogical> {
type Error = SexpTypeError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let slice: &[RLogical] = TryFromSexp::try_from_sexp(sexp)?;
Ok(slice.to_vec())
}
}impl_vec_try_from_sexp_native!(RLogical);
209impl TryFromSexp for Vec<crate::Rcomplex> {
type Error = SexpTypeError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let slice: &[crate::Rcomplex] = TryFromSexp::try_from_sexp(sexp)?;
Ok(slice.to_vec())
}
}impl_vec_try_from_sexp_native!(crate::Rcomplex);
210