#[macro_export]
macro_rules! block {
(
$name:ident <$ctx:ty, $err:ty> {
$(
$step_name:ident : $step_type:ty
),*
$(,)?
}
) => {
$crate::paste::paste! {
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct [<$name Inputs>] {
$(
pub $step_name: <$step_type as $crate::Step<$ctx, $err>>::Input,
)*
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct $name {
inputs: [<$name Inputs>],
}
impl $name {
pub fn new(inputs: [<$name Inputs>]) -> Self {
Self { inputs }
}
}
#[async_trait::async_trait]
impl $crate::Step<$ctx, $err> for $name {
type Input = [<$name Inputs>];
async fn execute(
ctx: &mut $ctx,
input: &Self::Input,
) -> $crate::StepResult<$err> {
$(
match <$step_type as $crate::Step<$ctx, $err>>::execute(ctx, &input.$step_name).await {
$crate::StepResult::Continue => {},
$crate::StepResult::Pause => return $crate::StepResult::Pause,
$crate::StepResult::Fail(e) => return $crate::StepResult::Fail(e),
}
)*
$crate::StepResult::Continue
}
async fn compensate(
ctx: &mut $ctx,
input: &Self::Input,
) -> $crate::CompensationResult<$err> {
$crate::block!(@compensate_reverse ctx, input, $ctx, $err, [$($step_name: $step_type),*])
}
}
}
};
(@compensate_reverse $ctx:ident, $input:ident, $ctx_ty:ty, $err_ty:ty, [$first_name:ident: $first_type:ty $(, $rest_name:ident: $rest_type:ty)*]) => {{
$crate::block!(@compensate_reverse $ctx, $input, $ctx_ty, $err_ty, [$($rest_name: $rest_type),*]);
match <$first_type as $crate::Step<$ctx_ty, $err_ty>>::compensate($ctx, &$input.$first_name).await {
$crate::CompensationResult::Completed => {},
$crate::CompensationResult::Pause => return $crate::CompensationResult::Pause,
$crate::CompensationResult::Critical(e) => return $crate::CompensationResult::Critical(e),
}
$crate::CompensationResult::Completed
}};
(@compensate_reverse $ctx:ident, $input:ident, $ctx_ty:ty, $err_ty:ty, []) => {
};
}
#[macro_export]
macro_rules! legend {
(
$name:ident <$ctx:ty, $err:ty> {
$(
$step_name:ident : $step_type:ty
),*
$(,)?
}
) => {
$crate::paste::paste! {
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct [<$name Inputs>] {
$(
pub $step_name: <$step_type as $crate::Step<$ctx, $err>>::Input,
)*
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct $name {
inputs: [<$name Inputs>],
}
impl $name {
pub fn new(inputs: [<$name Inputs>]) -> Self {
Self { inputs }
}
pub fn build(self, ctx: $ctx) -> $crate::Execution<
$ctx,
$err,
$crate::legend!(@steps_type $ctx, $err, [$($step_name: $step_type),*]),
$crate::New
>
where
$ctx: Send + Sync + 'static,
$err: Send + Sync + Clone + 'static,
{
let steps = $crate::legend!(@build_steps self.inputs, $ctx, $err, [$($step_name: $step_type),*]);
$crate::Execution::new(steps, ctx)
}
}
#[allow(dead_code)]
pub type [<$name Steps>] = $crate::legend!(@steps_type $ctx, $err, [$($step_name: $step_type),*]);
}
};
(@steps_type $ctx:ty, $err:ty, [$only_name:ident: $only_type:ty]) => {
$crate::HSingle<$crate::StepWrapper<$only_type, $ctx, $err>>
};
(@steps_type $ctx:ty, $err:ty, [$first_name:ident: $first_type:ty, $($rest_name:ident: $rest_type:ty),+]) => {
$crate::HCons<
$crate::StepWrapper<$first_type, $ctx, $err>,
$crate::legend!(@steps_type $ctx, $err, [$($rest_name: $rest_type),+])
>
};
(@build_steps $inputs:expr, $ctx:ty, $err:ty, [$only_name:ident: $only_type:ty]) => {
$crate::HSingle::new($crate::StepWrapper::<$only_type, $ctx, $err>::new($inputs.$only_name.clone()))
};
(@build_steps $inputs:expr, $ctx:ty, $err:ty, [$first_name:ident: $first_type:ty, $($rest_name:ident: $rest_type:ty),+]) => {
$crate::HCons::new(
$crate::StepWrapper::<$first_type, $ctx, $err>::new($inputs.$first_name.clone()),
$crate::legend!(@build_steps $inputs, $ctx, $err, [$($rest_name: $rest_type),+])
)
};
}