Skip to main content

ommui_data/annalisa/
mod.rs

1use crate::Result;
2use indexmap::{IndexMap, IndexSet};
3
4#[derive(Serialize, Deserialize, Debug, Clone)]
5#[serde(rename_all = "lowercase", tag = "type", content = "details")]
6pub enum Bin {
7    Add,
8    Blocker,
9    CalibrationLookup(CalibrationLookupDetails),
10    CalmingDetection,
11    Cosinus,
12    Cumulate,
13    Derivation,
14    Difference,
15    Divide,
16    Fifo,
17    FirstValue,
18    FixedValues(FixedValuesDetails),
19    GreaterThan,
20    Invert,
21    LinearInterpolatedLookup(LinearInterpolatedLookupDetails),
22    LinearRegression,
23    Maximum,
24    MeanValue,
25    Minimum,
26    Multiplex(MultiplexDetails),
27    Multiply,
28    Not,
29    Pipeline(PipelineDetails),
30    SingleNotNull(SingleNotNullDetails),
31    Sinus,
32    Storage,
33    Subtract,
34}
35
36impl PipelineDetails {
37    pub fn to_arnalisa(
38        &self,
39    ) -> Result<arnalisa::bins::pipeline::Description> {
40        let inputs = self
41            .pipes
42            .iter()
43            .filter_map(|pipe| {
44                if pipe.from.bin.is_empty() {
45                    Some(pipe.from.source.to_string())
46                } else {
47                    None
48                }
49            })
50            .collect::<IndexSet<_>>();
51
52        let bins = self
53            .bins
54            .iter()
55            .map(|(k, v)| {
56                use self::Bin as B;
57                use arnalisa::bins::SourceSinkDescription as D;
58                use arnalisa::bins::*;
59                use arnalisa::CalibrationSource;
60                let description = match v {
61                    B::Add => D::Add(add::Description),
62                    B::Blocker => D::Blocker(blocker::Description),
63                    B::CalibrationLookup(details) => {
64                        D::Calibration(calibration::Description {
65                            details: CalibrationSource::Identifier {
66                                id: details.calibration_id.to_string(),
67                            },
68                            reversed: details.reversed,
69                        })
70                    }
71                    B::CalmingDetection => {
72                        D::LastCalmPoint(last_calm_point::Description)
73                    }
74                    B::Cosinus => D::Cosinus(cosinus::Description),
75                    B::Cumulate => D::Cumulation(cumulation::Description),
76                    B::Derivation => {
77                        D::Derivation(derivation::Description)
78                    }
79                    B::Difference => {
80                        D::Derivation(derivation::Description)
81                    }
82                    B::Divide => D::Divide(divide::Description),
83                    B::Fifo => D::Fifo(fifo::Description),
84                    B::FirstValue => {
85                        D::FirstValue(first_value::Description)
86                    }
87                    B::FixedValues(details) => {
88                        D::FixedValues(fixedvalues::Description {
89                            values: details.fixed_values.clone(),
90                        })
91                    }
92                    B::GreaterThan => {
93                        D::GreaterThan(greater_than::Description)
94                    }
95                    B::Invert => D::Invert(invert::Description),
96                    B::LinearInterpolatedLookup(details) => {
97                        D::Calibration(calibration::Description {
98                            details: CalibrationSource::Embedded {
99                                curve: details.points.clone(),
100                            },
101                            reversed: false,
102                        })
103                    }
104                    B::LinearRegression => {
105                        D::LinearRegression(linear_regression::Description)
106                    }
107                    B::Maximum => D::Maximum(maximum::Description),
108                    B::MeanValue => D::Mean(mean::Description),
109                    B::Minimum => D::Minimum(minimum::Description),
110                    B::Multiplex(details) => {
111                        D::Multiplex(multiplex::Description {
112                            outputs: details.outputs.clone(),
113                        })
114                    }
115                    B::Multiply => D::Multiply(multiply::Description),
116                    B::Not => D::Not(not::Description),
117                    B::Pipeline(details) => {
118                        D::Pipeline(details.to_arnalisa()?)
119                    }
120                    B::SingleNotNull(details) => D::SingleNotNull({
121                        single_not_null::Description {
122                            inputs: details.inputs.clone(),
123                        }
124                    }),
125                    B::Sinus => D::Sinus(sinus::Description),
126                    B::Storage => D::Storage(storage::Description),
127                    B::Subtract => D::Subtract(subtract::Description),
128                };
129                Ok((k.to_string(), description))
130            })
131            .collect::<Result<IndexMap<_, _>>>()?;
132
133        fn pipes_for_bin(
134            raw_pipes: &[Pipe],
135            bin: &str,
136            bins: &IndexMap<String, arnalisa::bins::SourceSinkDescription>,
137        ) -> IndexMap<String, arnalisa::bins::SourceReference> {
138            let pipes = raw_pipes
139                .iter()
140                .filter_map(|pipe| {
141                    if pipe.to.bin == bin {
142                        Some((
143                            pipe.to.sink.to_string(),
144                            arnalisa::bins::SourceReference {
145                                bin: if pipe.from.bin.is_empty() {
146                                    None
147                                } else {
148                                    Some(pipe.from.bin.to_string())
149                                },
150                                source: pipe.from.source.to_string(),
151                            },
152                        ))
153                    } else {
154                        None
155                    }
156                })
157                .collect::<IndexMap<_, _>>();
158            let pipes = fixup_pipe_sources(pipes, bins);
159            if let Some(bin) = bins.get(&bin.to_string()) {
160                fixup_pipe_sinks(pipes, &bin)
161            } else {
162                pipes
163            }
164        }
165
166        fn fixup_pipe_sources(
167            mut p: IndexMap<String, arnalisa::bins::SourceReference>,
168            bins: &IndexMap<String, arnalisa::bins::SourceSinkDescription>,
169        ) -> IndexMap<String, arnalisa::bins::SourceReference> {
170            for pipe in p.values_mut() {
171                if let Some(ref bin) = pipe.bin {
172                    if let Some(bin) = bins.get(bin) {
173                        use arnalisa::bins::SourceSinkDescription::*;
174                        match bin {
175                            Add(_) => {
176                                if pipe.source == "sum" {
177                                    pipe.source = "output".to_string();
178                                }
179                            }
180                            Blocker(_) => {}
181                            Calibration(_) => {}
182                            Cosinus(_) => {}
183                            Cumulation(_) => {}
184                            Derivation(_) => {
185                                if pipe.source == "difference" {
186                                    pipe.source = "output".to_string();
187                                }
188                            }
189                            Divide(_) => {
190                                if pipe.source == "quotient" {
191                                    pipe.source = "output".to_string();
192                                }
193                            }
194                            Fifo(_) => {}
195                            FirstValue(_) => {}
196                            FixedValues(_) => {}
197                            GreaterThan(_) => {}
198                            Invert(_) => {}
199                            LastCalmPoint(_) => {}
200                            LinearRegression(_) => {}
201                            Maximum(_) => {}
202                            Mean(_) => {}
203                            Minimum(_) => {}
204                            Multiplex(_) => {}
205                            Multiply(_) => {
206                                if pipe.source == "product" {
207                                    pipe.source = "output".to_string();
208                                }
209                            }
210                            Not(_) => {}
211                            Pipeline(_) => {}
212                            SingleNotNull(_) => {}
213                            Sinus(_) => {}
214                            Subtract(_) => {
215                                if pipe.source == "difference" {
216                                    pipe.source = "output".to_string();
217                                }
218                            }
219                            Storage(_) => {}
220                        }
221                    }
222                }
223            }
224
225            p
226        }
227
228        fn fixup_pipe_sinks(
229            mut p: IndexMap<String, arnalisa::bins::SourceReference>,
230            bin: &arnalisa::bins::SourceSinkDescription,
231        ) -> IndexMap<String, arnalisa::bins::SourceReference> {
232            use arnalisa::bins::SourceSinkDescription::*;
233            match bin {
234                Add(_) => {
235                    if let Some(a) = p.swap_remove(&"summand1".to_string())
236                    {
237                        p.insert("a".to_string(), a);
238                    }
239                    if let Some(b) = p.swap_remove(&"summand2".to_string())
240                    {
241                        p.insert("b".to_string(), b);
242                    }
243                    p.sort_keys();
244                    p
245                }
246                Blocker(_) => p,
247                Calibration(_) => p,
248                Cosinus(_) => p,
249                Cumulation(_) => p,
250                Derivation(_) => p,
251                Divide(_) => {
252                    if let Some(a) = p.swap_remove(&"dividend".to_string())
253                    {
254                        p.insert("a".to_string(), a);
255                    }
256                    if let Some(b) = p.swap_remove(&"divisor".to_string())
257                    {
258                        p.insert("b".to_string(), b);
259                    }
260                    p.sort_keys();
261                    p
262                }
263                Fifo(_) => p,
264                FirstValue(_) => p,
265                FixedValues(_) => {
266                    if let Some(trigger) =
267                        p.swap_remove(&"finishDetectionInput".to_string())
268                    {
269                        p.insert("trigger".to_string(), trigger);
270                    }
271                    p.sort_keys();
272                    p
273                }
274                GreaterThan(_) => p,
275                Invert(_) => p,
276                LastCalmPoint(_) => {
277                    if let Some(y_max_delta) =
278                        p.swap_remove(&"yMaxDelta".to_string())
279                    {
280                        p.insert("y_max_delta".to_string(), y_max_delta);
281                    }
282                    p
283                }
284                LinearRegression(_) => {
285                    if let Some(trigger) =
286                        p.swap_remove(&"numItems".to_string())
287                    {
288                        p.insert("num_items".to_string(), trigger);
289                    }
290                    p.sort_keys();
291                    p
292                }
293                Maximum(_) => p,
294                Mean(_) => p,
295                Minimum(_) => p,
296                Multiplex(_) => {
297                    if let Some(input) =
298                        p.swap_remove(&"value".to_string())
299                    {
300                        p.insert("input".to_string(), input);
301                    }
302                    p.sort_keys();
303                    p
304                }
305                Multiply(_) => {
306                    if let Some(a) = p.swap_remove(&"factor1".to_string())
307                    {
308                        p.insert("a".to_string(), a);
309                    }
310                    if let Some(b) = p.swap_remove(&"factor2".to_string())
311                    {
312                        p.insert("b".to_string(), b);
313                    }
314                    p.sort_keys();
315                    p
316                }
317                Not(_) => p,
318                Pipeline(_) => p,
319                SingleNotNull(_) => p,
320                Sinus(_) => p,
321                Subtract(_) => {
322                    if let Some(a) = p.swap_remove(&"minuend".to_string())
323                    {
324                        p.insert("a".to_string(), a);
325                    }
326                    if let Some(b) =
327                        p.swap_remove(&"subtrahend".to_string())
328                    {
329                        p.insert("b".to_string(), b);
330                    }
331                    p.sort_keys();
332                    p
333                }
334                Storage(_) => p,
335            }
336        }
337
338        let pipes = std::iter::once("".to_string())
339            .chain(bins.keys().cloned())
340            .filter_map(|k| {
341                let pipes = pipes_for_bin(&self.pipes, &k, &bins);
342                if pipes.is_empty() {
343                    None
344                } else {
345                    Some((k, pipes))
346                }
347            })
348            .collect::<IndexMap<_, _>>();
349
350        Ok(arnalisa::bins::pipeline::Description {
351            pipes,
352            bins,
353            inputs,
354        })
355    }
356}
357
358#[derive(Serialize, Deserialize, Debug, Clone)]
359#[serde(rename_all = "camelCase")]
360pub struct PipelineDetails {
361    #[serde(default, skip_serializing_if = "IndexMap::is_empty")]
362    pub bins: IndexMap<String, Bin>,
363    pub pipes: Vec<Pipe>,
364}
365
366#[derive(Serialize, Deserialize, Debug, Clone)]
367#[serde(rename_all = "camelCase")]
368pub struct CalibrationLookupDetails {
369    pub calibration_id: String,
370    pub reversed: bool,
371}
372
373#[derive(Serialize, Deserialize, Debug, Clone)]
374#[serde(rename_all = "camelCase")]
375pub struct FixedValuesDetails {
376    pub fixed_values: IndexMap<String, arnalisa::Item>,
377}
378
379#[derive(Serialize, Deserialize, Debug, Clone)]
380#[serde(rename_all = "camelCase")]
381pub struct LinearInterpolatedLookupDetails {
382    pub points: Vec<(f64, f64)>,
383}
384
385#[derive(Serialize, Deserialize, Debug, Clone)]
386#[serde(rename_all = "camelCase")]
387pub struct MultiplexDetails {
388    pub outputs: IndexMap<String, usize>,
389}
390
391#[derive(Serialize, Deserialize, Debug, Clone)]
392#[serde(rename_all = "camelCase")]
393pub struct Pipe {
394    pub from: PipeSource,
395    pub to: PipeSink,
396}
397
398#[derive(Serialize, Deserialize, Debug, Clone)]
399#[serde(rename_all = "camelCase")]
400pub struct PipeSource {
401    #[serde(default, skip_serializing_if = "String::is_empty")]
402    pub bin: String,
403    pub source: String,
404}
405
406#[derive(Serialize, Deserialize, Debug, Clone)]
407#[serde(rename_all = "camelCase")]
408pub struct PipeSink {
409    #[serde(default, skip_serializing_if = "String::is_empty")]
410    pub bin: String,
411    pub sink: String,
412}
413
414#[derive(Serialize, Deserialize, Debug, Clone)]
415#[serde(rename_all = "camelCase")]
416pub struct SingleNotNullDetails {
417    pub inputs: IndexSet<String>,
418}