use crate::{
entry::{Entry, EntryId},
event::{Event, EventObserver},
registry::{Registry, RegistryReadGuard, RegistryWriteGuard},
};
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum TracedRegistryEvent {
Register,
UnRegister,
}
pub struct TracedRegistry<T>
where
T: Send + Sync + Clone + 'static,
{
registry: Registry<T>,
event: Event<(TracedRegistryEvent, EntryId, T)>,
}
impl<T> Clone for TracedRegistry<T>
where
T: Send + Clone + Sync,
{
fn clone(&self) -> Self {
Self {
registry: self.registry.clone(),
event: self.event.clone(),
}
}
}
impl<T> Default for TracedRegistry<T>
where
T: Send + Sync + Clone + 'static,
{
fn default() -> Self {
Self::new()
}
}
impl<T> TracedRegistry<T>
where
T: Send + Sync + Clone + 'static,
{
pub fn new() -> Self {
let registry = Registry::new();
let event = Event::new();
let event2 = event.clone();
registry.set_remove_callback(move |entry_id, value| {
event2.dispatch((TracedRegistryEvent::UnRegister, entry_id, value));
});
Self { registry, event }
}
#[must_use = "Entry will be immediately revoked if not used"]
pub fn register(&self, value: T) -> Entry<T> {
let entry = self.registry.register(value.clone());
self.event
.dispatch((TracedRegistryEvent::Register, entry.get_id(), value));
entry
}
#[must_use = "Entry will be immediately revoked if not used"]
pub fn register_observer<O>(&self, observer: O) -> Entry
where
O: EventObserver<(TracedRegistryEvent, EntryId, T)> + 'static,
{
self.event.register_observer(observer)
}
pub fn len(&self) -> usize {
self.registry.len()
}
pub fn is_empty(&self) -> bool {
self.registry.is_empty()
}
pub fn read(&self) -> RegistryReadGuard<'_, T> {
self.registry.read()
}
pub fn write(&self) -> RegistryWriteGuard<'_, T> {
self.registry.write()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
#[test]
fn test_attributes() {
fn is_send_sync<T: Send + Sync>() {}
fn is_clone<T: Clone>() {}
is_send_sync::<TracedRegistry<i32>>();
is_clone::<TracedRegistry<i32>>();
}
#[derive(Debug, PartialEq, Clone)]
struct TestData {
value: i32,
}
#[test]
fn test_register_and_notify_multiple_observers() {
let registry = TracedRegistry::new();
let counter1 = Arc::new(AtomicUsize::new(0));
let counter2 = Arc::new(AtomicUsize::new(0));
let counter1_clone = Arc::clone(&counter1);
let counter2_clone = Arc::clone(&counter2);
let observer_function1 = move |_: &_| {
counter1_clone.fetch_add(1, Ordering::Relaxed);
};
let observer_function2 = move |_: &_| {
counter2_clone.fetch_add(1, Ordering::Relaxed);
};
let _entry1 = registry.register_observer(observer_function1);
let _entry2 = registry.register_observer(observer_function2);
let entry = registry.register(TestData { value: 42 });
assert_eq!(counter1.load(Ordering::Relaxed), 1);
assert_eq!(counter2.load(Ordering::Relaxed), 1);
drop(entry);
assert_eq!(counter1.load(Ordering::Relaxed), 2);
assert_eq!(counter2.load(Ordering::Relaxed), 2);
}
}