logic_mesh/blocks/math/
add.rs

1// Copyright (c) 2022-2023, Radu Racariu.
2
3use uuid::Uuid;
4
5use crate::base::{
6    block::{Block, BlockDesc, BlockProps, BlockState},
7    input::{input_reader::InputReader, Input, InputProps},
8    output::Output,
9};
10
11use libhaystack::val::{kind::HaystackKind, Number, Value};
12
13use crate::{blocks::InputImpl, blocks::OutputImpl};
14
15/// Performs an addition of multiple numbers from the 16 inputs
16/// this block has.
17/// The addition would take into account the units of those input's values,
18/// if the units are not convertible, the block would be in an error state.
19#[block]
20#[derive(BlockProps, Debug)]
21#[dis = "Add"]
22#[category = "math"]
23#[input(kind = "Number", count = 16)]
24pub struct Add {
25    #[output(kind = "Number")]
26    pub out: OutputImpl,
27}
28
29impl Block for Add {
30    async fn execute(&mut self) {
31        self.read_inputs_until_ready().await;
32
33        let mut has_err = false;
34
35        let val = self
36            .inputs()
37            .into_iter()
38            .filter_map(|input| match input.get_value().as_ref() {
39                Some(Value::Number(num)) => Some(*num),
40                _ => None,
41            })
42            .reduce(|mut acc, val| {
43                if acc.unit.is_none() && acc.value == 0.0 {
44                    if let Some(unit) = val.unit {
45                        acc = Number::make_with_unit(0.0, unit);
46                    }
47                };
48
49                match acc + val {
50                    Ok(res) => res,
51                    Err(_) => {
52                        has_err = true;
53                        Number::make(0.0)
54                    }
55                }
56            });
57
58        if has_err {
59            self.set_state(BlockState::Fault);
60        } else if self.state() != BlockState::Running {
61            self.set_state(BlockState::Running);
62        }
63
64        if let Some(res) = val {
65            self.out.set((res).into())
66        }
67    }
68}
69
70#[cfg(test)]
71mod test {
72
73    use crate::base::input::input_reader::InputReader;
74    use crate::{
75        base::block::{Block, BlockProps},
76        blocks::math::Add,
77    };
78
79    #[tokio::test]
80    async fn test_add_block() {
81        let mut block = Add::new();
82
83        {
84            let in1 = block.get_input_mut("in0").unwrap();
85            in1.increment_conn();
86            in1.writer().try_send(3.into()).unwrap();
87            block.read_inputs().await;
88        }
89
90        {
91            let in16 = block.get_input_mut("in15").unwrap();
92            in16.increment_conn();
93            in16.writer().try_send(3.into()).unwrap();
94        }
95
96        block.execute().await;
97        assert_eq!(block.out.value, 6.into());
98    }
99}