#![feature(never_type)]
#![feature(try_trait_v2)]
#![feature(try_trait_v2_residual)]
#![feature(associated_type_defaults)]
use try_v2_derive::Try;
trait TryFrom<T>: Sized {
type Error = !;
type Return: std::ops::Try = Result<Self, Self::Error>;
fn try_from(value: T) -> Self::Return;
}
#[derive(Try)]
#[FromResidual(Result<_, Self::Residual>)]
#[must_use]
enum Eightball<Y, N> {
Yes(Y),
TryAgain,
No(N),
}
struct Even(i32);
struct Odd(i32);
impl TryFrom<i32> for Even {
type Return = Eightball<Self, Odd>;
fn try_from(num: i32) -> Self::Return {
if num % 2 == 0 {
Eightball::Yes(Even(num))
} else {
Eightball::No(Odd(num))
}
}
}
struct Even2(i32);
impl TryFrom<i32> for Even2 {
type Error = Eightball<!, Odd>;
fn try_from(num: i32) -> Result<Even2, Eightball<!, Odd>> {
if num % 2 == 0 {
Result::Ok(Even2(num))
} else {
Result::Err(Eightball::No(Odd(num)))
}
}
}
struct TryFromIntError;
impl TryFrom<i8> for u8 {
type Error = TryFromIntError;
fn try_from(u: i8) -> Result<Self, Self::Error> {
if u >= 0 {
Ok(u as Self)
} else {
Err(TryFromIntError)
}
}
}
fn even_string_own_try_type(num: i32) -> Eightball<String, Odd> {
let n = <Even as TryFrom<i32>>::try_from(num)?;
let s = format!("{}", n.0);
Eightball::Yes(s)
}
fn even_string_via_result(num: i32) -> Eightball<String, Odd> {
let n = <Even2 as TryFrom<i32>>::try_from(num)?;
let s = format!("{}", n.0);
Eightball::Yes(s)
}
fn unsigned(num: i8) -> Result<String, TryFromIntError> {
let n = <u8 as TryFrom<i8>>::try_from(num)?;
let s = format!("{}", n);
Ok(s)
}
struct ThirdWord(String);
impl TryFrom<&str> for ThirdWord {
type Return = Option<Self>;
fn try_from(input: &str) -> Self::Return {
input
.split_whitespace()
.nth(2)
.map(|s| ThirdWord(s.to_string()))
}
}
fn main() {
assert!(matches!(even_string_own_try_type(2), Eightball::Yes(s) if s == "2"));
assert!(matches!(even_string_own_try_type(1), Eightball::No(Odd(1))));
assert!(matches!(even_string_via_result(2), Eightball::Yes(s) if s == "2"));
assert!(matches!(even_string_via_result(1), Eightball::No(Odd(1))));
assert!(matches!(unsigned(5), Ok(s) if s == "5"));
assert!(matches!(unsigned(-1), Err(TryFromIntError)));
assert!(
matches!(<ThirdWord as TryFrom<&str>>::try_from("a lot of words"), Some(s) if s.0 == "of")
);
assert!(<ThirdWord as TryFrom<&str>>::try_from("two words").is_none());
}