sans_io_runtime/bus/
local_hub.rs

1use std::{collections::HashMap, fmt::Debug, hash::Hash};
2
3#[derive(Debug)]
4pub struct BusLocalHub<Owner, ChannelId: Hash + PartialEq + Eq> {
5    channels: HashMap<ChannelId, Vec<Owner>>,
6}
7
8impl<Owner, ChannelId: Hash + PartialEq + Eq> Default for BusLocalHub<Owner, ChannelId> {
9    fn default() -> Self {
10        Self {
11            channels: HashMap::new(),
12        }
13    }
14}
15
16impl<Owner: Clone + Debug + PartialEq, ChannelId: Debug + Clone + Copy + Hash + PartialEq + Eq>
17    BusLocalHub<Owner, ChannelId>
18{
19    /// subscribe to a channel. if it is first time subscription, return true; else return false
20    pub fn subscribe(&mut self, owner: Owner, channel: ChannelId) -> bool {
21        let entry = self.channels.entry(channel).or_default();
22        if entry.contains(&owner) {
23            false
24        } else {
25            entry.push(owner);
26            entry.len() == 1
27        }
28    }
29
30    /// unsubscribe from a channel. if it is last time unsubscription, return true; else return false
31    pub fn unsubscribe(&mut self, owner: Owner, channel: ChannelId) -> bool {
32        log::info!("channels: {:?}", self.channels);
33        if let Some(entry) = self.channels.get_mut(&channel) {
34            log::info!("remove owner {:?} with list {:?}", owner, entry);
35            if let Some(pos) = entry.iter().position(|x| *x == owner) {
36                log::info!("remove owner {:?}", owner);
37                entry.swap_remove(pos);
38                if entry.is_empty() {
39                    self.channels.remove(&channel);
40                    true
41                } else {
42                    false
43                }
44            } else {
45                false
46            }
47        } else {
48            false
49        }
50    }
51
52    /// get all subscribers of a channel
53    pub fn get_subscribers(&self, channel: ChannelId) -> Option<Vec<Owner>> {
54        self.channels.get(&channel).cloned()
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use crate::group_owner_type;
61
62    use super::*;
63
64    group_owner_type!(DemoOwner);
65
66    #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
67    enum Channel {
68        A,
69        B,
70        C,
71    }
72
73    #[test]
74    fn test_subscribe_unsubscribe() {
75        let mut hub: BusLocalHub<DemoOwner, Channel> = BusLocalHub::default();
76        let owner1 = DemoOwner(1);
77        let owner2 = DemoOwner(2);
78
79        assert_eq!(hub.subscribe(owner1, Channel::A), true);
80        assert_eq!(hub.subscribe(owner2, Channel::A), false);
81        assert_eq!(hub.subscribe(owner1, Channel::B), true);
82        assert_eq!(hub.subscribe(owner1, Channel::C), true);
83
84        assert_eq!(hub.unsubscribe(owner1, Channel::A), false);
85        assert_eq!(hub.unsubscribe(owner2, Channel::A), true);
86        assert_eq!(hub.unsubscribe(owner1, Channel::B), true);
87        assert_eq!(hub.unsubscribe(owner1, Channel::C), true);
88    }
89
90    #[test]
91    fn test_get_subscribers() {
92        let mut hub: BusLocalHub<DemoOwner, Channel> = BusLocalHub::default();
93        let owner1 = DemoOwner(1);
94        let owner2 = DemoOwner(2);
95
96        hub.subscribe(owner1, Channel::A);
97        hub.subscribe(owner1, Channel::B);
98        hub.subscribe(owner2, Channel::A);
99
100        assert_eq!(hub.get_subscribers(Channel::A), Some(vec![owner1, owner2]));
101        assert_eq!(hub.get_subscribers(Channel::B), Some(vec![owner1]));
102        assert_eq!(hub.get_subscribers(Channel::C), None);
103    }
104}