logic_mesh/blocks/math/
min.rs1use anyhow::Ok;
4use uuid::Uuid;
5
6use crate::{
7 base::{
8 block::{Block, BlockDesc, BlockProps, BlockState},
9 input::{input_reader::InputReader, Input, InputProps},
10 output::Output,
11 },
12 blocks::utils::convert_units,
13};
14
15use libhaystack::val::{kind::HaystackKind, Number, Value};
16
17use crate::{blocks::InputImpl, blocks::OutputImpl};
18
19#[block]
21#[derive(BlockProps, Debug)]
22#[dis = "Minimum"]
23#[category = "math"]
24pub struct Min {
25 #[input(kind = "Number")]
26 pub a: InputImpl,
27 #[input(kind = "Number")]
28 pub b: InputImpl,
29 #[output(kind = "Number")]
30 pub out: OutputImpl,
31}
32
33impl Block for Min {
34 async fn execute(&mut self) {
35 self.read_inputs_until_ready().await;
36
37 if let (Some(Value::Number(a)), Some(Value::Number(b))) =
38 (self.a.get_value(), self.b.get_value())
39 {
40 let _ = convert_units(&[a.to_owned(), b.to_owned()])
41 .and_then(|parts| {
42 if let [a, b] = &parts[..] {
43 let val = Number {
44 value: a.value.min(b.value),
45 unit: a.unit,
46 };
47 self.out.set(val.into());
48 }
49 Ok(())
50 })
51 .or_else(|_| {
52 self.set_state(BlockState::Fault);
53 Ok(())
54 });
55 }
56 }
57}
58
59#[cfg(test)]
60mod test {
61
62 use std::assert_matches::assert_matches;
63
64 use libhaystack::val::{Number, Value};
65
66 use crate::{
67 base::block::test_utils::write_block_inputs,
68 base::{block::Block, input::input_reader::InputReader},
69 blocks::math::Min,
70 };
71
72 #[tokio::test]
73 async fn test_min_block() {
74 let mut block = Min::new();
75
76 for _ in
77 write_block_inputs(&mut [(&mut block.a, 8.into()), (&mut block.b, 42.into())]).await
78 {
79 block.read_inputs().await;
80 }
81
82 block.execute().await;
83
84 assert_matches!(
85 block.out.value,
86 Value::Number(Number { value, .. }) if value == 8.0
87 );
88 }
89}