use std::sync::{Arc, Mutex, Weak};
use crossbeam_queue::SegQueue;
use super::slot::SlotMessage;
pub struct BroadcastSlotHandle<M, K>
where
M: Send + Sync + Clone + 'static,
K: Send + Sync + Clone + 'static,
{
inner: Arc<BroadcastInner<M, K>>,
my_queue: SubscriberQueue<M, K>,
parser_kind: &'static str,
}
pub(crate) type SubscriberQueue<M, K> = Arc<SegQueue<SlotMessage<M, K>>>;
pub(crate) type SubscriberWeak<M, K> = Weak<SegQueue<SlotMessage<M, K>>>;
pub(crate) struct BroadcastInner<M, K>
where
M: Send + Sync + Clone + 'static,
K: Send + Sync + Clone + 'static,
{
pub(crate) subscribers: Mutex<Vec<SubscriberWeak<M, K>>>,
}
impl<M, K> BroadcastInner<M, K>
where
M: Send + Sync + Clone + 'static,
K: Send + Sync + Clone + 'static,
{
pub(crate) fn new() -> Arc<Self> {
Arc::new(Self {
subscribers: Mutex::new(Vec::new()),
})
}
pub(crate) fn push(&self, msg: SlotMessage<M, K>) {
let mut subs = self.subscribers.lock().expect("broadcast lock poisoned");
subs.retain(|w| {
if let Some(q) = w.upgrade() {
q.push(msg.clone());
true
} else {
false
}
});
}
pub(crate) fn subscribe(self: &Arc<Self>) -> SubscriberQueue<M, K> {
let q = Arc::new(SegQueue::new());
self.subscribers
.lock()
.expect("broadcast lock poisoned")
.push(Arc::downgrade(&q));
q
}
}
impl<M, K> BroadcastSlotHandle<M, K>
where
M: Send + Sync + Clone + 'static,
K: Send + Sync + Clone + 'static,
{
pub(crate) fn new(inner: Arc<BroadcastInner<M, K>>, parser_kind: &'static str) -> Self {
let my_queue = inner.subscribe();
Self {
inner,
my_queue,
parser_kind,
}
}
pub fn drain(&mut self, out: &mut Vec<SlotMessage<M, K>>) -> usize {
let mut n = 0;
while let Some(msg) = self.my_queue.pop() {
out.push(msg);
n += 1;
}
n
}
pub fn drain_n(&mut self, out: &mut Vec<SlotMessage<M, K>>, max: usize) -> usize {
let mut n = 0;
while n < max
&& let Some(msg) = self.my_queue.pop()
{
out.push(msg);
n += 1;
}
n
}
pub fn pending(&self) -> usize {
self.my_queue.len()
}
pub fn subscribers(&self) -> usize {
self.inner
.subscribers
.lock()
.map(|s| s.iter().filter(|w| w.strong_count() > 0).count())
.unwrap_or(0)
}
pub fn parser_kind(&self) -> &'static str {
self.parser_kind
}
}
impl<M, K> Clone for BroadcastSlotHandle<M, K>
where
M: Send + Sync + Clone + 'static,
K: Send + Sync + Clone + 'static,
{
fn clone(&self) -> Self {
Self::new(Arc::clone(&self.inner), self.parser_kind)
}
}
impl<M, K> std::fmt::Debug for BroadcastSlotHandle<M, K>
where
M: Send + Sync + Clone + 'static,
K: Send + Sync + Clone + 'static,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BroadcastSlotHandle")
.field("parser_kind", &self.parser_kind)
.field("pending", &self.pending())
.field("subscribers", &self.subscribers())
.finish()
}
}