|
use std::fmt::{self, Display}; |
|
use std::str::FromStr; |
|
|
|
trait HandlerOutput {} |
|
|
|
impl HandlerOutput for () {} |
|
|
|
impl<S, E> HandlerOutput for Result<S, E> {} |
|
|
|
trait Handler<Args, Output: HandlerOutput> { |
|
type Error: Display; |
|
|
|
fn call(self) -> Result<Output, Self::Error>; |
|
} |
|
|
|
#[derive(Debug)] |
|
struct ConvertFailed; |
|
|
|
impl Display for ConvertFailed { |
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { |
|
write!(fmt, "Invalid value") |
|
} |
|
} |
|
|
|
impl std::error::Error for ConvertFailed {} |
|
|
|
macro_rules! impl_for_tuple { |
|
($($tys:ident),*) => { |
|
impl<F, O, $($tys,)*> Handler<($($tys,)*), O> for F |
|
where |
|
O: HandlerOutput, |
|
F: FnMut($($tys),*) -> O, |
|
$($tys: FromStr,)* |
|
$(<$tys as FromStr>::Err: Display,)* |
|
{ |
|
type Error = ConvertFailed; |
|
|
|
fn call(mut self) -> Result<O, Self::Error> { |
|
$( |
|
#[allow(non_snake_case)] |
|
let $tys = match $tys::from_str("0") { |
|
Ok(v) => v, |
|
Err(_) => return Err(ConvertFailed), |
|
}; |
|
)* |
|
Ok((self)($($tys),*)) |
|
} |
|
} |
|
|
|
} |
|
} |
|
|
|
impl_for_tuple!(); |
|
impl_for_tuple!(T0); |
|
impl_for_tuple!(T0, T1); |
|
impl_for_tuple!(T0, T1, T2); |
|
|
|
fn run<H, A, O>(h: H) -> Result<O, H::Error> |
|
where |
|
O: HandlerOutput, |
|
H: Handler<A, O>, |
|
{ |
|
h.call() |
|
} |
|
|
|
fn main() -> Result<(), Box<dyn std::error::Error>> { |
|
let mut x: isize = -1; |
|
let mut y: isize = -1; |
|
let mut xs: (u8, u8) = (0, 0); |
|
|
|
run(|| x = 1)?; |
|
run(|a, b| xs = (a, b))?; |
|
//run(|a| /*-> Result<(), std::num::ParseIntError> */ { y = str::parse(a)?; Ok(()) })?; |
|
//run(|a: usize| Ok::<(), ()>(())?); |
|
|
|
println!("{} {}", x, y); |
|
|
|
Ok(()) |
|
} |