use crate::reason::ShutdownReason;
pub trait ShutdownHook: Send + Sync + 'static {
fn name(&self) -> &str;
fn priority(&self) -> i32 {
0
}
fn run(&self, reason: ShutdownReason);
}
pub struct FnHook<F>
where
F: Fn(ShutdownReason) + Send + Sync + 'static,
{
name: String,
priority: i32,
f: F,
}
impl<F> FnHook<F>
where
F: Fn(ShutdownReason) + Send + Sync + 'static,
{
pub fn new(name: impl Into<String>, priority: i32, f: F) -> Self {
Self {
name: name.into(),
priority,
f,
}
}
}
impl<F> ShutdownHook for FnHook<F>
where
F: Fn(ShutdownReason) + Send + Sync + 'static,
{
fn name(&self) -> &str {
&self.name
}
fn priority(&self) -> i32 {
self.priority
}
fn run(&self, reason: ShutdownReason) {
(self.f)(reason);
}
}
pub fn hook_from_fn<F>(name: impl Into<String>, priority: i32, f: F) -> FnHook<F>
where
F: Fn(ShutdownReason) + Send + Sync + 'static,
{
FnHook::new(name, priority, f)
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
#[test]
fn fn_hook_records_invocations() {
let counter = Arc::new(AtomicUsize::new(0));
let c = Arc::clone(&counter);
let hook = hook_from_fn("bump", 0, move |_| {
c.fetch_add(1, Ordering::Relaxed);
});
hook.run(ShutdownReason::Requested);
hook.run(ShutdownReason::Requested);
assert_eq!(counter.load(Ordering::Relaxed), 2);
assert_eq!(hook.name(), "bump");
assert_eq!(hook.priority(), 0);
}
}