1use std::cell::RefCell;
4use std::collections::HashMap;
5use std::panic::RefUnwindSafe;
6use std::rc::Rc;
7
8use libloading::Library;
9
10use super::builder::SimBuilder;
11use super::compiled::{CompiledSim, CompiledSimInstance};
12use super::graph::{SimDeploy, SimExternal, SimNode, compile_sim, create_sim_graph_trybuild};
13use crate::compile::ir::HydroRoot;
14use crate::location::Location;
15use crate::location::dynamic::LocationId;
16use crate::prelude::Cluster;
17use crate::staging_util::Invariant;
18
19pub struct SimFlow<'a> {
21 pub(crate) ir: Vec<HydroRoot>,
22
23 pub(crate) external_ports: Rc<RefCell<(Vec<usize>, usize)>>,
24
25 pub(crate) processes: HashMap<usize, SimNode>,
26 pub(crate) clusters: HashMap<usize, SimNode>,
27 pub(crate) externals: HashMap<usize, SimExternal>,
28
29 pub(crate) external_registered: Rc<RefCell<HashMap<usize, usize>>>,
32
33 pub(crate) cluster_max_sizes: HashMap<LocationId, usize>,
34
35 pub(crate) _process_id_name: Vec<(usize, String)>,
38 pub(crate) _external_id_name: Vec<(usize, String)>,
39 pub(crate) _cluster_id_name: Vec<(usize, String)>,
40
41 pub(crate) _phantom: Invariant<'a>,
42}
43
44impl<'a> SimFlow<'a> {
45 pub fn with_cluster_size<C>(mut self, cluster: &Cluster<'a, C>, max_size: usize) -> Self {
47 self.cluster_max_sizes.insert(cluster.id(), max_size);
48 self
49 }
50
51 pub fn with_instance<T>(self, thunk: impl FnOnce(CompiledSimInstance) -> T) -> T {
53 self.compiled().with_instance(thunk)
54 }
55
56 pub fn fuzz(self, thunk: impl AsyncFn() + RefUnwindSafe) {
67 self.compiled().fuzz(thunk)
68 }
69
70 pub fn exhaustive(self, thunk: impl AsyncFnMut() + RefUnwindSafe) -> usize {
81 self.compiled().exhaustive(thunk)
82 }
83
84 pub fn compiled(mut self) -> CompiledSim {
86 use std::collections::BTreeMap;
87
88 use dfir_lang::graph::{eliminate_extra_unions_tees, partition_graph};
89
90 let mut sim_emit = SimBuilder {
91 process_graphs: BTreeMap::new(),
92 cluster_graphs: BTreeMap::new(),
93 process_tick_dfirs: BTreeMap::new(),
94 cluster_tick_dfirs: BTreeMap::new(),
95 extra_stmts_global: vec![],
96 extra_stmts_cluster: BTreeMap::new(),
97 next_hoff_id: 0,
98 };
99
100 self.externals.insert(
101 0,
102 SimExternal {
103 external_ports: self.external_ports.clone(),
104 registered: self.external_registered.clone(),
105 },
106 );
107
108 let mut seen_tees_instantiate: HashMap<_, _> = HashMap::new();
109 self.ir.iter_mut().for_each(|leaf| {
110 leaf.compile_network::<SimDeploy>(
111 &mut BTreeMap::new(),
112 &mut seen_tees_instantiate,
113 &self.processes,
114 &self.clusters,
115 &self.externals,
116 );
117 });
118
119 let mut built_tees = HashMap::new();
120 let mut next_stmt_id = 0;
121 for leaf in &mut self.ir {
122 leaf.emit::<SimDeploy>(&mut sim_emit, &mut built_tees, &mut next_stmt_id);
123 }
124
125 let process_graphs = sim_emit
126 .process_graphs
127 .into_iter()
128 .map(|(l, g)| {
129 let (mut flat_graph, _, _) = g.build();
130 eliminate_extra_unions_tees(&mut flat_graph);
131 (
132 l,
133 partition_graph(flat_graph).expect("Failed to partition (cycle detected)."),
134 )
135 })
136 .collect::<BTreeMap<_, _>>();
137
138 let cluster_graphs = sim_emit
139 .cluster_graphs
140 .into_iter()
141 .map(|(l, g)| {
142 let (mut flat_graph, _, _) = g.build();
143 eliminate_extra_unions_tees(&mut flat_graph);
144 (
145 l,
146 partition_graph(flat_graph).expect("Failed to partition (cycle detected)."),
147 )
148 })
149 .collect::<BTreeMap<_, _>>();
150
151 let process_tick_graphs = sim_emit
152 .process_tick_dfirs
153 .into_iter()
154 .map(|(l, g)| {
155 let (mut flat_graph, _, _) = g.build();
156 eliminate_extra_unions_tees(&mut flat_graph);
157 (
158 l,
159 partition_graph(flat_graph).expect("Failed to partition (cycle detected)."),
160 )
161 })
162 .collect::<BTreeMap<_, _>>();
163
164 let cluster_tick_graphs = sim_emit
165 .cluster_tick_dfirs
166 .into_iter()
167 .map(|(l, g)| {
168 let (mut flat_graph, _, _) = g.build();
169 eliminate_extra_unions_tees(&mut flat_graph);
170 (
171 l,
172 partition_graph(flat_graph).expect("Failed to partition (cycle detected)."),
173 )
174 })
175 .collect::<BTreeMap<_, _>>();
176
177 for c in self.clusters.keys() {
178 assert!(
179 self.cluster_max_sizes
180 .contains_key(&LocationId::Cluster(*c)),
181 "Cluster {:?} missing max size; call with_cluster_size() before compiled()",
182 c
183 );
184 }
185
186 let (bin, trybuild) = create_sim_graph_trybuild(
187 process_graphs,
188 cluster_graphs,
189 self.cluster_max_sizes,
190 process_tick_graphs,
191 cluster_tick_graphs,
192 sim_emit.extra_stmts_global,
193 sim_emit.extra_stmts_cluster,
194 );
195
196 let out = compile_sim(bin, trybuild).unwrap();
197 let lib = unsafe { Library::new(&out).unwrap() };
198
199 let external_ports = self.external_ports.take().0;
200 CompiledSim {
201 _path: out,
202 lib,
203 external_ports,
204 external_registered: self.external_registered.take(),
205 }
206 }
207}