Skip to main content

aorist_extendr_api/robj/
try_from_robj.rs

1//! Conversions to Robj
2
3use super::*;
4
5macro_rules! impl_try_from_scalar {
6    ($t: ty) => {
7        impl TryFrom<Robj> for $t {
8            type Error = Error;
9
10            fn try_from(robj: Robj) -> Result<Self> {
11                if let Some(v) = robj.as_integer_slice() {
12                    match v.len() {
13                        0 => Err(Error::ExpectedNonZeroLength(robj)),
14                        1 => {
15                            if !v[0].is_na() {
16                                Ok(v[0] as Self)
17                            } else {
18                                Err(Error::MustNotBeNA(robj))
19                            }
20                        }
21                        _ => Err(Error::ExpectedScalar(robj)),
22                    }
23                } else if let Some(v) = robj.as_real_slice() {
24                    match v.len() {
25                        0 => Err(Error::ExpectedNonZeroLength(robj)),
26                        1 => {
27                            if !v[0].is_na() {
28                                Ok(v[0] as Self)
29                            } else {
30                                Err(Error::MustNotBeNA(robj))
31                            }
32                        }
33                        _ => Err(Error::ExpectedScalar(robj)),
34                    }
35                } else {
36                    Err(Error::ExpectedNumeric(robj))
37                }
38            }
39        }
40    };
41}
42
43impl_try_from_scalar!(u8);
44impl_try_from_scalar!(u16);
45impl_try_from_scalar!(u32);
46impl_try_from_scalar!(u64);
47impl_try_from_scalar!(i8);
48impl_try_from_scalar!(i16);
49impl_try_from_scalar!(i32);
50impl_try_from_scalar!(i64);
51impl_try_from_scalar!(f32);
52impl_try_from_scalar!(f64);
53
54impl TryFrom<Robj> for Bool {
55    type Error = Error;
56
57    fn try_from(robj: Robj) -> Result<Self> {
58        if let Some(v) = robj.as_logical_slice() {
59            match v.len() {
60                0 => Err(Error::ExpectedNonZeroLength(robj)),
61                1 => Ok(v[0]),
62                _ => Err(Error::ExpectedScalar(robj)),
63            }
64        } else {
65            Err(Error::ExpectedLogical(robj))
66        }
67    }
68}
69
70impl TryFrom<Robj> for bool {
71    type Error = Error;
72
73    fn try_from(robj: Robj) -> Result<Self> {
74        if robj.is_na() {
75            Err(Error::MustNotBeNA(robj))
76        } else {
77            Ok(<Bool>::try_from(robj)?.is_true())
78        }
79    }
80}
81
82impl TryFrom<Robj> for &str {
83    type Error = Error;
84
85    fn try_from(robj: Robj) -> Result<Self> {
86        if robj.is_na() {
87            return Err(Error::MustNotBeNA(robj));
88        }
89        match robj.len() {
90            0 => Err(Error::ExpectedNonZeroLength(robj)),
91            1 => {
92                if let Some(s) = robj.as_str() {
93                    Ok(s)
94                } else {
95                    Err(Error::ExpectedString(robj))
96                }
97            }
98            _ => Err(Error::ExpectedScalar(robj)),
99        }
100    }
101}
102
103impl TryFrom<Robj> for String {
104    type Error = Error;
105
106    fn try_from(robj: Robj) -> Result<Self> {
107        <&str>::try_from(robj).map(|s| s.to_string())
108    }
109}
110
111impl TryFrom<Robj> for Vec<i32> {
112    type Error = Error;
113
114    fn try_from(robj: Robj) -> Result<Self> {
115        if let Some(v) = robj.as_integer_slice() {
116            Ok(Vec::from(v))
117        } else {
118            Err(Error::ExpectedInteger(robj))
119        }
120    }
121}
122
123impl TryFrom<Robj> for Vec<f64> {
124    type Error = Error;
125
126    fn try_from(robj: Robj) -> Result<Self> {
127        if let Some(v) = robj.as_real_slice() {
128            Ok(Vec::from(v))
129        } else {
130            Err(Error::ExpectedReal(robj))
131        }
132    }
133}
134
135impl TryFrom<Robj> for Vec<String> {
136    type Error = Error;
137
138    fn try_from(robj: Robj) -> Result<Self> {
139        if let Some(iter) = robj.as_str_iter() {
140            // check for NA's in the string vector
141            if iter.clone().any(|s| s.is_na()) {
142                Err(Error::MustNotBeNA(robj))
143            } else {
144                Ok(iter.map(|s| s.to_string()).collect::<Vec<String>>())
145            }
146        } else {
147            Err(Error::ExpectedString(robj))
148        }
149    }
150}
151
152macro_rules! impl_option {
153    ($type : ty) => {
154        impl TryFrom<Robj> for Option<$type> {
155            type Error = Error;
156
157            fn try_from(robj: Robj) -> Result<Self> {
158                if robj.is_na() {
159                    Ok(None)
160                } else {
161                    Ok(Some(<$type>::try_from(robj)?))
162                }
163            }
164        }
165    };
166}
167
168impl_option!(u8);
169impl_option!(u16);
170impl_option!(u32);
171impl_option!(u64);
172impl_option!(i8);
173impl_option!(i16);
174impl_option!(i32);
175impl_option!(i64);
176impl_option!(f32);
177impl_option!(f64);
178impl_option!(Bool);
179impl_option!(bool);
180impl_option!(&str);
181impl_option!(String);
182impl_option!(Vec<i32>);
183impl_option!(Vec<f64>);
184impl_option!(Vec<String>);
185
186impl TryFrom<Robj> for HashMap<String, Robj> {
187    type Error = Error;
188
189    fn try_from(robj: Robj) -> Result<Self> {
190        if let Some(iter) = robj.as_list().map(|l| l.iter()) {
191            Ok(iter
192                .map(|(k, v)| (k.to_string(), v))
193                .collect::<HashMap<String, Robj>>())
194        } else {
195            Err(Error::ExpectedList(robj))
196        }
197    }
198}
199
200impl TryFrom<Robj> for HashMap<&str, Robj> {
201    type Error = Error;
202
203    fn try_from(robj: Robj) -> Result<Self> {
204        if let Some(iter) = robj.as_list().map(|l| l.iter()) {
205            Ok(iter.map(|(k, v)| (k, v)).collect::<HashMap<&str, Robj>>())
206        } else {
207            Err(Error::ExpectedList(robj))
208        }
209    }
210}