use std::collections::HashMap;
use std::sync::Arc;
use crate::sink::SmallSinkVec;
use crate::{ChannelId, Sink, SinkId};
#[cfg(test)]
mod tests;
#[derive(Default)]
pub(crate) struct Subscriptions {
global: HashMap<SinkId, Arc<dyn Sink>>,
by_channel: HashMap<ChannelId, HashMap<SinkId, Arc<dyn Sink>>>,
}
impl Subscriptions {
pub fn clear(&mut self) {
self.global.clear();
self.by_channel.clear();
}
pub fn subscribe_global(&mut self, sink: Arc<dyn Sink>) -> bool {
let sink_id = sink.id();
if self.global.insert(sink_id, sink).is_none() {
self.by_channel.retain(|_, subs| {
subs.remove(&sink_id);
!subs.is_empty()
});
true
} else {
false
}
}
pub fn subscribe_channels(&mut self, sink: &Arc<dyn Sink>, channel_ids: &[ChannelId]) -> bool {
let sink_id = sink.id();
if self.global.contains_key(&sink_id) {
return false;
}
let mut inserted = false;
for &channel_id in channel_ids {
inserted |= self
.by_channel
.entry(channel_id)
.or_default()
.insert(sink_id, sink.clone())
.is_none();
}
inserted
}
pub fn unsubscribe_channels(&mut self, sink_id: SinkId, channel_ids: &[ChannelId]) -> bool {
let mut removed = false;
for &channel_id in channel_ids {
if let Some(subs) = self.by_channel.get_mut(&channel_id) {
if subs.remove(&sink_id).is_some() {
removed = true;
if subs.is_empty() {
self.by_channel.remove(&channel_id);
}
}
}
}
removed
}
pub fn remove_channel_subscriptions(&mut self, channel_id: ChannelId) -> bool {
self.by_channel.remove(&channel_id).is_some()
}
pub fn remove_subscriber(&mut self, sink_id: SinkId) -> bool {
if self.global.remove(&sink_id).is_some() {
true
} else {
let mut removed = false;
self.by_channel.retain(|_, subs| {
removed |= subs.remove(&sink_id).is_some();
!subs.is_empty()
});
removed
}
}
pub fn get_subscribers(&self, channel_id: ChannelId) -> SmallSinkVec {
let mut result: SmallSinkVec = self.global.values().cloned().collect();
if let Some(subs) = self.by_channel.get(&channel_id) {
result.extend(subs.values().cloned());
}
result
}
}