use service_channel::oneshot;
use std::collections::BTreeMap;
pub trait Topic: Ord + Clone + Send + 'static {
type Item: Clone + Send + 'static;
}
pub trait RoutedTopic<S>: Topic
where
S: crate::Service,
{
fn endpoint(service: &mut S) -> &mut TopicEndpoint<Self>
where
Self: Sized;
}
pub struct TopicEndpoint<T>
where
T: Topic,
{
waiters: BTreeMap<T, Vec<oneshot::Sender<T::Item>>>,
}
impl<T> Default for TopicEndpoint<T>
where
T: Topic,
{
fn default() -> Self {
Self {
waiters: BTreeMap::new(),
}
}
}
impl<T> TopicEndpoint<T>
where
T: Topic,
{
pub fn subscribe(&mut self, topic: T, tx: oneshot::Sender<T::Item>) {
self.waiters.entry(topic).or_default().push(tx);
}
pub fn publish(&mut self, topic: &T, item: T::Item) {
let waiters = self.waiters.remove(topic).unwrap_or_default();
for tx in waiters {
let _ = tx.send(item.clone());
}
}
pub fn topic_len(&self) -> usize {
self.waiters.len()
}
pub fn len(&self, topic: &T) -> usize {
self.waiters.get(topic).map_or(0, Vec::len)
}
pub fn is_empty(&self) -> bool {
self.waiters.is_empty()
}
pub fn is_topic_empty(&self, topic: &T) -> bool {
self.waiters.get(topic).is_none_or(Vec::is_empty)
}
pub fn clear(&mut self) {
self.waiters.clear();
}
pub fn clear_topic(&mut self, topic: &T) {
self.waiters.remove(topic);
}
}