use super::engine::{Engine, EngineConfig};
use crate::base::Issue;
use crate::def::{ParseOptions, Parsed, WorkflowDef, parse, parse_owned};
use crate::function::{CallLayer, Function, Registry};
use crate::program::CompileOptions;
use serde_json::Value;
use std::fmt;
enum Pending {
Parsed(Box<WorkflowDef>, Vec<Issue>),
Refused(Vec<Issue>),
}
pub struct EngineBuilder {
registry: Registry,
options: CompileOptions,
config: EngineConfig,
pending: Vec<Pending>,
}
impl EngineBuilder {
pub(crate) fn new() -> Self {
Self {
registry: Registry::default(),
options: CompileOptions::default(),
config: EngineConfig::default(),
pending: Vec::new(),
}
}
#[must_use]
pub fn registry(mut self, registry: Registry) -> Self {
self.registry = registry;
self
}
#[must_use]
pub fn register<F: Function>(mut self, name: &str, f: F) -> Self {
self.registry.register(name, f);
self
}
#[must_use]
pub fn layer<L: CallLayer>(mut self, l: L) -> Self {
self.registry.layer(l);
self
}
#[must_use]
pub fn options(mut self, options: CompileOptions) -> Self {
self.options = options;
self
}
#[must_use]
pub fn config(mut self, config: EngineConfig) -> Self {
self.config = config;
self
}
#[must_use]
pub fn workflow(mut self, def: WorkflowDef) -> Self {
self.pending
.push(Pending::Parsed(Box::new(def), Vec::new()));
self
}
#[must_use]
pub fn workflow_json(self, raw: &Value) -> Self {
self.parsed(parse(raw, ParseOptions::default()))
}
#[must_use]
pub fn workflow_json_owned(self, raw: Value) -> Self {
self.parsed(parse_owned(raw, ParseOptions::default()))
}
fn parsed(mut self, parsed: Parsed) -> Self {
self.pending.push(match parsed.def {
Some(def) => Pending::Parsed(Box::new(def), parsed.issues),
None => Pending::Refused(parsed.issues),
});
self
}
pub fn build(self) -> std::result::Result<Engine, Vec<Issue>> {
let compiler = self.registry.compiler(self.options);
let mut workflows = Vec::with_capacity(self.pending.len());
let mut rejected = Vec::new();
for pending in self.pending {
match pending {
Pending::Parsed(def, mut parsed) => match compiler.compile_one(&def) {
Ok(compiled) => workflows.push(compiled.workflow),
Err(mut issues) => {
rejected.append(&mut parsed);
rejected.append(&mut issues);
}
},
Pending::Refused(mut issues) => rejected.append(&mut issues),
}
}
if !rejected.is_empty() {
return Err(rejected);
}
Ok(Engine::new(compiler.link(workflows), self.config))
}
}
impl fmt::Debug for EngineBuilder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EngineBuilder")
.field("registry", &self.registry)
.field("options", &self.options)
.field("config", &self.config)
.field("workflows", &self.pending.len())
.finish()
}
}