1#![forbid(unused_must_use)]
5#![warn(
6 missing_docs,
7 missing_debug_implementations,
8 missing_copy_implementations,
9 trivial_casts,
10 trivial_numeric_casts,
11 unsafe_code,
12 unstable_features,
13 unused_import_braces,
14 unused_qualifications
15)]
16
17mod api;
18mod constructs;
19mod error;
20mod expressions;
21mod guards;
22mod io;
23mod main_function;
24mod memory;
25mod names;
26mod schedule;
27mod statements;
28mod types;
29mod windows;
30
31use std::{collections::HashMap, path::PathBuf, sync::Mutex, time::Duration};
32
33use api::{AcceptEventFunction, MonitorConstructor};
34use constructs::{
35 EnumDefinition, FunctionDefinition, FunctionVisibility, RequirementKey, RustType,
36 StructDefinition,
37};
38use include_dir::{include_dir, Dir, DirEntry};
39use itertools::Itertools;
40pub use main_function::MainFunction;
41use memory::StreamMemoryStruct;
42use rtlola_streamir::{
43 formatter::{
44 files::{ConstructStore, ConstructWriteError, FilesFormatter},
45 StreamIrFormatter,
46 },
47 ir::{
48 expressions::Expr,
49 memory::{Memory, Parameter, StreamMemory},
50 windows::Window,
51 LocalFreq, LocalFreqRef, OutputReference, StreamIr, StreamReference, Type, WindowReference,
52 },
53};
54use schedule::{DeadlineEnum, QueueStruct, StreamReferenceEnum};
55use statements::CycleFunction;
56use tera::Tera;
57use windows::WindowMemory;
58
59#[derive(Debug, Clone)]
60pub struct NoStdInfo {
62 pub max_instances: HashMap<OutputReference, usize>,
64 pub max_spawned: usize,
67 pub max_closed: usize,
69 pub max_verdict_periodic: usize,
71 pub max_dynamic_deadlines: usize,
73 pub max_dynamic_instances: usize,
75 pub max_queue_size: usize,
77}
78
79#[derive(Debug)]
80pub struct RustFormatter {
82 sr2name: HashMap<StreamReference, String>,
83 sr2ty: HashMap<StreamReference, Type>,
84 sr2parameters: HashMap<StreamReference, Vec<Parameter>>,
85 sr2memory: HashMap<StreamReference, StreamMemory>,
86 lfreq2lfreq: HashMap<LocalFreqRef, LocalFreq>,
87 wref2window: HashMap<WindowReference, Window>,
88 static_deadlines: Vec<Duration>,
89 dynamic_deadlines: Vec<Duration>,
90 construct_store: ConstructStore<Self>,
91 output_folder: PathBuf,
92 overwrite: bool,
94 expr_counter: Mutex<HashMap<(Expr, Option<StreamReference>), usize>>,
97 num_exprs: Mutex<usize>,
98 tera: Tera,
99 main: MainFunction,
100 verdict_streams: Vec<StreamReference>,
101 no_std_info: Option<NoStdInfo>,
102}
103
104impl StreamIrFormatter for RustFormatter {
105 type Return = Result<(), ConstructWriteError>;
106
107 fn id(&self) -> String {
108 "rust-formatter".into()
109 }
110
111 fn format(self, ir: StreamIr) -> Self::Return {
112 let StreamIr { stmt, .. } = ir;
113 let _ = self.call_self_function::<_, String>(CycleFunction(stmt), &[]);
114 let _ = self.call_self_function::<_, String>(AcceptEventFunction, &[]);
115 self.require_struct(MonitorStruct);
116 self.main.insert_requirement(&self);
117 if self.no_std_info.is_some() {
118 self.add_requirement_string_all(RequirementKey::NoStd, "#![no_std]".into());
119 }
120 self.generate_files()
121 }
122}
123
124impl RustFormatter {
125 pub fn new(
130 ir: &StreamIr,
131 output_folder: PathBuf,
132 overwrite: bool,
133 main: MainFunction,
134 verdict_streams: Vec<StreamReference>,
135 no_std_info: Option<NoStdInfo>,
136 ) -> Self {
137 let (sr2name, sr2ty, sr2parameters, sr2memory) = ir
138 .sr2memory
139 .iter()
140 .map(|(sr, m)| {
141 let Memory { buffer, ty, name } = m;
142 (
143 (*sr, name.clone()),
144 (*sr, ty.clone()),
145 (*sr, m.parameters().unwrap_or(&[]).to_owned()),
146 (*sr, buffer.clone()),
147 )
148 })
149 .multiunzip();
150 let mut tera = Tera::default();
151 static TEMPLATE_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/templates");
152
153 for entry in TEMPLATE_DIR.find("**/*").unwrap() {
154 if let DirEntry::File(template) = entry {
155 tera.add_raw_template(
156 template.path().to_str().unwrap(),
157 template.contents_utf8().unwrap(),
158 )
159 .unwrap();
160 }
161 }
162
163 let (static_deadlines, dynamic_deadlines) = ir.all_periodic_pacings();
164 let dynamic_deadlines = dynamic_deadlines
165 .into_iter()
166 .map(|d| d.dur)
167 .unique()
168 .collect();
169
170 let lfreq2lfreq = ir.lref2lfreq.clone();
171 let wref2window = ir.wref2window.clone();
172
173 Self {
174 sr2name,
175 sr2ty,
176 sr2parameters,
177 sr2memory,
178 static_deadlines,
179 dynamic_deadlines,
180 lfreq2lfreq,
181 wref2window,
182 construct_store: ConstructStore::default(),
183 output_folder,
184 expr_counter: Mutex::new(HashMap::new()),
185 num_exprs: Mutex::new(0),
186 tera,
187 overwrite,
188 main,
189 verdict_streams,
190 no_std_info,
191 }
192 }
193
194 pub(crate) fn streams(&self) -> impl Iterator<Item = StreamReference> + '_ {
195 self.sr2name.keys().sorted().copied()
196 }
197
198 pub(crate) fn inputs(&self) -> impl Iterator<Item = StreamReference> + '_ {
199 self.sr2name
200 .keys()
201 .filter(|o| matches!(o, StreamReference::In(_)))
202 .sorted()
203 .copied()
204 }
205
206 pub(crate) fn outputs(&self) -> impl Iterator<Item = StreamReference> + '_ {
207 self.sr2name
208 .keys()
209 .filter(|o| matches!(o, StreamReference::Out(_)))
210 .sorted()
211 .copied()
212 }
213
214 pub(crate) fn stream_type(&self, sr: StreamReference) -> RustType {
215 self.lola_stream_type(sr).clone().into()
216 }
217
218 pub(crate) fn lola_stream_type(&self, sr: StreamReference) -> &Type {
219 &self.sr2ty[&sr]
220 }
221
222 pub(crate) fn stream_memory(&self, sr: StreamReference) -> &StreamMemory {
223 &self.sr2memory[&sr]
224 }
225
226 pub(crate) fn stream_parameter(&self, sr: StreamReference) -> &[Parameter] {
227 &self.sr2parameters[&sr]
228 }
229
230 pub(crate) fn parameter_ty(&self, sr: StreamReference) -> Option<RustType> {
231 if let Some(parameters) = self.stream_memory(sr).parameters() {
232 let rust_tys = parameters
233 .iter()
234 .map(|p| RustType::from(p.ty.clone()))
235 .collect::<Vec<_>>();
236 Some(match rust_tys.len() {
237 0 => unreachable!(),
238 1 => rust_tys.into_iter().next().unwrap(),
239 2.. => RustType::Tuple(rust_tys),
240 })
241 } else {
242 None
243 }
244 }
245
246 pub(crate) fn windows(&self) -> impl Iterator<Item = WindowReference> + '_ {
247 self.wref2window.keys().sorted().copied()
248 }
249
250 pub(crate) fn sliding_windows(&self) -> impl Iterator<Item = usize> + '_ {
251 self.windows().filter_map(|w| match w {
252 WindowReference::Sliding(i) => Some(i),
253 _ => None,
254 })
255 }
256
257 pub(crate) fn no_std_num_instances(&self, sr: OutputReference) -> Option<usize> {
258 self.no_std_info.as_ref().map(|m| m.max_instances[&sr])
259 }
260}
261
262struct MonitorStruct;
263
264impl StructDefinition for MonitorStruct {
265 fn key(&self) -> RequirementKey {
266 RequirementKey::MonitorStruct
267 }
268
269 fn struct_name(&self, f: &RustFormatter) -> String {
270 f.monitor_struct_name()
271 }
272
273 fn fields(&self, f: &RustFormatter) -> Vec<(String, RustType)> {
274 f.require_struct(StreamMemoryStruct);
275 f.require_enum(DeadlineEnum);
276 if f.no_std_info.is_some() {
277 f.import("heapless::Vec", self.file(f));
278 }
279 f.call_function::<_, String>(MonitorConstructor, &[]);
280 [
281 Some(StreamMemoryStruct.as_argument(f)),
282 (!(f.dynamic_deadlines.is_empty() && f.static_deadlines.is_empty()))
283 .then(|| QueueStruct.as_argument(f)),
284 (!f.wref2window.is_empty()).then(|| WindowMemory.as_argument(f)),
285 Some(f.time_argument()),
286 Some((
287 f.spawned_argument_name(),
288 RustType::Vec(
289 Box::new(DeadlineEnum.as_ty(f)),
290 f.no_std_info.as_ref().map(|i| i.max_spawned),
291 ),
292 )),
293 Some((
294 f.closed_argument_name(),
295 RustType::Vec(
296 Box::new(StreamReferenceEnum.as_ty(f)),
297 f.no_std_info.as_ref().map(|i| i.max_closed),
298 ),
299 )),
300 ]
301 .into_iter()
302 .flatten()
303 .collect()
304 }
305
306 fn visibility(&self) -> FunctionVisibility {
307 FunctionVisibility::Public
308 }
309
310 fn file(&self, _f: &RustFormatter) -> PathBuf {
311 _f.main_file()
312 }
313}