cog_task/server/task/
block.rs

1use crate::action::Action;
2use crate::comm::SignalId;
3use crate::resource::ResourceAddr;
4use crate::server::{config::OptionalConfig, Config, State};
5use crate::util::Hash;
6use eyre::{eyre, Result};
7use serde::{Deserialize, Serialize};
8use serde_cbor::ser::to_vec_packed;
9use serde_cbor::Value;
10use std::collections::BTreeMap;
11
12#[derive(Deserialize, Serialize, Debug)]
13pub struct Block {
14    name: String,
15    #[serde(default)]
16    #[serde(alias = "cfg")]
17    config: OptionalConfig,
18    tree: Box<dyn Action>,
19    #[serde(default)]
20    state: BTreeMap<SignalId, Value>,
21}
22
23impl Block {
24    pub fn init(&mut self) -> Result<()> {
25        self.verify_name()?;
26        self.verify_connections()?;
27        Ok(())
28    }
29
30    fn verify_name(&self) -> Result<()> {
31        if self.name.is_empty() {
32            Err(eyre!("Block `name` cannot be the empty string."))
33        } else if !self
34            .name
35            .chars()
36            .all(|c| c.is_alphabetic() || c.is_alphanumeric() | "+-_() ".contains(c))
37        {
38            Err(eyre!(
39                "Block `name` characters need to be alphanumeric or one of (+-_() ): '{}'",
40                self.name
41            ))
42        } else {
43            Ok(())
44        }
45    }
46
47    fn verify_connections(&self) -> Result<()> {
48        let mut in_signals = self.tree.in_signals();
49        let mut out_signals = self.tree.out_signals();
50
51        in_signals.insert(0);
52        out_signals.insert(0);
53
54        let in_not_out: Vec<_> = in_signals.difference(&out_signals).collect();
55        let out_not_in: Vec<_> = out_signals.difference(&in_signals).collect();
56
57        if !in_not_out.is_empty() {
58            Err(eyre!("Consumed signals are never produced: {in_not_out:?}"))
59        } else if !out_not_in.is_empty() {
60            Err(eyre!("Produced signals are never consumed: {out_not_in:?}"))
61        } else {
62            Ok(())
63        }
64    }
65
66    pub fn resources(&self, config: &Config) -> Vec<ResourceAddr> {
67        self.tree.resources(config)
68    }
69
70    #[inline(always)]
71    pub fn action_tree(&self) -> &dyn Action {
72        &*self.tree
73    }
74
75    #[inline(always)]
76    pub fn action_tree_vec(&self) -> Vec<u8> {
77        to_vec_packed(&self.tree).unwrap()
78    }
79
80    #[inline(always)]
81    pub fn default_state(&self) -> &State {
82        &self.state
83    }
84
85    #[inline(always)]
86    pub fn label(&self) -> &str {
87        &self.name
88    }
89
90    #[inline]
91    pub fn config(&self, base_config: &Config) -> Config {
92        self.config.fill_blanks(base_config)
93    }
94}
95
96impl Hash for Block {
97    fn hash(&self) -> String {
98        use sha2::{Digest, Sha256};
99        let mut hasher = Sha256::default();
100        hasher.update(&serde_cbor::to_vec(&(&self.tree, &self.config)).unwrap());
101        hex::encode(hasher.finalize())
102    }
103}