diff --git a/crates/nu-protocol/src/engine/ctrlc.rs b/crates/nu-protocol/src/engine/ctrlc.rs index e9275f6029..3d48495373 100644 --- a/crates/nu-protocol/src/engine/ctrlc.rs +++ b/crates/nu-protocol/src/engine/ctrlc.rs @@ -3,11 +3,15 @@ use std::sync::{Arc, Mutex}; use crate::{engine::Sequence, ShellError}; +/// Handler is a closure that can be sent across threads and shared. pub type Handler = Box; +/// Manages a collection of handlers. #[derive(Clone)] pub struct Handlers { + /// List of handler tuples containing an ID and the handler itself. handlers: Arc>>, + /// Sequence generator for unique IDs. next_id: Arc, } @@ -19,13 +23,17 @@ impl Debug for Handlers { } } +/// Guard that unregisters a handler when dropped. #[derive(Clone)] pub struct Guard { + /// Unique ID of the handler. id: usize, + /// Reference to the handlers list. handlers: Arc>>, } impl Drop for Guard { + /// Drops the `Guard`, removing the associated handler from the list. fn drop(&mut self) { if let Ok(mut handlers) = self.handlers.lock() { handlers.retain(|(id, _)| *id != self.id); @@ -46,6 +54,8 @@ impl Handlers { Handlers { handlers, next_id } } + /// Registers a new handler and returns an RAII guard which will unregister the handler when + /// dropped. pub fn register(&self, handler: Handler) -> Result { let id = self.next_id.next()?; if let Ok(mut handlers) = self.handlers.lock() { @@ -57,6 +67,7 @@ impl Handlers { }) } + /// Runs all registered handlers. pub fn run(&self) { if let Ok(handlers) = self.handlers.lock() { for (_, handler) in handlers.iter() { @@ -78,6 +89,7 @@ mod tests { use std::sync::atomic::{AtomicBool, Ordering}; #[test] + /// Tests registering and running multiple handlers. fn test_multiple_handlers() { let handlers = Handlers::new(); let called1 = Arc::new(AtomicBool::new(false)); @@ -100,6 +112,7 @@ mod tests { } #[test] + /// Tests the dropping of a guard and ensuring the handler is unregistered. fn test_guard_drop() { let handlers = Handlers::new(); let called = Arc::new(AtomicBool::new(false));