logic_mesh/blocks/math/
mul.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 a multiplication of multiple numbers from the 16 inputs
16/// this block has.
17/// The operation 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#[category = "math"]
22#[input(kind = "Number", count = 16)]
23pub struct Mul {
24    #[output(kind = "Number")]
25    pub out: OutputImpl,
26}
27
28impl Block for Mul {
29    async fn execute(&mut self) {
30        self.read_inputs_until_ready().await;
31
32        let mut val: Option<Number> = None;
33        let mut cnt = 0;
34        for el in self
35            .inputs()
36            .into_iter()
37            .filter_map(|input| match input.get_value().as_ref() {
38                Some(Value::Number(num)) => Some(*num),
39                _ => None,
40            })
41        {
42            cnt += 1;
43
44            if let Some(v) = val {
45                let res = v * el;
46
47                if res.is_err() {
48                    val = None;
49                    break;
50                }
51
52                match res {
53                    Ok(res) => {
54                        val.replace(res);
55                    }
56                    Err(_) => {
57                        val = None;
58                        break;
59                    }
60                }
61            } else {
62                val = Some(el);
63            }
64        }
65
66        if cnt > 1 {
67            if let Some(res) = val {
68                self.out.set(res.into())
69            }
70        }
71    }
72}
73
74#[cfg(test)]
75mod test {
76
77    use crate::base::input::input_reader::InputReader;
78    use crate::{
79        base::block::{Block, BlockProps},
80        blocks::math::Mul,
81    };
82
83    #[tokio::test]
84    async fn test_mul_block() {
85        let mut block = Mul::new();
86
87        {
88            let in1 = block.get_input_mut("in0").unwrap();
89            in1.increment_conn();
90            in1.writer().try_send(3.into()).unwrap();
91            block.read_inputs().await;
92        }
93
94        {
95            let in16 = block.get_input_mut("in15").unwrap();
96            in16.increment_conn();
97            in16.writer().try_send(3.into()).unwrap();
98        }
99
100        block.execute().await;
101        assert_eq!(block.out.value, 9.into());
102    }
103}