use std::collections::HashSet;
#[macro_export]
macro_rules! define_topics {
(
$name:ident,
topics = [
$( $variant:ident = $str:literal ),+ $(,)?
] $(,)?
) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum $name {
$( $variant, )+
}
impl $crate::connect::lsp::Topic for $name {
fn name(&self) -> &'static str {
match self {
$( | $name::$variant => $str, )+
}
}
}
impl ::std::fmt::Display for $name {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
f.write_str($crate::connect::lsp::Topic::name(self))
}
}
};
}
pub trait Topic: Copy + Send + Sync + 'static {
fn name(&self) -> &'static str;
}
#[derive(Debug, Clone, Default)]
pub struct Subscriptions {
topics: HashSet<&'static str>,
}
impl Subscriptions {
pub fn new() -> Self {
Self {
topics: HashSet::new(),
}
}
pub fn subscribe(&mut self, topic: impl Topic) {
self.topics.insert(topic.name());
}
pub fn unsubscribe(&mut self, topic: impl Topic) {
self.topics.remove(topic.name());
}
pub fn is_subscribed(&self, topic: impl Topic) -> bool {
self.topics.contains(topic.name())
}
pub fn topics(&self) -> impl Iterator<Item = &'static str> + '_ {
self.topics.iter().copied()
}
pub fn clear(&mut self) {
self.topics.clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum TestTopic {
Alpha,
Beta,
}
impl Topic for TestTopic {
fn name(&self) -> &'static str {
match self {
| TestTopic::Alpha => "alpha",
| TestTopic::Beta => "beta",
}
}
}
impl std::fmt::Display for TestTopic {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.name())
}
}
#[test]
fn topic_display() {
assert_eq!(format!("{}", TestTopic::Alpha), "alpha");
assert_eq!(format!("{}", TestTopic::Beta), "beta");
}
#[test]
fn subscriptions_subscribe_unsubscribe() {
let mut subs = Subscriptions::new();
assert!(!subs.is_subscribed(TestTopic::Alpha));
subs.subscribe(TestTopic::Alpha);
assert!(subs.is_subscribed(TestTopic::Alpha));
subs.unsubscribe(TestTopic::Alpha);
assert!(!subs.is_subscribed(TestTopic::Alpha));
}
#[test]
fn subscriptions_multiple_topics() {
let mut subs = Subscriptions::new();
subs.subscribe(TestTopic::Alpha);
subs.subscribe(TestTopic::Beta);
assert!(subs.is_subscribed(TestTopic::Alpha));
assert!(subs.is_subscribed(TestTopic::Beta));
}
#[test]
fn subscriptions_clear() {
let mut subs = Subscriptions::new();
subs.subscribe(TestTopic::Alpha);
subs.subscribe(TestTopic::Beta);
subs.clear();
assert!(!subs.is_subscribed(TestTopic::Alpha));
assert!(!subs.is_subscribed(TestTopic::Beta));
}
}