logic_mesh/blocks/math/
add.rs1use 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#[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}