nmbrs_runtime/wrappers/
if.rs1use std::sync::Arc;
10
11use crate::adapter::WrappingDispenser;
12use crate::adapter::{ExecutionError, OpDispenser, OpResult};
13use crate::wrapper_registry::{WrapperName, WrapperRegistration, WrapperSubject};
14
15pub const NAME: WrapperName = WrapperName::new("if");
17
18fn triggers(s: WrapperSubject) -> bool {
20 let Some(template) = s.op() else {
21 return false;
22 };
23 template.condition.is_some()
24}
25
26fn describe_assignment(s: WrapperSubject) -> Option<String> {
27 let template = s.op()?;
28 template.condition.as_ref().map(|cond| {
29 let trimmed = crate::wrapper_registrations::trim_braces(cond);
30 format!("if: {trimmed}")
31 })
32}
33
34inventory::submit! {
35 WrapperRegistration {
36 name: NAME,
37 owned_fields: &["if"],
38 triggers,
39 requires_inner: &[],
40 forbids_outer: &[],
41 mutually_exclusive_with: &[],
42 describe_assignment,
43 levels: &[crate::wrapper_registry::WrapperLevel::Op],
44 }
45}
46
47pub struct ConditionalDispenser {
58 inner: Arc<dyn OpDispenser>,
59 condition_handle: crate::fixture::PullHandle,
62 metrics: Arc<crate::activity::ActivityMetrics>,
64}
65
66impl ConditionalDispenser {
67 pub fn wrap(
74 inner: Arc<dyn OpDispenser>,
75 condition_field: &str,
76 metrics: Arc<crate::activity::ActivityMetrics>,
77 fx: &mut crate::fixture::ScopeFixture,
78 ) -> Result<Arc<dyn OpDispenser>, String> {
79 let condition_handle = fx
80 .register_pull(condition_field)
81 .map_err(|e| format!("conditional `if`: {e}"))?;
82 Ok(Arc::new(Self {
83 inner,
84 condition_handle,
85 metrics,
86 }))
87 }
88}
89
90impl WrappingDispenser for ConditionalDispenser {}
93
94impl OpDispenser for ConditionalDispenser {
95 fn execute<'a>(
96 &'a self,
97 cycle: u64,
98 ctx: &'a crate::fixture::ExecCtx<'a>,
99 ) -> std::pin::Pin<
100 Box<dyn std::future::Future<Output = Result<OpResult, ExecutionError>> + Send + 'a>,
101 > {
102 Box::pin(async move {
103 let value = ctx.pulls.get(self.condition_handle);
107 if !crate::wrappers::condition::is_truthy(value) {
108 self.metrics.skips_total.inc();
109 return Ok(OpResult::skipped());
110 }
111 self.inner.execute(cycle, ctx).await
112 })
113 }
114 fn inner_dispenser(&self) -> Option<&dyn OpDispenser> {
115 Some(self.inner.as_ref())
116 }
117}