aorist_extendr_api/robj/
from_robj.rs1use super::*;
2
3pub trait FromRobj<'a>: Sized {
5 fn from_robj(_robj: &'a Robj) -> std::result::Result<Self, &'static str> {
7 Err("unable to convert value from R object")
8 }
9}
10
11macro_rules! impl_prim_from_robj {
12 ($t: ty) => {
13 impl<'a> FromRobj<'a> for $t {
14 fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
15 if let Some(v) = robj.as_integer_slice() {
16 match v.len() {
17 0 => Err("Input must be of length 1. Vector of length zero given."),
18 1 => {
19 if !v[0].is_na() {
20 Ok(v[0] as Self)
21 } else {
22 Err("Input must not be NA.")
23 }
24 }
25 _ => Err("Input must be of length 1. Vector of length >1 given."),
26 }
27 } else if let Some(v) = robj.as_real_slice() {
28 match v.len() {
29 0 => Err("Input must be of length 1. Vector of length zero given."),
30 1 => {
31 if !v[0].is_na() {
32 Ok(v[0] as Self)
33 } else {
34 Err("Input must not be NA.")
35 }
36 }
37 _ => Err("Input must be of length 1. Vector of length >1 given."),
38 }
39 } else {
40 Err("unable to convert R object to primitive")
41 }
42 }
43 }
44 };
45}
46
47impl_prim_from_robj!(u8);
48impl_prim_from_robj!(u16);
49impl_prim_from_robj!(u32);
50impl_prim_from_robj!(u64);
51impl_prim_from_robj!(i8);
52impl_prim_from_robj!(i16);
53impl_prim_from_robj!(i32);
54impl_prim_from_robj!(i64);
55impl_prim_from_robj!(f32);
56impl_prim_from_robj!(f64);
57
58impl<'a> FromRobj<'a> for bool {
59 fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
60 if let Some(v) = robj.as_logical_slice() {
61 match v.len() {
62 0 => Err("Input must be of length 1. Vector of length zero given."),
63 1 => {
64 if !v[0].is_na() {
65 Ok(v[0].to_bool())
66 } else {
67 Err("Input must not be NA.")
68 }
69 }
70 _ => Err("Input must be of length 1. Vector of length >1 given."),
71 }
72 } else {
73 Err("Not a logical object.")
74 }
75 }
76}
77
78impl<'a> FromRobj<'a> for &'a str {
79 fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
80 if robj.is_na() {
81 Err("Input must not be NA.")
82 } else if let Some(s) = robj.as_str() {
83 Ok(s)
84 } else {
85 Err("Not a string object.")
86 }
87 }
88}
89
90impl<'a> FromRobj<'a> for String {
91 fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
92 if robj.is_na() {
93 Err("Input must not be NA.")
94 } else if let Some(s) = robj.as_str() {
95 Ok(s.to_string())
96 } else {
97 Err("not a string object")
98 }
99 }
100}
101
102impl<'a> FromRobj<'a> for Vec<i32> {
103 fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
104 if let Some(v) = robj.as_integer_slice() {
105 Ok(Vec::from(v))
106 } else {
107 Err("not an integer or logical vector")
108 }
109 }
110}
111
112impl<'a> FromRobj<'a> for Vec<f64> {
113 fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
114 if let Some(v) = robj.as_real_slice() {
115 Ok(Vec::from(v))
116 } else {
117 Err("not a floating point vector")
118 }
119 }
120}
121
122impl<'a> FromRobj<'a> for Vec<String> {
123 fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
124 if robj.is_na() {
125 Err("Input must be a character vector. Got 'NA'.")
126 } else if let Some(v) = robj.as_string_vector() {
127 let str_vec = v.to_vec();
128 if let Some(_str) = str_vec.iter().find(|&s| *s == na_str()) {
130 Err("Input vector cannot contain NA's.")
131 } else {
132 Ok(str_vec)
133 }
134 } else {
135 Err("Input must be a character vector.")
136 }
137 }
138}
139
140macro_rules! impl_iter_from_robj {
141 ($t: ty, $iter_fn: ident, $msg: expr) => {
142 impl<'a> FromRobj<'a> for $t {
143 fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
144 if let Some(v) = robj.$iter_fn() {
145 Ok(v)
146 } else {
147 Err($msg)
148 }
149 }
150 }
151 };
152}
153
154impl_iter_from_robj!(StrIter, as_str_iter, "Not a character vector.");
155impl_iter_from_robj!(Int, as_integer_iter, "Not an integer vector.");
156impl_iter_from_robj!(Real, as_real_iter, "Not a real vector.");
157impl_iter_from_robj!(Logical, as_logical_iter, "Not a logical vector.");
158
159impl<'a> FromRobj<'a> for Robj {
161 fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
162 Ok(unsafe { new_owned(robj.get()) })
163 }
164}
165
166impl<'a> FromRobj<'a> for HashMap<String, Robj> {
167 fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
168 if let Some(iter) = robj.as_list().map(|l| l.iter()) {
169 Ok(iter
170 .map(|(k, v)| (k.to_string(), v))
171 .collect::<HashMap<String, Robj>>())
172 } else {
173 Err("expected a list")
174 }
175 }
176}
177
178impl<'a> FromRobj<'a> for HashMap<&str, Robj> {
179 fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
180 if let Some(iter) = robj.as_list().map(|l| l.iter()) {
181 Ok(iter.map(|(k, v)| (k, v)).collect::<HashMap<&str, Robj>>())
182 } else {
183 Err("expected a list")
184 }
185 }
186}
187
188impl<'a> FromRobj<'a> for Option<i32> {
190 fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
191 if robj.is_na() {
192 Ok(None)
193 } else if let Some(val) = robj.as_integer() {
194 Ok(Some(val))
195 } else {
196 Err("expected an integer scalar")
197 }
198 }
199}
200
201impl<'a> FromRobj<'a> for Option<bool> {
203 fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
204 if let Some(val) = robj.as_logical() {
205 if val.is_na() {
206 Ok(None)
207 } else {
208 Ok(Some(val.is_true()))
209 }
210 } else {
211 Err("expected a logical scalar")
212 }
213 }
214}
215
216impl<'a> FromRobj<'a> for Option<f64> {
218 fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
219 if robj.is_na() {
220 Ok(None)
221 } else if let Some(val) = robj.as_real() {
222 Ok(Some(val))
223 } else {
224 Err("expected a real scalar")
225 }
226 }
227}
228
229impl<'a> FromRobj<'a> for Option<&'a str> {
231 fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
232 if robj.is_na() {
233 Ok(None)
234 } else if let Some(val) = robj.as_str() {
235 Ok(Some(val))
236 } else {
237 Err("expected a character scalar")
238 }
239 }
240}
241
242impl<'a> FromRobj<'a> for Option<String> {
244 fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
245 if robj.is_na() {
246 Ok(None)
247 } else if let Some(val) = robj.as_str() {
248 Ok(Some(val.to_string()))
249 } else {
250 Err("expected a character scalar")
251 }
252 }
253}
254
255impl<'a, T> FromRobj<'a> for &'a [T]
256where
257 Robj: AsTypedSlice<'a, T>,
258{
259 fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
260 if let Some(slice) = robj.as_typed_slice() {
261 Ok(slice)
262 } else {
263 Err("Expected a vector type.")
264 }
265 }
266}
267
268impl<'a, T: 'a> FromRobj<'a> for RArray<T, [usize; 2]>
270where
271 Robj: AsTypedSlice<'a, T>,
272{
273 fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
274 match robj.as_matrix() {
275 Some(x) => Ok(x),
276 _ => Err("Expected a matrix."),
277 }
278 }
279}
280
281impl<'a, T: 'a> FromRobj<'a> for RMatrix3D<T>
283where
284 Robj: AsTypedSlice<'a, T>,
285{
286 fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
287 match robj.as_matrix3d() {
288 Some(x) => Ok(x),
289 _ => Err("Expected a matrix."),
290 }
291 }
292}