use std::string::String;
use std::vec::Vec;
use crate::authoring::{BuildError, Weave};
use crate::foundation::{KnotKind, NumericPath, SignalDomain};
use crate::runtime_impl::error::{RecipeError, RecipeResolveError};
use crate::runtime_impl::{BindOpts, PortWriter, Runtime};
#[cfg(feature = "schema")]
use schemars::JsonSchema;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "schema")]
use std::borrow::ToOwned;
pub trait Recipe: Sized {
type Ports;
fn weave() -> Result<Weave, BuildError>;
fn resolve_ports(runtime: &Runtime) -> Result<Self::Ports, RecipeResolveError>;
fn bind() -> Result<RecipeInstance<Self>, RecipeError> {
Self::bind_with(BindOpts::default())
}
fn bind_with(opts: BindOpts) -> Result<RecipeInstance<Self>, RecipeError> {
let runtime = Runtime::bind(Self::weave()?, opts)?;
let ports = Self::resolve_ports(&runtime)?;
Ok(RecipeInstance { runtime, ports })
}
fn manifest() -> Result<RecipeManifest, RecipeError> {
Ok(RecipeManifest::from_weave(&Self::weave()?))
}
}
pub struct RecipeInstance<R: Recipe> {
runtime: Runtime,
ports: R::Ports,
}
impl<R: Recipe> RecipeInstance<R> {
pub fn runtime(&self) -> &Runtime {
&self.runtime
}
pub fn runtime_mut(&mut self) -> &mut Runtime {
&mut self.runtime
}
pub fn ports(&self) -> &R::Ports {
&self.ports
}
pub(crate) fn port_writer_with_ports(&mut self) -> (&R::Ports, PortWriter<'_>) {
let Self { runtime, ports } = self;
(ports, runtime.port_writer())
}
pub fn into_parts(self) -> (Runtime, R::Ports) {
(self.runtime, self.ports)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
pub struct RecipeManifest {
pub weave_id: String,
pub numeric: NumericPath,
pub signal_inputs: Vec<SignalInManifest>,
pub signal_outputs: Vec<SignalOutManifest>,
pub emit_commands: Vec<EmitCommandManifest>,
}
impl RecipeManifest {
pub fn from_weave(weave: &Weave) -> Self {
let mut signal_inputs = Vec::new();
let mut signal_outputs = Vec::new();
let mut emit_commands = Vec::new();
for knot in weave.knots() {
match &knot.kind {
KnotKind::SignalIn { domain } => signal_inputs.push(SignalInManifest {
knot: knot.id.clone(),
domain: *domain,
}),
KnotKind::SignalOut { path, domain } => signal_outputs.push(SignalOutManifest {
knot: knot.id.clone(),
path: path.clone(),
domain: *domain,
}),
KnotKind::EmitCommand { name } => emit_commands.push(EmitCommandManifest {
knot: knot.id.clone(),
name: name.clone(),
}),
_ => {}
}
}
signal_inputs.sort_by(|left, right| left.knot.cmp(&right.knot));
signal_outputs.sort_by(|left, right| {
left.path
.cmp(&right.path)
.then_with(|| left.knot.cmp(&right.knot))
});
emit_commands.sort_by(|left, right| {
left.name
.cmp(&right.name)
.then_with(|| left.knot.cmp(&right.knot))
});
Self {
weave_id: String::from(weave.id()),
numeric: weave.numeric(),
signal_inputs,
signal_outputs,
emit_commands,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
pub struct SignalInManifest {
pub knot: String,
pub domain: SignalDomain,
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
pub struct SignalOutManifest {
pub knot: String,
pub path: String,
pub domain: SignalDomain,
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
pub struct EmitCommandManifest {
pub knot: String,
pub name: String,
}