arc_malachitebft_sync/macros.rs
1/// Process an [`Input`][input] and handle the emitted [`Effects`][effect].
2///
3/// [input]: crate::handle::Input
4/// [effect]: crate::handle::Effect
5///
6/// # Example
7///
8/// ```rust,ignore
9/// malachitebft_core_consensus::process!(
10/// // Input to process
11/// input: input,
12/// // Consensus state
13/// state: &mut state,
14/// // Metrics
15/// metrics: &metrics,
16/// // Effect handler
17/// on: effect => handle_effect(effect).await
18/// )
19/// ```
20#[macro_export]
21macro_rules! process {
22 (input: $input:expr, state: $state:expr, metrics: $metrics:expr, with: $effect:ident => $handle:expr) => {{
23 let mut gen =
24 $crate::co::Gen::new(|co| $crate::handle::handle(co, $state, $metrics, $input));
25
26 let mut co_result = gen.resume_with($crate::Resume::default());
27
28 loop {
29 match co_result {
30 $crate::co::CoState::Yielded($effect) => {
31 let resume = match $handle {
32 Ok(resume) => resume,
33 Err(error) => {
34 $crate::tracing::error!("Error when processing effect: {error:?}");
35 $crate::Resume::default()
36 }
37 };
38 co_result = gen.resume_with(resume)
39 }
40 $crate::co::CoState::Complete(result) => {
41 return result.map_err(Into::into);
42 }
43 }
44 }
45 }};
46}
47
48/// Yield an effect, expecting a specific type of resume value.
49///
50/// Effects yielded by this macro must resume with a value that matches the provided pattern.
51/// If not pattern is give, then the yielded effect must resume with [`Resume::Continue`][continue].
52///
53/// # Errors
54/// This macro will abort the current function with a [`Error::UnexpectedResume`][error] error
55/// if the effect does not resume with a value that matches the provided pattern.
56///
57/// # Example
58/// ```rust,ignore
59/// // If we do not need to extract the resume value
60/// let () = perform!(co, effect, Resume::Continue => ());
61///
62/// // Or just
63/// let () = perform!(co, effect, Resume::Continue);
64///
65/// /// If we need to extract the resume value
66/// let value: Ctx::Value = perform!(co, effect, Resume::SentValueRequest(request_id) => request_id);
67/// ```
68///
69/// [continue]: crate::handle::Resume::Continue
70/// [error]: crate::handle::Error::UnexpectedResume
71#[macro_export]
72macro_rules! perform {
73 ($co:expr, $effect:expr) => {
74 perform!($co, $effect, $crate::Resume::Continue(_))
75 };
76
77 ($co:expr, $effect:expr, $pat:pat) => {
78 perform!($co, $effect, $pat => ())
79 };
80
81 // TODO: Add support for multiple patterns + if guards
82 ($co:expr, $effect:expr, $pat:pat => $expr:expr $(,)?) => {
83 match $co.yield_($effect).await {
84 $pat => $expr,
85 resume => {
86 return ::core::result::Result::Err($crate::Error::UnexpectedResume(
87 resume,
88 stringify!($pat)
89 )
90 .into())
91 }
92 }
93 };
94}