1use super::*;
10use crate as extendr_api;
11use crate::conversions::try_into_int::FloatToInt;
12
13macro_rules! impl_try_from_scalar_integer {
14 ($t:ty) => {
15 impl TryFrom<&Robj> for $t {
16 type Error = Error;
17
18 fn try_from(robj: &Robj) -> Result<Self> {
20 match robj.len() {
22 0 => return Err(Error::ExpectedNonZeroLength(robj.clone())),
23 1 => {}
24 _ => return Err(Error::ExpectedScalar(robj.clone())),
25 };
26
27 if robj.is_na() {
29 return Err(Error::MustNotBeNA(robj.clone()));
30 }
31
32 if let Some(v) = robj.as_integer() {
37 return Self::try_from(v).map_err(|_| Error::OutOfLimits(robj.clone()));
38 }
39
40 if let Some(v) = robj.as_real() {
44 return v
45 .try_into_int()
46 .map_err(|conv_err| Error::ExpectedWholeNumber(robj.clone(), conv_err));
47 }
48
49 Err(Error::ExpectedNumeric(robj.clone()))
50 }
51 }
52 };
53}
54
55macro_rules! impl_try_from_scalar_real {
56 ($t:ty) => {
57 impl TryFrom<&Robj> for $t {
58 type Error = Error;
59
60 fn try_from(robj: &Robj) -> Result<Self> {
62 match robj.len() {
64 0 => return Err(Error::ExpectedNonZeroLength(robj.clone())),
65 1 => {}
66 _ => return Err(Error::ExpectedScalar(robj.clone())),
67 };
68
69 if robj.is_na() {
71 return Err(Error::MustNotBeNA(robj.clone()));
72 }
73
74 if let Some(v) = robj.as_real() {
78 return Ok(v as Self);
80 }
81 if let Some(v) = robj.as_integer() {
82 return Ok(v as Self);
84 }
85
86 Err(Error::ExpectedNumeric(robj.clone()))
87 }
88 }
89 };
90}
91
92macro_rules! impl_typed_slice_conversions {
93 ($type:ty, $error:ident, $desc:expr) => {
94 impl_typed_slice_conversions!($type, $error, $error, $error, $desc);
95 };
96 ($type:ty, $vec_error:ident, $slice_error:ident, $mut_error:ident, $desc:expr) => {
97 impl TryFrom<&Robj> for Vec<$type> {
98 type Error = Error;
99
100 #[doc = concat!("Convert ", $desc, " into `Vec<", stringify!($type), ">`.")]
101 #[doc = "Note: Unless you plan to store the result, use a slice instead."]
102 fn try_from(robj: &Robj) -> Result<Self> {
103 robj.as_typed_slice()
104 .map(<[_]>::to_vec)
105 .ok_or_else(|| Error::$vec_error(robj.clone()))
106 }
107 }
108
109 impl TryFrom<&Robj> for &[$type] {
110 type Error = Error;
111
112 #[doc = concat!("Convert ", $desc, " into `&[", stringify!($type), "]`.")]
113 fn try_from(robj: &Robj) -> Result<Self> {
114 robj.as_typed_slice()
115 .ok_or_else(|| Error::$slice_error(robj.clone()))
116 }
117 }
118
119 impl TryFrom<&mut Robj> for &mut [$type] {
120 type Error = Error;
121
122 #[doc = concat!("Convert ", $desc, " into `&mut [", stringify!($type), "]`.")]
123 fn try_from(robj: &mut Robj) -> Result<Self> {
124 robj.as_typed_slice_mut()
125 .ok_or_else(|| Error::$mut_error(robj.clone()))
126 }
127 }
128
129 impl TryFrom<&Robj> for Option<&[$type]> {
130 type Error = Error;
131
132 #[doc = concat!("Convert ", $desc, " into `Option<&[", stringify!($type), "]>`.")]
133 fn try_from(robj: &Robj) -> Result<Self> {
134 if robj.is_null() || robj.is_na() {
135 Ok(None)
136 } else {
137 Ok(Some(<&[$type]>::try_from(robj)?))
138 }
139 }
140 }
141
142 impl TryFrom<&mut Robj> for Option<&mut [$type]> {
143 type Error = Error;
144
145 #[doc = concat!("Convert ", $desc, " into `Option<&mut [", stringify!($type), "]>`.")]
146 fn try_from(robj: &mut Robj) -> Result<Self> {
147 if robj.is_null() || robj.is_na() {
148 Ok(None)
149 } else {
150 Ok(Some(<&mut [$type]>::try_from(robj)?))
151 }
152 }
153 }
154
155 impl TryFrom<&Robj> for &$type {
156 type Error = Error;
157
158 #[doc = concat!("Convert ", $desc, " into `&", stringify!($type), "`.")]
159 fn try_from(robj: &Robj) -> Result<Self> {
160 let slice: &[$type] = robj.try_into()?;
161
162 if slice.is_empty() {
163 return Err(Error::ExpectedNonZeroLength(robj.clone()));
164 }
165 if slice.len() != 1 {
166 return Err(Error::ExpectedScalar(robj.clone()));
167 }
168 let Some(value) = slice.get(0) else {
169 unreachable!()
170 };
171 if value.is_na() {
172 return Err(Error::MustNotBeNA(robj.clone()));
173 }
174 Ok(value)
175 }
176 }
177
178 impl TryFrom<&mut Robj> for &mut $type {
179 type Error = Error;
180
181 #[doc = concat!("Convert ", $desc, " into `&mut ", stringify!($type), "`.")]
182 fn try_from(robj: &mut Robj) -> Result<Self> {
183 let slice: &mut [$type] = robj.try_into()?;
184
185 if slice.is_empty() {
186 return Err(Error::ExpectedNonZeroLength(robj.clone()));
187 }
188 if slice.len() != 1 {
189 return Err(Error::ExpectedScalar(robj.clone()));
190 }
191 let Some(value) = slice.get_mut(0) else {
192 unreachable!()
193 };
194 if value.is_na() {
195 return Err(Error::MustNotBeNA(robj.clone()));
196 }
197 Ok(value)
198 }
199 }
200 };
201}
202
203impl_try_from_scalar_integer!(u8);
204impl_try_from_scalar_integer!(u16);
205impl_try_from_scalar_integer!(u32);
206impl_try_from_scalar_integer!(u64);
207impl_try_from_scalar_integer!(usize);
208impl_try_from_scalar_integer!(i8);
209impl_try_from_scalar_integer!(i16);
210impl_try_from_scalar_integer!(i32);
211impl_try_from_scalar_integer!(i64);
212impl_try_from_scalar_integer!(isize);
213impl_try_from_scalar_real!(f32);
214impl_try_from_scalar_real!(f64);
215
216impl TryFrom<&Robj> for bool {
217 type Error = Error;
218
219 fn try_from(robj: &Robj) -> Result<Self> {
222 if robj.is_na() {
223 Err(Error::MustNotBeNA(robj.clone()))
224 } else {
225 Ok(<Rbool>::try_from(robj)?.is_true())
226 }
227 }
228}
229
230impl TryFrom<&Robj> for &str {
231 type Error = Error;
232
233 fn try_from(robj: &Robj) -> Result<Self> {
236 if robj.is_na() {
237 return Err(Error::MustNotBeNA(robj.clone()));
238 }
239 match robj.len() {
240 0 => Err(Error::ExpectedNonZeroLength(robj.clone())),
241 1 => {
242 if let Some(s) = robj.as_str() {
243 Ok(s)
244 } else {
245 Err(Error::ExpectedString(robj.clone()))
246 }
247 }
248 _ => Err(Error::ExpectedScalar(robj.clone())),
249 }
250 }
251}
252
253impl TryFrom<&Robj> for Option<&str> {
254 type Error = Error;
255
256 fn try_from(robj: &Robj) -> Result<Self> {
257 if robj.is_null() || robj.is_na() {
258 Ok(None)
259 } else {
260 Ok(Some(<&str>::try_from(robj)?))
261 }
262 }
263}
264
265impl TryFrom<&Robj> for String {
266 type Error = Error;
267
268 fn try_from(robj: &Robj) -> Result<Self> {
272 <&str>::try_from(robj).map(|s| s.to_string())
273 }
274}
275
276impl_typed_slice_conversions!(i32, ExpectedInteger, "an INTSXP object");
277impl_typed_slice_conversions!(Rint, ExpectedInteger, "an INTSXP object");
278impl_typed_slice_conversions!(Rfloat, ExpectedReal, "a REALSXP object");
279impl_typed_slice_conversions!(
280 Rbool,
281 ExpectedInteger,
282 ExpectedLogical,
283 ExpectedLogical,
284 "a LGLSXP object"
285);
286impl_typed_slice_conversions!(Rcplx, ExpectedComplex, "a complex object");
287impl_typed_slice_conversions!(u8, ExpectedRaw, "a RAWSXP object");
288impl_typed_slice_conversions!(f64, ExpectedReal, "a REALSXP object");
289
290impl TryFrom<&Robj> for Vec<String> {
291 type Error = Error;
292
293 fn try_from(robj: &Robj) -> Result<Self> {
296 if let Some(iter) = robj.as_str_iter() {
297 if iter.clone().any(|s| s.is_na()) {
299 Err(Error::MustNotBeNA(robj.clone()))
300 } else {
301 Ok(iter.map(|s| s.to_string()).collect::<Vec<String>>())
302 }
303 } else {
304 Err(Error::ExpectedString(robj.clone()))
305 }
306 }
307}
308
309impl TryFrom<&Robj> for Rcplx {
310 type Error = Error;
311
312 fn try_from(robj: &Robj) -> Result<Self> {
313 match robj.len() {
315 0 => return Err(Error::ExpectedNonZeroLength(robj.clone())),
316 1 => {}
317 _ => return Err(Error::ExpectedScalar(robj.clone())),
318 };
319
320 if robj.is_na() {
322 return Ok(Rcplx::na());
323 }
324
325 if let Some(v) = robj.as_real() {
327 return Ok(Rcplx::from(v));
328 }
329
330 if let Some(v) = robj.as_integer() {
333 return Ok(Rcplx::from(v as f64));
334 }
335
336 if let Some(s) = robj.as_typed_slice() {
338 return Ok(s[0]);
339 }
340
341 Err(Error::ExpectedComplex(robj.clone()))
342 }
343}
344
345macro_rules! impl_try_from_robj {
348 ($(@generics<$generics:tt>)? $type:ty $(where $($where_clause:tt)*)?) => {
349 impl$(<$generics>)? TryFrom<Robj> for $type $(where $($where_clause)*)? {
350 type Error = Error;
351
352 fn try_from(robj: Robj) -> Result<Self> {
353 Self::try_from(&robj)
354 }
355 }
356
357 impl$(<$generics>)? TryFrom<&Robj> for Option<$type> $(where $($where_clause)*)? {
358 type Error = Error;
359
360 fn try_from(robj: &Robj) -> Result<Self> {
361 if robj.is_null() || robj.is_na() {
362 Ok(None)
363 } else {
364 Ok(Some(<$type>::try_from(robj)?))
365 }
366 }
367 }
368
369 impl$(<$generics>)? TryFrom<Robj> for Option<$type> $(where $($where_clause)*)? {
370 type Error = Error;
371
372 fn try_from(robj: Robj) -> Result<Self> {
373 Self::try_from(&robj)
374 }
375 }
376 };
377}
378#[rustfmt::skip]
379impl_try_from_robj!(u8);
380impl_try_from_robj!(u16);
381impl_try_from_robj!(u32);
382impl_try_from_robj!(u64);
383impl_try_from_robj!(usize);
384
385impl_try_from_robj!(i8);
386impl_try_from_robj!(i16);
387impl_try_from_robj!(i32);
388impl_try_from_robj!(i64);
389impl_try_from_robj!(isize);
390
391impl_try_from_robj!(bool);
392
393impl_try_from_robj!(Rint);
394impl_try_from_robj!(Rfloat);
395impl_try_from_robj!(Rbool);
396impl_try_from_robj!(Rcplx);
397
398impl_try_from_robj!(f32);
399impl_try_from_robj!(f64);
400
401impl_try_from_robj!(Vec::<String>);
402impl_try_from_robj!(Vec::<Rint>);
403impl_try_from_robj!(Vec::<Rfloat>);
404impl_try_from_robj!(Vec::<Rbool>);
405impl_try_from_robj!(Vec::<Rcplx>);
406impl_try_from_robj!(Vec::<u8>);
407impl_try_from_robj!(Vec::<i32>);
408impl_try_from_robj!(Vec::<f64>);
409
410impl_try_from_robj!(String);
411
412impl TryFrom<&Robj> for Option<Environment> {
413 type Error = Error;
414 fn try_from(robj: &Robj) -> Result<Self> {
415 if robj.is_null() || robj.is_na() {
416 Ok(None)
417 } else {
418 Ok(Some(Environment::try_from(robj)?))
419 }
420 }
421}
422
423impl TryFrom<Robj> for Option<Environment> {
424 type Error = Error;
425 fn try_from(robj: Robj) -> Result<Self> {
426 Self::try_from(&robj)
427 }
428}
429
430impl_try_from_robj!(@generics<T> HashMap::<&str, T> where T: TryFrom<Robj, Error = error::Error>);
431impl_try_from_robj!(@generics<T> HashMap::<String,T> where T: TryFrom<Robj, Error = error::Error>);
432
433impl_try_from_robj!(HashMap::<&str, Robj>);
434impl_try_from_robj!(HashMap::<String, Robj>);
435
436impl TryFrom<&Robj> for Option<()> {
437 type Error = Error;
438
439 fn try_from(value: &Robj) -> Result<Self> {
440 if value.is_null() {
441 Ok(Some(()))
442 } else {
443 Err(Error::ExpectedNull(value.clone()))
444 }
445 }
446}
447
448impl TryFrom<Robj> for Option<()> {
449 type Error = Error;
450 fn try_from(robj: Robj) -> Result<Self> {
451 Self::try_from(&robj)
452 }
453}
454
455impl<T> TryFrom<&Robj> for HashMap<&str, T>
456where
457 T: TryFrom<Robj, Error = error::Error>,
458{
459 type Error = Error;
460
461 fn try_from(value: &Robj) -> Result<Self> {
462 let value: List = value.try_into()?;
463
464 let value = value
465 .iter()
466 .map(|(name, value)| -> Result<(&str, T)> { value.try_into().map(|x| (name, x)) })
467 .collect::<Result<HashMap<_, _>>>()?;
468
469 Ok(value)
470 }
471}
472
473impl<T> TryFrom<&Robj> for HashMap<String, T>
474where
475 T: TryFrom<Robj, Error = error::Error>,
476{
477 type Error = Error;
478 fn try_from(value: &Robj) -> Result<Self> {
479 let value: HashMap<&str, _> = value.try_into()?;
480 Ok(value.into_iter().map(|(k, v)| (k.to_string(), v)).collect())
481 }
482}
483
484macro_rules! impl_try_from_robj_for_arrays {
485 ($slice_type:ty) => {
486 impl<const N: usize> TryFrom<&Robj> for [$slice_type; N] {
487 type Error = Error;
488
489 fn try_from(value: &Robj) -> Result<Self> {
490 let value: &[$slice_type] = value.try_into()?;
491 if value.len() != N {
492 return Err(Error::ExpectedLength(N));
493 }
494 let value: Self = value
495 .try_into()
496 .map_err(|error| format!("{}", error).to_string())?;
497 Ok(value)
498 }
499 }
500
501 impl<const N: usize> TryFrom<Robj> for [$slice_type; N] {
504 type Error = Error;
505
506 fn try_from(robj: Robj) -> Result<Self> {
507 Self::try_from(&robj)
508 }
509 }
510
511 impl<const N: usize> TryFrom<&Robj> for Option<[$slice_type; N]> {
512 type Error = Error;
513
514 fn try_from(robj: &Robj) -> Result<Self> {
515 if robj.is_null() || robj.is_na() {
516 Ok(None)
517 } else {
518 Ok(Some(<[$slice_type; N]>::try_from(robj)?))
519 }
520 }
521 }
522
523 impl<const N: usize> TryFrom<Robj> for Option<[$slice_type; N]> {
524 type Error = Error;
525
526 fn try_from(robj: Robj) -> Result<Self> {
527 Self::try_from(&robj)
528 }
529 }
530 };
531}
532
533impl_try_from_robj_for_arrays!(Rint);
534impl_try_from_robj_for_arrays!(Rfloat);
535impl_try_from_robj_for_arrays!(Rbool);
536impl_try_from_robj_for_arrays!(Rcplx);
537impl_try_from_robj_for_arrays!(u8);
538impl_try_from_robj_for_arrays!(i32);
539impl_try_from_robj_for_arrays!(f64);
540
541impl<T0> TryFrom<&Robj> for (T0,)
547where
548 T0: for<'a> TryFrom<&'a Robj, Error = Error>,
549{
550 type Error = Error;
551
552 fn try_from(robj: &Robj) -> Result<Self> {
553 let list: List = robj.try_into()?;
554 if list.len() != 1 {
555 return Err(Error::ExpectedLength(1));
556 }
557 Ok(((&list.elt(0)?).try_into()?,))
558 }
559}
560
561impl<T0> TryFrom<Robj> for (T0,)
562where
563 T0: for<'a> TryFrom<&'a Robj, Error = Error>,
564{
565 type Error = Error;
566
567 fn try_from(robj: Robj) -> Result<Self> {
568 Self::try_from(&robj)
569 }
570}
571
572impl<T0> TryFrom<&Robj> for Option<(T0,)>
573where
574 T0: for<'a> TryFrom<&'a Robj, Error = Error>,
575{
576 type Error = Error;
577
578 fn try_from(robj: &Robj) -> Result<Self> {
579 if robj.is_null() || robj.is_na() {
580 Ok(None)
581 } else {
582 <(T0,)>::try_from(robj).map(Some)
583 }
584 }
585}
586
587impl<T0> TryFrom<Robj> for Option<(T0,)>
588where
589 T0: for<'a> TryFrom<&'a Robj, Error = Error>,
590{
591 type Error = Error;
592
593 fn try_from(robj: Robj) -> Result<Self> {
594 Self::try_from(&robj)
595 }
596}
597
598impl_try_from_robj_tuples!((2, 12));
599
600impl TryFrom<&Robj> for HashMap<&str, Robj> {
603 type Error = Error;
604
605 fn try_from(value: &Robj) -> Result<Self> {
606 let value: List = value.try_into()?;
607 Ok(value.into_iter().collect())
608 }
609}
610
611impl TryFrom<&Robj> for HashMap<String, Robj> {
612 type Error = Error;
613 fn try_from(value: &Robj) -> Result<Self> {
614 let value: HashMap<&str, _> = value.try_into()?;
615 Ok(value.into_iter().map(|(k, v)| (k.to_string(), v)).collect())
616 }
617}