use alloc::vec::Vec; use hashbrown::HashMap; use crate::{ mode::{Mode, ModeAndSubmode, ModeReply, ModeRequest, Submode}, request::MessageSender, ComponentId, }; #[cfg(feature = "alloc")] pub use alloc_mod::*; /// Common trait for node modes which can have mode parents or mode children. pub trait ModeNode { fn id(&self) -> ComponentId; } /// Trait which denotes that an object is a parent in a mode tree. /// /// A mode parent is capable of sending mode requests to child objects and has a unique component /// ID. pub trait ModeParent: ModeNode { type Sender: MessageSender; fn add_mode_child(&mut self, id: ComponentId, request_sender: Self::Sender); } /// Trait which denotes that an object is a child in a mode tree. /// /// A child is capable of sending mode replies to parent objects and has a unique component ID. pub trait ModeChild: ModeNode { type Sender: MessageSender; fn add_mode_parent(&mut self, id: ComponentId, reply_sender: Self::Sender); } /// Utility method which connects a mode tree parent object to a child object by calling /// [ModeParent::add_mode_child] on the [parent][ModeParent] and calling /// [ModeChild::add_mode_parent] on the [child][ModeChild]. /// /// # Arguments /// /// * `parent` - The parent object which implements [ModeParent]. /// * `request_sender` - Sender object to send mode requests to the child. /// * `child` - The child object which implements [ModeChild]. /// * `reply_sender` - Sender object to send mode replies to the parent. pub fn connect_mode_nodes( parent: &mut impl ModeParent, request_sender: ReqSender, child: &mut impl ModeChild, reply_sender: ReplySender, ) { parent.add_mode_child(child.id(), request_sender); child.add_mode_parent(parent.id(), reply_sender); } #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum TableEntryType { /// Target table containing information of the expected children modes for given mode. Target, /// Sequence table which contains information about how to reach a target table, including /// the order of the sequences. Sequence, } /// Common fields required for both target and sequence table entries. /// /// The most important parameters here are the target ID which this entry belongs to, and the mode /// and submode the entry either will be commanded to for sequence table entries or which will be /// monitored for target table entries. #[derive(Debug, Copy, Clone)] pub struct ModeTableEntryCommon { /// Name of respective table entry. pub name: &'static str, /// Target component ID. pub target_id: ComponentId, /// Has a different meaning depending on whether this is a sequence table or a target table. /// /// - For sequence tables, this denotes the mode which will be commanded /// - For target tables, this is the mode which the target children should have and which /// might be monitored depending on configuration. pub mode_submode: ModeAndSubmode, /// This mask allows to specify multiple allowed submodes for a given mode. pub allowed_submode_mask: Option, } impl ModeTableEntryCommon { pub fn set_allowed_submode_mask(&mut self, mask: Submode) { self.allowed_submode_mask = Some(mask); } pub fn allowed_submode_mask(&self) -> Option { self.allowed_submode_mask } } /// An entry for the target tables. #[derive(Debug)] pub struct TargetTableEntry { pub common: ModeTableEntryCommon, pub monitor_state: bool, } impl TargetTableEntry { pub fn new( name: &'static str, target_id: ComponentId, mode_submode: ModeAndSubmode, monitor_state: bool, allowed_submode_mask: Option, ) -> Self { Self { common: ModeTableEntryCommon { name, target_id, mode_submode, allowed_submode_mask, }, monitor_state, } } pub fn new_with_precise_submode( name: &'static str, target_id: ComponentId, mode_submode: ModeAndSubmode, monitor_state: bool, ) -> Self { Self { common: ModeTableEntryCommon { name, target_id, mode_submode, allowed_submode_mask: None, }, monitor_state, } } delegate::delegate! { to self.common { pub fn set_allowed_submode_mask(&mut self, mask: Submode); pub fn allowed_submode_mask(&self) -> Option; } } } /// An entry for the sequence tables. /// /// The `check_success` field instructs the mode sequence executor to verify that the /// target mode was actually reached before executing the next sequence. #[derive(Debug)] pub struct SequenceTableEntry { pub common: ModeTableEntryCommon, pub check_success: bool, } impl SequenceTableEntry { pub fn new( name: &'static str, target_id: ComponentId, mode_submode: ModeAndSubmode, check_success: bool, ) -> Self { Self { common: ModeTableEntryCommon { name, target_id, mode_submode, allowed_submode_mask: None, }, check_success, } } delegate::delegate! { to self.common { pub fn set_allowed_submode_mask(&mut self, mask: Submode); pub fn allowed_submode_mask(&self) -> Option; } } } pub trait ModeStoreProvider { fn add_component(&mut self, target_id: ComponentId, mode: ModeAndSubmode); fn get_mode(&self, target_id: ComponentId) -> Option; fn set_mode(&mut self, target_id: ComponentId, mode: ModeAndSubmode); } #[cfg(feature = "alloc")] pub mod alloc_mod { use super::*; #[derive(Debug)] pub struct TargetTablesMapValue { /// Name for a given mode table entry. pub name: &'static str, /// These are the rows of the a target table. pub entries: Vec, } impl TargetTablesMapValue { pub fn new(name: &'static str) -> Self { Self { name, entries: Default::default(), } } pub fn add_entry(&mut self, entry: TargetTableEntry) { self.entries.push(entry); } } #[derive(Debug)] pub struct SequenceTableMapTable { /// Name for a given mode sequence. pub name: &'static str, /// These are the rows of the a sequence table. pub entries: Vec, } impl SequenceTableMapTable { pub fn new(name: &'static str) -> Self { Self { name, entries: Default::default(), } } pub fn add_entry(&mut self, entry: SequenceTableEntry) { self.entries.push(entry); } } #[derive(Debug)] pub struct SequenceTablesMapValue { /// Name for a given mode sequence. pub name: &'static str, /// Each sequence can consists of multiple sequences that are executed consecutively. pub entries: Vec, } impl SequenceTablesMapValue { pub fn new(name: &'static str) -> Self { Self { name, entries: Default::default(), } } pub fn add_sequence_table(&mut self, entry: SequenceTableMapTable) { self.entries.push(entry); } } #[derive(Debug, Default)] pub struct TargetModeTables(pub HashMap); #[derive(Debug, Default)] pub struct SequenceModeTables(pub HashMap); #[derive(Debug, Default)] pub struct ModeStoreVec(pub alloc::vec::Vec<(ComponentId, ModeAndSubmode)>); #[derive(Debug, Default)] pub struct ModeStoreMap(pub hashbrown::HashMap); impl ModeStoreProvider for ModeStoreVec { fn add_component(&mut self, target_id: ComponentId, mode: ModeAndSubmode) { self.0.push((target_id, mode)); } fn get_mode(&self, target_id: ComponentId) -> Option { self.0.iter().find_map(|(id, mode)| { if *id == target_id { return Some(*mode); } None }) } fn set_mode(&mut self, target_id: ComponentId, mode_to_set: ModeAndSubmode) { self.0.iter_mut().for_each(|(id, mode)| { if *id == target_id { *mode = mode_to_set; } }); } } impl ModeStoreProvider for ModeStoreMap { fn add_component(&mut self, target_id: ComponentId, mode: ModeAndSubmode) { self.0.insert(target_id, mode); } fn get_mode(&self, target_id: ComponentId) -> Option { self.0.get(&target_id).copied() } fn set_mode(&mut self, target_id: ComponentId, mode_to_set: ModeAndSubmode) { self.0.insert(target_id, mode_to_set); } } } #[cfg(test)] mod tests {}