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