Skip to main content

bitwarden_sync/
registry.rs

1//! Generic handler registry providing thread-safe handler storage.
2//!
3//! This module provides [`HandlerRegistry`], a reusable building block for
4//! storing and iterating over trait object handlers behind `Arc`.
5//!
6//! # Architecture
7//!
8//! The registry uses interior mutability via `RwLock` to allow
9//! handler registration without requiring mutable access. This enables
10//! sharing the registry across async boundaries and multiple components.
11//!
12//! # Execution Model
13//!
14//! Handlers are stored in registration order. The registry itself does not
15//! define execution semantics — callers iterate over handlers and decide
16//! how to dispatch them (fail-fast, best-effort, etc.).
17
18use std::sync::{Arc, RwLock};
19
20/// A thread-safe, ordered collection of handlers.
21///
22/// Supports registration via interior mutability and snapshot-based iteration.
23/// The type parameter `H` is typically a `dyn Trait` for trait object storage.
24///
25/// # Example
26///
27/// ```ignore
28/// let registry = HandlerRegistry::<dyn MyHandler>::new();
29/// registry.register(Arc::new(MyHandlerImpl));
30///
31/// for handler in &registry.handlers() {
32///     handler.handle();
33/// }
34/// ```
35pub(crate) struct HandlerRegistry<H: ?Sized> {
36    handlers: RwLock<Vec<Arc<H>>>,
37}
38
39impl<H: ?Sized> HandlerRegistry<H> {
40    /// Create a new empty handler registry.
41    pub fn new() -> Self {
42        Self {
43            handlers: RwLock::new(Vec::new()),
44        }
45    }
46
47    /// Register a new handler.
48    ///
49    /// Handlers are stored in registration order.
50    pub fn register(&self, handler: Arc<H>) {
51        self.handlers
52            .write()
53            .expect("Handler registry lock poisoned")
54            .push(handler);
55    }
56
57    /// Get a snapshot of all registered handlers.
58    ///
59    /// Returns a cloned `Vec` so that iteration does not hold the lock.
60    pub fn handlers(&self) -> Vec<Arc<H>> {
61        self.handlers
62            .read()
63            .expect("Handler registry lock poisoned")
64            .clone()
65    }
66}
67
68impl<H: ?Sized> Default for HandlerRegistry<H> {
69    fn default() -> Self {
70        Self::new()
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77
78    trait TestTrait: Send + Sync {
79        fn name(&self) -> &str;
80    }
81
82    struct Named(String);
83
84    impl TestTrait for Named {
85        fn name(&self) -> &str {
86            &self.0
87        }
88    }
89
90    #[test]
91    fn test_register_and_retrieve_handlers() {
92        let registry = HandlerRegistry::<dyn TestTrait>::new();
93        registry.register(Arc::new(Named("a".into())));
94        registry.register(Arc::new(Named("b".into())));
95
96        let handlers = registry.handlers();
97        assert_eq!(handlers.len(), 2);
98        assert_eq!(handlers[0].name(), "a");
99        assert_eq!(handlers[1].name(), "b");
100    }
101
102    #[test]
103    fn test_empty_registry_returns_empty_vec() {
104        let registry = HandlerRegistry::<dyn TestTrait>::new();
105        assert!(registry.handlers().is_empty());
106    }
107
108    #[test]
109    fn test_default_creates_empty_registry() {
110        let registry = HandlerRegistry::<dyn TestTrait>::default();
111        assert!(registry.handlers().is_empty());
112    }
113}