1use std::error::Error;
2use std::marker::PhantomData;
3use std::path::PathBuf;
4use std::time::SystemTime;
5
6use rtlola_frontend::mir::RtLolaMir;
7
8use crate::config::{Config, ExecutionMode, MonitorConfig, OfflineMode, OnlineMode};
9use crate::configuration::time::{OutputTimeRepresentation, RelativeFloat, TimeRepresentation};
10use crate::input::{ArrayFactory, EventFactory, EventFactoryError, InputMap, MappedFactory};
11use crate::monitor::{NoTracer, Tracer, TracingVerdict, VerdictRepresentation};
12#[cfg(feature = "queued-api")]
13use crate::QueuedMonitor;
14use crate::{CondDeserialize, CondSerialize, Monitor, Value};
15
16pub trait ConfigState {}
20
21#[derive(Debug, Clone, Default, Copy)]
23pub struct ConfigureIR {}
24impl ConfigState for ConfigureIR {}
25
26#[derive(Debug, Clone)]
28pub struct IrConfigured {
29 ir: RtLolaMir,
30}
31impl ConfigState for IrConfigured {}
32
33#[derive(Debug, Clone)]
35pub struct ModeConfigured<Mode: ExecutionMode> {
36 ir: RtLolaMir,
37 mode: Mode,
38}
39impl<Mode: ExecutionMode> ConfigState for ModeConfigured<Mode> {}
40
41#[derive(Debug, Clone)]
43pub struct InputConfigured<Mode: ExecutionMode, Source: EventFactory> {
44 ir: RtLolaMir,
45 mode: Mode,
46 source: PhantomData<Source>,
47}
48impl<Source: EventFactory, Mode: ExecutionMode> ConfigState for InputConfigured<Mode, Source> {}
49
50#[derive(Debug, Clone)]
52pub struct VerdictConfigured<
53 Mode: ExecutionMode,
54 Source: EventFactory,
55 Verdict: VerdictRepresentation,
56> {
57 ir: RtLolaMir,
58 mode: Mode,
59 source: PhantomData<Source>,
60 verdict: PhantomData<Verdict>,
61}
62impl<Source: EventFactory, Verdict: VerdictRepresentation, Mode: ExecutionMode> ConfigState
63 for VerdictConfigured<Mode, Source, Verdict>
64{
65}
66
67#[derive(Debug, Clone)]
86pub struct ConfigBuilder<S: ConfigState, OutputTime: OutputTimeRepresentation> {
87 output_time_representation: PhantomData<OutputTime>,
89 start_time: Option<SystemTime>,
91 state: S,
93}
94
95impl ConfigBuilder<ConfigureIR, RelativeFloat> {
96 pub fn new() -> Self {
98 ConfigBuilder {
99 output_time_representation: PhantomData,
100 start_time: None,
101 state: ConfigureIR {},
102 }
103 }
104}
105
106impl Default for ConfigBuilder<ConfigureIR, RelativeFloat> {
107 fn default() -> Self {
108 Self::new()
109 }
110}
111
112impl<S: ConfigState, OutputTime: OutputTimeRepresentation> ConfigBuilder<S, OutputTime> {
113 pub fn output_time<T: OutputTimeRepresentation>(self) -> ConfigBuilder<S, T> {
117 let ConfigBuilder {
118 output_time_representation: _,
119 start_time,
120 state,
121 } = self;
122 ConfigBuilder {
123 output_time_representation: PhantomData,
124 start_time,
125 state,
126 }
127 }
128
129 pub fn start_time(mut self, time: SystemTime) -> Self {
131 self.start_time = Some(time);
132 self
133 }
134}
135
136impl<OutputTime: OutputTimeRepresentation> ConfigBuilder<ConfigureIR, OutputTime> {
137 pub fn with_ir(self, ir: RtLolaMir) -> ConfigBuilder<IrConfigured, OutputTime> {
139 let ConfigBuilder {
140 output_time_representation,
141 start_time,
142 state: _,
143 } = self;
144 ConfigBuilder {
145 output_time_representation,
146 start_time,
147 state: IrConfigured { ir },
148 }
149 }
150
151 pub fn spec_file(self, path: PathBuf) -> ConfigBuilder<IrConfigured, OutputTime> {
153 let ConfigBuilder {
154 output_time_representation,
155 start_time,
156 state: _,
157 } = self;
158 let config = rtlola_frontend::ParserConfig::from_path(path).unwrap_or_else(|e| {
159 eprintln!("{}", e);
160 std::process::exit(1)
161 });
162 let handler = rtlola_frontend::Handler::from(&config);
163 let ir = rtlola_frontend::parse(&config).unwrap_or_else(|e| {
164 handler.emit_error(&e);
165 std::process::exit(1);
166 });
167 ConfigBuilder {
168 output_time_representation,
169 start_time,
170 state: IrConfigured { ir },
171 }
172 }
173
174 pub fn spec_str(self, spec: &str) -> ConfigBuilder<IrConfigured, OutputTime> {
176 let ConfigBuilder {
177 output_time_representation,
178 start_time,
179 state: _,
180 } = self;
181 let config = rtlola_frontend::ParserConfig::for_string(spec.to_string());
182 let handler = rtlola_frontend::Handler::from(&config);
183 let ir = rtlola_frontend::parse(&config).unwrap_or_else(|e| {
184 handler.emit_error(&e);
185 std::process::exit(1);
186 });
187 ConfigBuilder {
188 output_time_representation,
189 start_time,
190 state: IrConfigured { ir },
191 }
192 }
193}
194
195impl<OutputTime: OutputTimeRepresentation> ConfigBuilder<IrConfigured, OutputTime> {
196 pub fn online(self) -> ConfigBuilder<ModeConfigured<OnlineMode>, OutputTime> {
198 let ConfigBuilder {
199 output_time_representation,
200 start_time,
201 state: IrConfigured { ir },
202 } = self;
203
204 ConfigBuilder {
205 output_time_representation,
206 start_time,
207 state: ModeConfigured {
208 ir,
209 mode: OnlineMode::default(),
210 },
211 }
212 }
213
214 pub fn offline<InputTime: TimeRepresentation>(
219 self,
220 ) -> ConfigBuilder<ModeConfigured<OfflineMode<InputTime>>, OutputTime> {
221 let ConfigBuilder {
222 output_time_representation,
223 start_time,
224 state: IrConfigured { ir },
225 } = self;
226
227 ConfigBuilder {
228 output_time_representation,
229 start_time,
230 state: ModeConfigured {
231 ir,
232 mode: OfflineMode::default(),
233 },
234 }
235 }
236}
237
238impl<Mode: ExecutionMode, OutputTime: OutputTimeRepresentation>
239 ConfigBuilder<ModeConfigured<Mode>, OutputTime>
240{
241 pub fn with_array_events<
243 const N: usize,
244 I: Error + Send + 'static,
245 E: TryInto<[Value; N], Error = I> + CondSerialize + CondDeserialize + Send,
246 >(
247 self,
248 ) -> ConfigBuilder<InputConfigured<Mode, ArrayFactory<N, I, E>>, OutputTime> {
249 let ConfigBuilder {
250 output_time_representation,
251 start_time,
252 state: ModeConfigured { ir, mode },
253 } = self;
254
255 ConfigBuilder {
256 output_time_representation,
257 start_time,
258 state: InputConfigured {
259 ir,
260 mode,
261 source: PhantomData,
262 },
263 }
264 }
265
266 pub fn with_mapped_events<Inner: InputMap>(
269 self,
270 ) -> ConfigBuilder<InputConfigured<Mode, MappedFactory<Inner>>, OutputTime> {
271 let ConfigBuilder {
272 output_time_representation,
273 start_time,
274 state: ModeConfigured { ir, mode },
275 } = self;
276
277 ConfigBuilder {
278 output_time_representation,
279 start_time,
280 state: InputConfigured {
281 ir,
282 mode,
283 source: PhantomData,
284 },
285 }
286 }
287
288 pub fn with_event_factory<Source: EventFactory>(
290 self,
291 ) -> ConfigBuilder<InputConfigured<Mode, Source>, OutputTime> {
292 let ConfigBuilder {
293 output_time_representation,
294 start_time,
295 state: ModeConfigured { ir, mode },
296 } = self;
297
298 ConfigBuilder {
299 output_time_representation,
300 start_time,
301 state: InputConfigured {
302 ir,
303 mode,
304 source: PhantomData,
305 },
306 }
307 }
308}
309
310impl<Mode: ExecutionMode, OutputTime: OutputTimeRepresentation, Source: EventFactory>
311 ConfigBuilder<InputConfigured<Mode, Source>, OutputTime>
312{
313 pub fn with_verdict<Verdict: VerdictRepresentation>(
315 self,
316 ) -> ConfigBuilder<VerdictConfigured<Mode, Source, Verdict>, OutputTime> {
317 let ConfigBuilder {
318 output_time_representation,
319 start_time,
320 state: InputConfigured { ir, mode, source },
321 } = self;
322 ConfigBuilder {
323 output_time_representation,
324 start_time,
325 state: VerdictConfigured {
326 ir,
327 mode,
328 source,
329 verdict: Default::default(),
330 },
331 }
332 }
333}
334
335impl<
336 Source: EventFactory + 'static,
337 Mode: ExecutionMode,
338 Verdict: VerdictRepresentation<Tracing = NoTracer>,
339 OutputTime: OutputTimeRepresentation,
340 > ConfigBuilder<VerdictConfigured<Mode, Source, Verdict>, OutputTime>
341{
342 pub fn with_tracer<T: Tracer>(
344 self,
345 ) -> ConfigBuilder<VerdictConfigured<Mode, Source, TracingVerdict<T, Verdict>>, OutputTime>
346 {
347 let ConfigBuilder {
348 output_time_representation,
349 start_time,
350 state:
351 VerdictConfigured {
352 ir,
353 mode,
354 source,
355 verdict: _,
356 },
357 } = self;
358 ConfigBuilder {
359 output_time_representation,
360 start_time,
361 state: VerdictConfigured {
362 ir,
363 mode,
364 source,
365 verdict: Default::default(),
366 },
367 }
368 }
369}
370
371impl<
372 Source: EventFactory + 'static,
373 Mode: ExecutionMode,
374 Verdict: VerdictRepresentation,
375 OutputTime: OutputTimeRepresentation,
376 > ConfigBuilder<VerdictConfigured<Mode, Source, Verdict>, OutputTime>
377{
378 pub fn build(self) -> MonitorConfig<Source, Mode, Verdict, OutputTime> {
380 let ConfigBuilder {
381 output_time_representation,
382 start_time,
383 state: VerdictConfigured { ir, mode, .. },
384 } = self;
385 let config = Config {
386 ir,
387 mode,
388 output_time_representation,
389 start_time,
390 };
391 MonitorConfig::new(config)
392 }
393
394 pub fn monitor_with_data(
396 self,
397 data: Source::CreationData,
398 ) -> Result<Monitor<Source, Mode, Verdict, OutputTime>, EventFactoryError> {
399 self.build().monitor_with_data(data)
400 }
401
402 pub fn monitor(self) -> Result<Monitor<Source, Mode, Verdict, OutputTime>, EventFactoryError>
404 where
405 Source: EventFactory<CreationData = ()> + 'static,
406 {
407 self.build().monitor()
408 }
409}
410
411impl<
412 Source: EventFactory + 'static,
413 SourceTime: TimeRepresentation,
414 Verdict: VerdictRepresentation,
415 OutputTime: OutputTimeRepresentation,
416 > ConfigBuilder<VerdictConfigured<OfflineMode<SourceTime>, Source, Verdict>, OutputTime>
417{
418 #[cfg(feature = "queued-api")]
419 pub fn queued_monitor_with_data(
421 self,
422 data: Source::CreationData,
423 ) -> QueuedMonitor<Source, OfflineMode<SourceTime>, Verdict, OutputTime> {
424 self.build().queued_monitor_with_data(data)
425 }
426
427 #[cfg(feature = "queued-api")]
428 pub fn queued_monitor(
430 self,
431 ) -> QueuedMonitor<Source, OfflineMode<SourceTime>, Verdict, OutputTime>
432 where
433 Source: EventFactory<CreationData = ()> + 'static,
434 {
435 self.build().queued_monitor()
436 }
437}
438
439impl<
440 Source: EventFactory + 'static,
441 Verdict: VerdictRepresentation,
442 OutputTime: OutputTimeRepresentation,
443 > ConfigBuilder<VerdictConfigured<OnlineMode, Source, Verdict>, OutputTime>
444{
445 #[cfg(feature = "queued-api")]
446 pub fn queued_monitor_with_data(
448 self,
449 data: Source::CreationData,
450 ) -> QueuedMonitor<Source, OnlineMode, Verdict, OutputTime> {
451 self.build().queued_monitor_with_data(data)
452 }
453
454 #[cfg(feature = "queued-api")]
455 pub fn queued_monitor(self) -> QueuedMonitor<Source, OnlineMode, Verdict, OutputTime>
457 where
458 Source: EventFactory<CreationData = ()> + 'static,
459 {
460 self.build().queued_monitor()
461 }
462}