use std::sync::Arc;
use crate::adapter::{ExecutionError, OpDispenser, OpResult, WrappingDispenser};
use crate::wrapper_registry::{WrapperName, WrapperRegistration, WrapperSubject};
pub const NAME: WrapperName = WrapperName::new("readout");
fn triggers(s: WrapperSubject) -> bool {
let Some(template) = s.op() else {
return false;
};
template
.params
.get("readout")
.and_then(|v| v.as_str())
.map(|v| v.eq_ignore_ascii_case("visible"))
.unwrap_or(false)
}
fn describe_assignment(s: WrapperSubject) -> Option<String> {
let template = s.op()?;
let v = template.params.get("readout")?.as_str()?;
Some(format!("readout: {v} (op-level status line)"))
}
inventory::submit! {
WrapperRegistration {
name: NAME,
owned_fields: &["readout"],
triggers,
requires_inner: &[super::traverse::NAME],
forbids_outer: &[],
mutually_exclusive_with: &[],
describe_assignment,
levels: &[crate::wrapper_registry::WrapperLevel::Op],
}
}
pub struct ReadoutDispenser {
inner: Arc<dyn OpDispenser>,
op_name: String,
measure: Option<String>,
}
impl ReadoutDispenser {
pub fn wrap(inner: Arc<dyn OpDispenser>, op_name: String) -> Arc<dyn OpDispenser> {
Self::wrap_with_measure(inner, op_name, None)
}
pub fn wrap_with_measure(
inner: Arc<dyn OpDispenser>,
op_name: String,
measure: Option<String>,
) -> Arc<dyn OpDispenser> {
Arc::new(Self {
inner,
op_name,
measure,
})
}
}
impl WrappingDispenser for ReadoutDispenser {}
impl OpDispenser for ReadoutDispenser {
fn execute<'a>(
&'a self,
cycle: u64,
ctx: &'a crate::fixture::ExecCtx<'a>,
) -> std::pin::Pin<
Box<dyn std::future::Future<Output = Result<OpResult, ExecutionError>> + Send + 'a>,
> {
Box::pin(async move {
let parent = crate::execution_context::current_phase_node();
let obs = crate::observer::global_observer();
if let (Some(p), Some(o)) = (parent, obs.as_ref()) {
o.op_starting(p, &self.op_name);
}
let start = std::time::Instant::now();
let result = self.inner.execute(cycle, ctx).await;
let dur = start.elapsed().as_secs_f64();
if let (Some(p), Some(o)) = (parent, obs.as_ref()) {
if let Some(t) = self.measure.as_deref() {
match crate::wires::substitute_via_wires(t, ctx.wires) {
Ok(text) => o.op_measure(p, &self.op_name, &text),
Err(e) => crate::diag!(
crate::observer::LogLevel::Debug,
"measure: substitution failed for '{t}': {e}"
),
}
}
match &result {
Ok(_) => o.op_completed(p, &self.op_name, dur),
Err(e) => o.op_failed(p, &self.op_name, &format!("{e}")),
}
}
result
})
}
fn inner_dispenser(&self) -> Option<&dyn OpDispenser> {
Some(self.inner.as_ref())
}
}