aorist_extendr_api/robj/
try_from_robj.rs1use 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 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}