pub struct Connections<T> {
entries: Vec<(u32, T)>,
next: u32,
}
impl<T> Default for Connections<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> Connections<T> {
pub const fn new() -> Self {
Self {
entries: Vec::new(),
next: 1,
}
}
pub fn advise(&mut self, sink: T) -> u32 {
let cookie = self.next;
self.next += 1;
self.entries.push((cookie, sink));
cookie
}
pub fn unadvise(&mut self, cookie: u32) -> bool {
let before = self.entries.len();
self.entries.retain(|(held, _)| *held != cookie);
self.entries.len() != before
}
pub fn clear(&mut self) {
self.entries.clear();
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}
impl<T: Clone> Connections<T> {
pub fn sinks(&self) -> Vec<T> {
self.entries.iter().map(|(_, sink)| sink.clone()).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cookies_start_at_one_and_zero_matches_nothing() {
let mut connections = Connections::new();
assert_eq!(connections.advise("a"), 1);
assert_eq!(connections.advise("b"), 2);
assert!(!connections.unadvise(0));
assert_eq!(connections.len(), 2);
}
#[test]
fn a_cookie_is_never_handed_out_twice() {
let mut connections = Connections::new();
let first = connections.advise("a");
connections.advise("b");
assert!(connections.unadvise(first));
let third = connections.advise("c");
assert_ne!(third, first);
assert!(
!connections.unadvise(first),
"the stale cookie still matches"
);
assert_eq!(connections.sinks(), vec!["b", "c"]);
}
#[test]
fn unadvising_twice_is_reported_the_second_time() {
let mut connections = Connections::new();
let cookie = connections.advise("a");
assert!(connections.unadvise(cookie));
assert!(!connections.unadvise(cookie));
assert!(connections.is_empty());
}
#[test]
fn clearing_drops_every_sink() {
let mut connections = Connections::new();
connections.advise("a");
connections.advise("b");
connections.clear();
assert!(connections.is_empty());
assert!(connections.sinks().is_empty());
}
}