use std::sync::Arc;
use crate::adapter::WrappingDispenser;
use crate::adapter::{ExecutionError, OpDispenser, OpResult};
use crate::wrapper_registry::{WrapperName, WrapperRegistration, WrapperSubject};
pub const NAME: WrapperName = WrapperName::new("fields");
fn triggers(s: WrapperSubject) -> bool {
let Some(template) = s.op() else {
return false;
};
template
.params
.get("fields")
.map(|v| {
v.as_bool()
.unwrap_or_else(|| v.as_str().map(|s| s == "true").unwrap_or(false))
})
.unwrap_or(false)
}
fn describe_assignment(_: WrapperSubject) -> Option<String> {
Some("fields: rendered op text to stdout".into())
}
inventory::submit! {
WrapperRegistration {
name: NAME,
owned_fields: &["fields"],
triggers,
requires_inner: &[],
forbids_outer: &[],
mutually_exclusive_with: &[],
describe_assignment,
levels: &[crate::wrapper_registry::WrapperLevel::Op],
}
}
pub struct FieldsDispenser {
inner: Arc<dyn OpDispenser>,
op_name: String,
op_fields: Vec<(String, serde_json::Value)>,
}
impl FieldsDispenser {
pub fn wrap(inner: Arc<dyn OpDispenser>, op_name: &str) -> Arc<dyn OpDispenser> {
Arc::new(Self {
inner,
op_name: op_name.to_string(),
op_fields: Vec::new(),
})
}
pub fn wrap_with_op_fields(
inner: Arc<dyn OpDispenser>,
op_name: &str,
op_fields: Vec<(String, serde_json::Value)>,
) -> Arc<dyn OpDispenser> {
Arc::new(Self {
inner,
op_name: op_name.to_string(),
op_fields,
})
}
}
impl WrappingDispenser for FieldsDispenser {}
impl OpDispenser for FieldsDispenser {
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 {
if !self.op_fields.is_empty() {
match crate::wires::resolve_op_fields_via_wires(&self.op_fields, ctx.wires) {
Ok(resolved) => {
for s in resolved.strings().iter() {
println!("{s}");
}
}
Err(msg) => {
eprintln!("[{}@{}] fields-render failed: {msg}", self.op_name, cycle);
}
}
}
let result = self.inner.execute(cycle, ctx).await?;
if self.op_fields.is_empty() {
if let Some(ref body) = result.body {
let json = body.to_json();
println!(
"[{}@{}] {} rows: {}",
self.op_name,
cycle,
body.element_count(),
serde_json::to_string_pretty(&json).unwrap_or_else(|_| json.to_string())
);
} else {
println!("[{}@{}] (no result body)", self.op_name, cycle);
}
for name in ctx.wires.names() {
if let Some(value) = ctx.wires.get(&name) {
println!(" wire {name} = {}", value.to_display_string());
}
}
}
Ok(result)
})
}
fn inner_dispenser(&self) -> Option<&dyn OpDispenser> {
Some(self.inner.as_ref())
}
}