Skip to main content

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}