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}