Skip to main content

registry_io/sync/
guard.rs

1//! RAII handler guard that unregisters on drop.
2//!
3//! A [`HandlerGuard`] is returned by
4//! [`SyncRegistry::register_guard`](crate::SyncRegistry::register_guard) and
5//! its priority variant. While the guard is alive the handler stays
6//! registered; when the guard is dropped (or goes out of scope) the
7//! corresponding handler is automatically removed.
8//!
9//! The guard holds a [`Weak`] reference to the registry so it does not keep
10//! the registry alive on its own. If the registry is dropped before the
11//! guard, dropping the guard becomes a no-op.
12
13use std::sync::Weak;
14
15use crate::HandlerId;
16
17use super::SyncRegistry;
18
19/// RAII handle for a registered handler.
20///
21/// Drop the guard to unregister. Call [`HandlerGuard::forget`] to detach the
22/// guard from the handler, leaving the handler registered indefinitely.
23///
24/// The guard is not [`Clone`]; ownership of a registration is unique.
25///
26/// # Examples
27///
28/// Automatic cleanup when the guard leaves scope:
29///
30/// ```
31/// use std::sync::Arc;
32/// use registry_io::SyncRegistry;
33///
34/// let registry = Arc::new(SyncRegistry::<u32>::new());
35/// assert_eq!(registry.handler_count(), 0);
36///
37/// {
38///     let _guard = registry.register_guard(|n| {
39///         println!("got {n}");
40///     });
41///     assert_eq!(registry.handler_count(), 1);
42/// }
43///
44/// assert_eq!(registry.handler_count(), 0);
45/// ```
46///
47/// Forgetting the guard to keep the handler registered:
48///
49/// ```
50/// use std::sync::Arc;
51/// use registry_io::SyncRegistry;
52///
53/// let registry = Arc::new(SyncRegistry::<()>::new());
54/// let guard = registry.register_guard(|_| {});
55/// let id = guard.id();
56/// guard.forget();
57/// // Handler is still active.
58/// assert_eq!(registry.handler_count(), 1);
59/// // Manually unregister via the returned id.
60/// assert!(registry.unregister(id));
61/// ```
62#[must_use = "dropping the HandlerGuard immediately unregisters the handler; \
63              bind it to a name to keep the handler alive"]
64pub struct HandlerGuard<E: Send + Sync + 'static> {
65    id: HandlerId,
66    registry: Weak<SyncRegistry<E>>,
67}
68
69impl<E: Send + Sync + 'static> HandlerGuard<E> {
70    /// Internal constructor used by `SyncRegistry`.
71    pub(crate) fn new(id: HandlerId, registry: Weak<SyncRegistry<E>>) -> Self {
72        Self { id, registry }
73    }
74
75    /// Returns the [`HandlerId`] of the underlying registration.
76    ///
77    /// Useful for diagnostic logging or to retain the id before consuming
78    /// the guard with [`HandlerGuard::forget`].
79    ///
80    /// # Examples
81    ///
82    /// ```
83    /// use std::sync::Arc;
84    /// use registry_io::SyncRegistry;
85    ///
86    /// let registry = Arc::new(SyncRegistry::<()>::new());
87    /// let guard = registry.register_guard(|_| {});
88    /// let id = guard.id();
89    /// drop(guard);
90    /// // The id is still meaningful for logging, but the handler is gone:
91    /// assert!(!registry.contains(id));
92    /// ```
93    #[inline]
94    #[must_use]
95    pub fn id(&self) -> HandlerId {
96        self.id
97    }
98
99    /// Consume the guard without unregistering the handler.
100    ///
101    /// The handler remains registered until it is explicitly removed via
102    /// [`SyncRegistry::unregister`](crate::SyncRegistry::unregister) or the
103    /// registry is dropped.
104    ///
105    /// # Examples
106    ///
107    /// ```
108    /// use std::sync::Arc;
109    /// use registry_io::SyncRegistry;
110    ///
111    /// let registry = Arc::new(SyncRegistry::<()>::new());
112    /// let guard = registry.register_guard(|_| {});
113    /// guard.forget();
114    /// assert_eq!(registry.handler_count(), 1);
115    /// ```
116    pub fn forget(self) {
117        let mut me = std::mem::ManuallyDrop::new(self);
118        // Replace the weak ref with a sentinel that points to nothing so a
119        // future `Drop` (impossible after ManuallyDrop, but defensive)
120        // would do nothing.
121        me.registry = Weak::new();
122    }
123}
124
125impl<E: Send + Sync + 'static> Drop for HandlerGuard<E> {
126    fn drop(&mut self) {
127        if let Some(registry) = self.registry.upgrade() {
128            let _ = registry.unregister(self.id);
129        }
130    }
131}
132
133impl<E: Send + Sync + 'static> core::fmt::Debug for HandlerGuard<E> {
134    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
135        f.debug_struct("HandlerGuard")
136            .field("id", &self.id)
137            .field("registry_alive", &(self.registry.strong_count() > 0))
138            .finish()
139    }
140}