use std::collections::BTreeSet;
use std::sync::{Mutex, OnceLock};
static ACTIVE: OnceLock<Mutex<BTreeSet<String>>> = OnceLock::new();
fn active() -> &'static Mutex<BTreeSet<String>> {
ACTIVE.get_or_init(|| Mutex::new(BTreeSet::new()))
}
pub fn add(uri: &str) -> bool {
active().lock().unwrap().insert(uri.to_string())
}
pub fn remove(uri: &str) -> bool {
active().lock().unwrap().remove(uri)
}
pub fn list() -> Vec<String> {
active().lock().unwrap().iter().cloned().collect()
}
pub fn contains(uri: &str) -> bool {
active().lock().unwrap().contains(uri)
}
pub fn server_supports(capabilities: &serde_json::Value) -> bool {
capabilities
.pointer("/resources/subscribe")
.and_then(|v| v.as_bool())
.unwrap_or(false)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn subscriptions_are_tracked_deduplicated_and_ordered() {
assert!(add("note://b"));
assert!(add("note://a"));
assert!(!add("note://a"));
assert!(contains("note://a"));
assert_eq!(list(), ["note://a", "note://b"]);
assert!(remove("note://a"));
assert!(!remove("note://a"));
assert!(!contains("note://a"));
assert_eq!(list(), ["note://b"]);
remove("note://b");
assert!(list().is_empty());
}
#[test]
fn capability_is_read_from_the_initialize_result() {
let yes = serde_json::json!({ "resources": { "subscribe": true } });
let no = serde_json::json!({ "resources": { "listChanged": true } });
assert!(server_supports(&yes));
assert!(!server_supports(&no));
assert!(!server_supports(&serde_json::json!({ "tools": {} })));
}
}