async_flow/model/
system_builder.rs1use super::{
4 BlockDefinition, InputPortId, Inputs, OutputPortId, Outputs, PortId, SystemDefinition,
5};
6use alloc::{collections::BTreeSet, rc::Rc, vec::Vec};
7use core::fmt::Debug;
8use thiserror::Error;
9
10#[derive(Clone, Debug, Error)]
11pub enum SystemBuildError {
12 #[error("unregistered input port ID: {0}")]
13 UnregisteredInput(InputPortId),
14
15 #[error("unregistered output port ID: {0}")]
16 UnregisteredOutput(OutputPortId),
17
18 #[error("already connected output port ID: {0}")]
19 AlreadyConnectedOutput(OutputPortId),
20}
21
22#[derive(Clone, Default)]
34pub struct SystemBuilder {
35 system: SystemDefinition,
36 registered_inputs: BTreeSet<InputPortId>,
37 registered_outputs: BTreeSet<OutputPortId>,
38 connected_outputs: BTreeSet<OutputPortId>,
39}
40
41impl SystemBuilder {
42 pub fn new() -> Self {
44 Self::default()
45 }
46
47 pub fn register<T: BlockDefinition + 'static>(&mut self, block: T) -> Rc<T> {
49 let block: Rc<T> = Rc::new(block);
50 self.system.push_block(&block);
51
52 for input in block.inputs() {
53 self.register_input(input);
54 }
55 for output in block.outputs() {
56 self.register_output(output);
57 }
58
59 block
60 }
61
62 pub fn register_port(&mut self, input: impl Into<PortId>) {
64 match input.into() {
65 PortId::Input(input) => self.register_input(input),
66 PortId::Output(output) => self.register_output(output),
67 }
68 }
69
70 pub fn register_input(&mut self, input: impl Into<InputPortId>) {
72 let input = input.into();
73 self.registered_inputs.insert(input);
74 }
75
76 pub fn register_output(&mut self, output: impl Into<OutputPortId>) {
78 let output = output.into();
79 self.registered_outputs.insert(output);
80 }
81
82 pub fn export(&mut self, input: impl Into<PortId>) -> Result<PortId, SystemBuildError> {
85 self.export_port(input)
86 }
87
88 pub fn export_port(&mut self, input: impl Into<PortId>) -> Result<PortId, SystemBuildError> {
91 let input = input.into();
92 match input.into() {
93 PortId::Input(input) => self.export_input(input).map(|_| ()),
94 PortId::Output(output) => self.export_output(output).map(|_| ()),
95 }?;
96 Ok(input)
97 }
98
99 pub fn export_input(
101 &mut self,
102 input: impl Into<InputPortId>,
103 ) -> Result<InputPortId, SystemBuildError> {
104 let input = input.into();
105 if !self.registered_inputs.contains(&input) {
106 return Err(SystemBuildError::UnregisteredInput(input));
107 }
108 self.system.inputs.insert(input);
109 Ok(input)
110 }
111
112 pub fn export_output(
114 &mut self,
115 output: impl Into<OutputPortId>,
116 ) -> Result<OutputPortId, SystemBuildError> {
117 let output = output.into();
118 if !self.registered_outputs.contains(&output) {
119 return Err(SystemBuildError::UnregisteredOutput(output));
120 }
121 self.system.outputs.insert(output);
122 Ok(output)
123 }
124
125 pub fn connect<T>(
130 &mut self,
131 output: &Outputs<T>,
132 input: &Inputs<T>,
133 ) -> Result<bool, SystemBuildError> {
134 self.connect_ids(output.id(), input.id())
135 }
136
137 pub(crate) fn connect_ids(
143 &mut self,
144 output: impl Into<OutputPortId>,
145 input: impl Into<InputPortId>,
146 ) -> Result<bool, SystemBuildError> {
147 let output = output.into();
148 let input = input.into();
149 if !self.registered_inputs.contains(&input) {
150 return Err(SystemBuildError::UnregisteredInput(input));
151 }
152 if !self.registered_outputs.contains(&output) {
153 return Err(SystemBuildError::UnregisteredOutput(output));
154 }
155 if self.connected_outputs.contains(&output) {
156 return Err(SystemBuildError::AlreadyConnectedOutput(output));
157 }
158 let result = self.system.connections.insert((output, input));
159 if result {
160 self.connected_outputs.insert(output);
162 }
163 Ok(result)
164 }
165
166 pub fn build(self) -> SystemDefinition {
168 self.system
169 }
170}
171
172impl Debug for SystemBuilder {
173 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
174 f.debug_struct("SystemBuilder")
175 .field(
176 "registered_inputs",
177 &self
178 .registered_inputs
179 .iter()
180 .map(|id| id.0)
181 .collect::<Vec<_>>(),
182 )
183 .field(
184 "registered_outputs",
185 &self
186 .registered_outputs
187 .iter()
188 .map(|id| id.0)
189 .collect::<Vec<_>>(),
190 )
191 .field(
192 "connected_outputs",
193 &self
194 .connected_outputs
195 .iter()
196 .map(|id| id.0)
197 .collect::<Vec<_>>(),
198 )
199 .field("system", &self.system)
200 .finish()
201 }
202}