1use std::cell::RefCell;
4use std::collections::HashMap;
5use std::panic::RefUnwindSafe;
6use std::rc::Rc;
7
8use dfir_lang::graph::FlatGraphBuilder;
9use libloading::Library;
10
11use super::builder::SimBuilder;
12use super::compiled::{CompiledSim, CompiledSimInstance};
13use super::graph::{SimDeploy, SimExternal, SimNode, compile_sim, create_sim_graph_trybuild};
14use crate::compile::ir::HydroRoot;
15use crate::staging_util::Invariant;
16
17pub struct SimFlow<'a> {
19 pub(crate) ir: Vec<HydroRoot>,
20
21 pub(crate) external_ports: Rc<RefCell<(Vec<usize>, usize)>>,
22
23 pub(crate) processes: HashMap<usize, SimNode>,
24 pub(crate) clusters: HashMap<usize, SimNode>,
25 pub(crate) externals: HashMap<usize, SimExternal>,
26
27 pub(crate) _process_id_name: Vec<(usize, String)>,
30 pub(crate) _external_id_name: Vec<(usize, String)>,
31 pub(crate) _cluster_id_name: Vec<(usize, String)>,
32
33 pub(crate) _phantom: Invariant<'a>,
34}
35
36impl<'a> SimFlow<'a> {
37 pub fn with_instance<T>(self, thunk: impl FnOnce(CompiledSimInstance) -> T) -> T {
39 self.compiled().with_instance(thunk)
40 }
41
42 pub fn fuzz(self, thunk: impl AsyncFn(CompiledSimInstance) + RefUnwindSafe) {
53 self.compiled().fuzz(thunk)
54 }
55
56 pub fn exhaustive(self, thunk: impl AsyncFn(CompiledSimInstance) + RefUnwindSafe) -> usize {
67 self.compiled().exhaustive(thunk)
68 }
69
70 pub fn compiled(mut self) -> CompiledSim {
72 use std::collections::BTreeMap;
73
74 use dfir_lang::graph::{eliminate_extra_unions_tees, partition_graph};
75
76 let mut sim_emit = SimBuilder {
77 async_level: FlatGraphBuilder::new(),
78 tick_dfirs: BTreeMap::new(),
79 extra_stmts: vec![],
80 next_hoff_id: 0,
81 };
82
83 let mut seen_tees_instantiate: HashMap<_, _> = HashMap::new();
84 self.ir.iter_mut().for_each(|leaf| {
85 leaf.compile_network::<SimDeploy>(
86 &(),
87 &mut BTreeMap::new(),
88 &mut seen_tees_instantiate,
89 &self.processes,
90 &self.clusters,
91 &self.externals,
92 );
93 });
94
95 let mut built_tees = HashMap::new();
96 let mut next_stmt_id = 0;
97 for leaf in &mut self.ir {
98 leaf.emit(&mut sim_emit, &mut built_tees, &mut next_stmt_id);
99 }
100
101 let (mut async_level_flat_graph, _, _) = sim_emit.async_level.build();
102 eliminate_extra_unions_tees(&mut async_level_flat_graph);
103 let async_level_graph =
104 partition_graph(async_level_flat_graph).expect("Failed to partition (cycle detected).");
105
106 let tick_graphs = sim_emit
107 .tick_dfirs
108 .into_iter()
109 .map(|(l, g)| {
110 let (mut flat_graph, _, _) = g.build();
111 eliminate_extra_unions_tees(&mut flat_graph);
112 (
113 l,
114 partition_graph(flat_graph).expect("Failed to partition (cycle detected)."),
115 )
116 })
117 .collect::<BTreeMap<_, _>>();
118
119 let (bin, trybuild) =
120 create_sim_graph_trybuild(async_level_graph, tick_graphs, sim_emit.extra_stmts);
121
122 let out = compile_sim(bin, trybuild).unwrap();
123 let lib = unsafe { Library::new(&out).unwrap() };
124
125 let external_ports = self.external_ports.take().0;
126 CompiledSim {
127 _path: out,
128 lib,
129 external_ports,
130 }
131 }
132}