use std::marker::PhantomData;
pub trait ResultFlow<InputOk, InputErr> {
type OutputOk;
type OutputErr;
fn apply_result(
&self,
input: Result<InputOk, InputErr>,
) -> Result<Self::OutputOk, Self::OutputErr>;
fn then_result<Next>(self, next: Next) -> ResultFlowChain<InputOk, InputErr, Self, Next>
where
Self: Sized,
Next: ResultFlow<Self::OutputOk, Self::OutputErr>,
{
ResultFlowChain {
head: self,
next,
_phantom: PhantomData,
}
}
}
#[derive(Debug, Copy, Clone)]
pub struct ResultFlowChain<InputOk, InputErr, Head, Next>
where
Head: ResultFlow<InputOk, InputErr>,
Next: ResultFlow<Head::OutputOk, Head::OutputErr>,
{
head: Head,
next: Next,
_phantom: PhantomData<(InputOk, InputErr)>,
}
impl<InputOk, InputErr, Head, Next> ResultFlowChain<InputOk, InputErr, Head, Next>
where
Head: ResultFlow<InputOk, InputErr>,
Next: ResultFlow<Head::OutputOk, Head::OutputErr>,
{
pub fn new(head: Head, next: Next) -> Self {
Self {
head,
next,
_phantom: PhantomData,
}
}
pub const fn new_const(head: Head, next: Next) -> Self {
Self {
head,
next,
_phantom: PhantomData,
}
}
}
impl<InputOk, InputErr, Head, Next> ResultFlow<InputOk, InputErr>
for ResultFlowChain<InputOk, InputErr, Head, Next>
where
Head: ResultFlow<InputOk, InputErr>,
Next: ResultFlow<Head::OutputOk, Head::OutputErr>,
{
type OutputOk = Next::OutputOk;
type OutputErr = Next::OutputErr;
fn apply_result(
&self,
input_result: Result<InputOk, InputErr>,
) -> Result<Self::OutputOk, Self::OutputErr> {
let intermediate = self.head.apply_result(input_result);
self.next.apply_result(intermediate)
}
}