a3s_code_core/capability/
flow_binding.rs1use std::fmt;
2
3use a3s_flow::{FlowEngine, FlowError, WorkflowSpec};
4
5#[derive(Clone)]
12pub struct FlowBinding {
13 spec: WorkflowSpec,
14 engine: FlowEngine,
15}
16
17impl FlowBinding {
18 pub fn new(spec: WorkflowSpec, engine: FlowEngine) -> a3s_flow::Result<Self> {
20 spec.validate()?;
21 if !engine.supports_runtime_build(spec.runtime_build_id.as_ref()) {
22 let required = spec
23 .runtime_build_id
24 .as_ref()
25 .map(ToString::to_string)
26 .unwrap_or_else(|| "<unpinned>".to_owned());
27 let current = engine
28 .runtime_build_compatibility()
29 .map(|compatibility| compatibility.current_build_id().to_string())
30 .unwrap_or_else(|| "<unfenced>".to_owned());
31 return Err(FlowError::InvalidWorkflow(format!(
32 "workflow '{}' requires runtime build {required}, but its engine exposes {current}",
33 spec.name
34 )));
35 }
36 Ok(Self { spec, engine })
37 }
38
39 pub fn public_name(&self) -> &str {
41 &self.spec.name
42 }
43
44 pub fn spec(&self) -> &WorkflowSpec {
46 &self.spec
47 }
48
49 pub(crate) fn engine(&self) -> &FlowEngine {
50 &self.engine
51 }
52}
53
54impl fmt::Debug for FlowBinding {
55 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
56 formatter
57 .debug_struct("FlowBinding")
58 .field("public_name", &self.public_name())
59 .field("version", &self.spec.version)
60 .field("runtime", &self.spec.runtime)
61 .field("runtime_build_id", &self.spec.runtime_build_id)
62 .finish_non_exhaustive()
63 }
64}