submap/
broadcastmap.rs

1use std::str::Split;
2
3#[allow(clippy::wildcard_imports)]
4use crate::types::*;
5
6#[derive(Debug, Clone)]
7struct Broadcast<C> {
8    childs: Map<String, Broadcast<C>>,
9    childs_any: Option<Box<Broadcast<C>>>,
10    members: Set<C>,
11    members_wildcard: Set<C>,
12}
13
14impl<C> Broadcast<C> {
15    #[inline]
16    fn is_empty(&self) -> bool {
17        self.childs.is_empty() && self.members.is_empty()
18    }
19}
20
21impl<C> Default for Broadcast<C> {
22    fn default() -> Self {
23        Self {
24            childs: <_>::default(),
25            childs_any: <_>::default(),
26            members: <_>::default(),
27            members_wildcard: <_>::default(),
28        }
29    }
30}
31
32#[derive(Debug, Clone)]
33pub struct BroadcastMap<C> {
34    broadcasts: Broadcast<C>,
35    separator: char,
36    match_any: Set<String>,
37    wildcard: Set<String>,
38}
39
40impl<C> Default for BroadcastMap<C> {
41    fn default() -> Self {
42        Self {
43            broadcasts: Broadcast::default(),
44            separator: '.',
45            match_any: vec!["?".to_owned()].into_iter().collect(),
46            wildcard: vec!["*".to_owned()].into_iter().collect(),
47        }
48    }
49}
50
51impl<C> BroadcastMap<C>
52where
53    C: Client,
54{
55    #[inline]
56    pub fn new() -> Self {
57        Self::default()
58    }
59    #[inline]
60    pub fn separator(mut self, separator: char) -> Self {
61        self.separator = separator;
62        self
63    }
64    #[inline]
65    pub fn wildcard(mut self, wildcard: &str) -> Self {
66        self.wildcard = vec![wildcard.to_owned()].into_iter().collect();
67        self
68    }
69    #[inline]
70    pub fn match_any(mut self, match_any: &str) -> Self {
71        self.match_any = vec![match_any.to_owned()].into_iter().collect();
72        self
73    }
74    #[inline]
75    pub fn wildcard_multiple(mut self, wildcard_multiple: &[&str]) -> Self {
76        self.wildcard = wildcard_multiple.iter().map(|&v| v.to_owned()).collect();
77        self
78    }
79    #[inline]
80    pub fn match_any_multiple(mut self, match_any_multiple: &[&str]) -> Self {
81        self.match_any = match_any_multiple.iter().map(|&v| v.to_owned()).collect();
82        self
83    }
84    #[inline]
85    pub fn is_empty(&self) -> bool {
86        self.broadcasts.is_empty()
87    }
88    #[inline]
89    pub fn register_client(&mut self, name: &str, client: &C) {
90        register_broadcast_client_rec(&mut self.broadcasts, name.split(self.separator), client);
91    }
92    #[inline]
93    pub fn unregister_client(&mut self, name: &str, client: &C) {
94        unregister_broadcast_client_rec(&mut self.broadcasts, name.split(self.separator), client);
95    }
96    pub fn get_clients_by_mask(&self, mask: &str) -> Set<C> {
97        let mut result = Set::new();
98        get_broadcast_clients_rec(
99            &self.broadcasts,
100            mask.split(self.separator),
101            &mut result,
102            &self.wildcard,
103            &self.match_any,
104        );
105        result
106    }
107}
108
109fn get_broadcast_clients_rec<C>(
110    broadcast: &Broadcast<C>,
111    mut sp: Split<char>,
112    result: &mut Set<C>,
113    wildcard: &Set<String>,
114    match_any: &Set<String>,
115) where
116    C: Client,
117{
118    if let Some(chunk) = sp.next() {
119        if wildcard.contains(chunk) {
120            result.extend(broadcast.members_wildcard.clone());
121        } else if match_any.contains(chunk) {
122            if let Some(ref child) = broadcast.childs_any {
123                get_broadcast_clients_rec(child, sp, result, wildcard, match_any);
124            }
125        } else if let Some(child) = broadcast.childs.get(chunk) {
126            get_broadcast_clients_rec(child, sp, result, wildcard, match_any);
127        }
128    } else {
129        result.extend(broadcast.members.clone());
130    }
131}
132
133fn register_broadcast_client_rec<C>(broadcast: &mut Broadcast<C>, mut sp: Split<char>, client: &C)
134where
135    C: Client,
136{
137    if let Some(chunk) = sp.next() {
138        broadcast.members_wildcard.insert(client.clone());
139        if let Some(c) = broadcast.childs.get_mut(chunk) {
140            register_broadcast_client_rec(c, sp.clone(), client);
141        } else {
142            let mut child = Broadcast::default();
143            register_broadcast_client_rec(&mut child, sp.clone(), client);
144            broadcast.childs.insert(chunk.to_owned(), child);
145        }
146        if let Some(ref mut c) = broadcast.childs_any {
147            register_broadcast_client_rec(c, sp, client);
148        } else {
149            let mut child = Broadcast::default();
150            register_broadcast_client_rec(&mut child, sp, client);
151            broadcast.childs_any.replace(Box::new(child));
152        }
153    } else {
154        broadcast.members.insert(client.clone());
155    }
156}
157
158fn unregister_broadcast_client_rec<C>(broadcast: &mut Broadcast<C>, mut sp: Split<char>, client: &C)
159where
160    C: Client,
161{
162    if let Some(chunk) = sp.next() {
163        broadcast.members_wildcard.remove(client);
164        if let Some(c) = broadcast.childs.get_mut(chunk) {
165            unregister_broadcast_client_rec(c, sp.clone(), client);
166            if c.is_empty() {
167                broadcast.childs.remove(chunk);
168            }
169        }
170        if let Some(ref mut c) = broadcast.childs_any {
171            unregister_broadcast_client_rec(c, sp, client);
172            if c.is_empty() {
173                broadcast.childs_any = None;
174            }
175        }
176    } else {
177        broadcast.members.remove(client);
178    }
179}
180
181#[cfg(test)]
182mod test {
183    use super::BroadcastMap;
184    #[test]
185    #[allow(clippy::similar_names)]
186    fn test_broadcast() {
187        let mut bmap: BroadcastMap<u32> = BroadcastMap::new().separator('/');
188        let client1: u32 = 1;
189        let client2: u32 = 2;
190        let client3: u32 = 3;
191        let client4: u32 = 4;
192        let client5: u32 = 5;
193        bmap.register_client("this/is/a", &client1);
194        bmap.register_client("this/is/b", &client2);
195        bmap.register_client("this/is", &client3);
196        bmap.register_client("this", &client4);
197        bmap.register_client("that/is/a", &client5);
198        let clients = bmap.get_clients_by_mask("this/is/*");
199        assert!(clients.contains(&client1));
200        assert!(clients.contains(&client2));
201        assert!(!clients.contains(&client3));
202        assert!(!clients.contains(&client4));
203        assert!(!clients.contains(&client5));
204        let clients = bmap.get_clients_by_mask("this/is");
205        assert!(!clients.contains(&client1));
206        assert!(!clients.contains(&client2));
207        assert!(clients.contains(&client3));
208        assert!(!clients.contains(&client4));
209        assert!(!clients.contains(&client5));
210        let clients = bmap.get_clients_by_mask("this");
211        assert!(!clients.contains(&client1));
212        assert!(!clients.contains(&client2));
213        assert!(!clients.contains(&client3));
214        assert!(clients.contains(&client4));
215        assert!(!clients.contains(&client5));
216        let clients = bmap.get_clients_by_mask("this/*");
217        assert!(clients.contains(&client1));
218        assert!(clients.contains(&client2));
219        assert!(clients.contains(&client3));
220        assert!(!clients.contains(&client4));
221        assert!(!clients.contains(&client5));
222        let clients = bmap.get_clients_by_mask("this/is/*");
223        assert!(clients.contains(&client1));
224        assert!(clients.contains(&client2));
225        assert!(!clients.contains(&client3));
226        assert!(!clients.contains(&client4));
227        assert!(!clients.contains(&client5));
228        let clients = bmap.get_clients_by_mask("*");
229        assert!(clients.contains(&client1));
230        assert!(clients.contains(&client2));
231        assert!(clients.contains(&client3));
232        assert!(clients.contains(&client4));
233        assert!(clients.contains(&client5));
234        let clients = bmap.get_clients_by_mask("this/is/a/*");
235        assert!(!clients.contains(&client1));
236        assert!(!clients.contains(&client2));
237        assert!(!clients.contains(&client3));
238        assert!(!clients.contains(&client4));
239        assert!(!clients.contains(&client5));
240        let clients = bmap.get_clients_by_mask("this/is/a/?");
241        assert!(!clients.contains(&client1));
242        assert!(!clients.contains(&client2));
243        assert!(!clients.contains(&client3));
244        assert!(!clients.contains(&client4));
245        assert!(!clients.contains(&client5));
246        let clients = bmap.get_clients_by_mask("this/?/a");
247        assert!(clients.contains(&client1));
248        assert!(!clients.contains(&client2));
249        assert!(!clients.contains(&client3));
250        assert!(!clients.contains(&client4));
251        assert!(!clients.contains(&client5));
252        let clients = bmap.get_clients_by_mask("this/?/?");
253        assert!(clients.contains(&client1));
254        assert!(clients.contains(&client2));
255        assert!(!clients.contains(&client3));
256        assert!(!clients.contains(&client4));
257        assert!(!clients.contains(&client5));
258        let clients = bmap.get_clients_by_mask("?/is/a");
259        assert!(clients.contains(&client1));
260        assert!(!clients.contains(&client2));
261        assert!(!clients.contains(&client3));
262        assert!(!clients.contains(&client4));
263        assert!(clients.contains(&client5));
264        bmap.unregister_client("this/is/a", &client1);
265        bmap.unregister_client("this/is/b", &client2);
266        bmap.unregister_client("this/is", &client3);
267        bmap.unregister_client("this", &client4);
268        bmap.unregister_client("that/is/a", &client5);
269        assert!(bmap.broadcasts.is_empty());
270    }
271}