logic_mesh/blocks/
utils.rs

1// Copyright (c) 2022-2023, Radu Racariu.
2
3//!
4//! Various utility functions used by the blocks.
5//!
6
7use std::sync::atomic::AtomicU64;
8
9use super::InputImpl;
10use anyhow::Result;
11use libhaystack::{
12    units::units_generated::MILLISECOND,
13    val::{Number, Value},
14};
15
16/// Default value for sleep intervals
17const DEFAULT_SLEEP_DUR: u64 = 200;
18
19/// A global variable that controls the sleep duration used
20/// to schedule the execution of blocks.
21static SLEEP_DUR: AtomicU64 = AtomicU64::new(DEFAULT_SLEEP_DUR);
22
23/// Set the sleep duration used to schedule the execution of blocks.
24pub fn set_sleep_dur(dur: u64) {
25    SLEEP_DUR.store(dur, std::sync::atomic::Ordering::Relaxed);
26}
27
28/// Get the sleep duration used to schedule the execution of blocks.
29/// If the duration is not set, the default value is returned.
30pub fn get_sleep_dur() -> u64 {
31    SLEEP_DUR.load(std::sync::atomic::Ordering::Relaxed)
32}
33
34pub(super) fn input_as_float_or_default(input: &InputImpl) -> f64 {
35    input_as_number(input).map(|v| v.value).unwrap_or(0.0)
36}
37
38pub(super) fn input_as_number(input: &InputImpl) -> Option<Number> {
39    if let Some(Value::Number(val)) = input.val {
40        Some(val)
41    } else {
42        None
43    }
44}
45
46/// Convert the duration to milliseconds, or return the default with
47/// `DEFAULT_SLEEP_DUR` if the conversion fails.
48pub(super) fn input_to_millis_or_default(dur: &Option<Value>) -> u64 {
49    if let Some(Value::Number(dur)) = dur {
50        if let Some(unit) = dur.unit {
51            match unit.convert_to(dur.value, &MILLISECOND) {
52                Ok(millis) => millis as u64,
53                Err(_) => DEFAULT_SLEEP_DUR,
54            }
55        } else {
56            dur.value as u64
57        }
58    } else {
59        DEFAULT_SLEEP_DUR
60    }
61}
62
63/// Convert all the numbers to the same unit
64///
65/// # Arguments
66/// numbers - the numbers to convert
67///
68/// # Returns
69/// A vector of numbers with the same unit
70pub(super) fn convert_units(numbers: &[Number]) -> Result<Vec<Number>> {
71    if numbers.len() <= 1 {
72        Ok(numbers.to_vec())
73    } else if let Some(unit) = numbers
74        .iter()
75        .find_map(|n| if n.unit.is_some() { n.unit } else { None })
76    {
77        numbers
78            .iter()
79            .map(|n| {
80                if let Some(other_unit) = n.unit {
81                    if other_unit != unit {
82                        other_unit
83                            .convert_to(n.value, unit)
84                            .map_err(|err| anyhow::anyhow!(err))
85                            .map(|v| Number {
86                                value: v,
87                                unit: Some(unit),
88                            })
89                    } else {
90                        Ok(*n)
91                    }
92                } else {
93                    Ok(Number {
94                        value: n.value,
95                        unit: Some(unit),
96                    })
97                }
98            })
99            .collect::<Result<Vec<Number>>>()
100    } else {
101        Ok(numbers.to_vec())
102    }
103}