extendr_api/optional/
either.rs

1/*!
2Enables support for the [`either`](https://docs.rs/either/latest/either/) crate,
3to allow accepting and returning `Either<L, R>` values if both `L` and `R` are convertible to/from `Robj`.
4
5`either` crate support is currently available in the dev version of `extendr-api`
6and requires enabling `either` feature:
7
8```toml
9[dependencies]
10extendr-api = { git = "https://github.com/extendr/extendr" , features = ["either"] }
11```
12
13```rust
14use extendr_api::prelude::*;
15
16#[extendr]
17fn accept_numeric(input : Either<Integers, Doubles>) {}
18```
19
20Here is an example of `either` usage -- a type-aware sum:
21```rust
22use extendr_api::prelude::*;
23
24#[extendr]
25fn type_aware_sum(input : Either<Integers, Doubles>) -> Either<Rint, Rfloat> {
26    match input {
27        Left(ints) => Left(ints.iter().sum::<Rint>()),
28        Right(dbls) => Right(dbls.iter().sum::<Rfloat>()),
29    }
30}
31```
32*/
33use crate::prelude::*;
34use crate::{Error, Robj};
35
36impl<'a, L, R> TryFrom<&'a Robj> for Either<L, R>
37where
38    L: TryFrom<&'a Robj, Error = Error>,
39    R: TryFrom<&'a Robj, Error = Error>,
40{
41    type Error = Error;
42
43    /// Returns the first type that matches the provided `Robj`, starting from
44    /// `L`-type, and if that fails, then the `R`-type is converted.
45    fn try_from(value: &'a Robj) -> Result<Self> {
46        match L::try_from(value) {
47            Ok(left) => Ok(Left(left)),
48            Err(left_err) => match R::try_from(value) {
49                Ok(right) => Ok(Right(right)),
50                Err(right_err) => Err(Error::EitherError(Box::new(left_err), Box::new(right_err))),
51            },
52        }
53    }
54}
55
56impl<L, R> TryFrom<Robj> for Either<L, R>
57where
58    for<'a> Either<L, R>: TryFrom<&'a Robj, Error = Error>,
59{
60    type Error = Error;
61
62    /// Returns the first type that matches the provided `Robj`, starting from
63    /// `L`-type, and if that fails, then the `R`-type is converted.
64    fn try_from(value: Robj) -> Result<Self> {
65        (&value).try_into()
66    }
67}
68
69impl<L, R> From<Either<L, R>> for Robj
70where
71    Robj: From<L> + From<R>,
72{
73    fn from(value: Either<L, R>) -> Self {
74        match value {
75            Left(left) => Robj::from(left),
76            Right(right) => Robj::from(right),
77        }
78    }
79}