Skip to main content

async_flow/model/
system_builder.rs

1// This is free and unencumbered software released into the public domain.
2
3use super::{BlockDefinition, InputId, Inputs, OutputId, Outputs, SystemDefinition};
4use thiserror::Error;
5
6#[derive(Debug, Error)]
7pub enum SystemBuildError {
8    #[error("unregistered input port ID: {0}")]
9    UnregisteredInput(InputId),
10    #[error("unregistered output port ID: {0}")]
11    UnregisteredOutput(OutputId),
12}
13
14/// A builder for system definitions.
15///
16/// # Examples
17///
18/// ```
19/// use async_flow::model::SystemBuilder;
20///
21/// let mut builder = SystemBuilder::new();
22/// //let block = builder.register(MyBlock::new());
23/// let system = builder.build();
24/// ```
25#[derive(Clone, Debug, Default)]
26pub struct SystemBuilder {
27    system: SystemDefinition,
28}
29
30impl SystemBuilder {
31    /// Creates a new system builder.
32    pub fn new() -> Self {
33        Self::default()
34    }
35
36    /// Registers a block.
37    pub fn register<T: BlockDefinition>(&mut self, block: T) -> T {
38        for input in block.inputs() {
39            self.register_input(input);
40        }
41        for output in block.outputs() {
42            self.register_output(output);
43        }
44        block
45    }
46
47    /// Registers a block's input port.
48    pub fn register_input(&mut self, input: impl Into<InputId>) {
49        self.system.registered_inputs.insert(input.into());
50    }
51
52    /// Registers a block's output port.
53    pub fn register_output(&mut self, output: impl Into<OutputId>) {
54        self.system.registered_outputs.insert(output.into());
55    }
56
57    /// Connects an output port to an input port of the same type.
58    ///
59    /// Returns a boolean indicating whether the connection was newly
60    /// inserted or already existed.
61    pub fn connect<T>(
62        &mut self,
63        output: &Outputs<T>,
64        input: &Inputs<T>,
65    ) -> Result<bool, SystemBuildError> {
66        if !self.system.registered_inputs.contains(&input.id()) {
67            return Err(SystemBuildError::UnregisteredInput(input.id()));
68        }
69        if !self.system.registered_outputs.contains(&output.id()) {
70            return Err(SystemBuildError::UnregisteredOutput(output.id()));
71        }
72        Ok(self.system.connections.insert((output.id(), input.id())))
73    }
74
75    /// Builds the system.
76    pub fn build(self) -> SystemDefinition {
77        self.system
78    }
79}