use std::sync::atomic::AtomicBool;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use std::sync::OnceLock;
type BackListener = Box<dyn Fn() + Send + Sync + 'static>;
static BACK_REQUESTS: AtomicUsize = AtomicUsize::new(0);
static BACK_INTERCEPTION: AtomicBool = AtomicBool::new(false);
static BACK_LISTENER: OnceLock<BackListener> = OnceLock::new();
pub fn push_back_request() {
BACK_REQUESTS.fetch_add(1, Ordering::SeqCst);
if let Some(listener) = BACK_LISTENER.get() {
listener();
}
}
pub fn set_back_request_listener(listener: impl Fn() + Send + Sync + 'static) {
let _ = BACK_LISTENER.set(Box::new(listener));
}
pub fn take_back_requests() -> usize {
BACK_REQUESTS.swap(0, Ordering::SeqCst)
}
pub fn set_back_interception(enabled: bool) {
BACK_INTERCEPTION.store(enabled, Ordering::SeqCst);
}
pub fn back_interception_enabled() -> bool {
BACK_INTERCEPTION.load(Ordering::SeqCst)
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
#[test]
fn requests_accumulate_and_drain() {
let _ = take_back_requests(); push_back_request();
push_back_request();
assert_eq!(take_back_requests(), 2);
assert_eq!(take_back_requests(), 0);
}
#[test]
fn a_registered_listener_hears_every_request() {
let heard = Arc::new(AtomicUsize::new(0));
let counter = Arc::clone(&heard);
set_back_request_listener(move || {
counter.fetch_add(1, Ordering::SeqCst);
});
let before = heard.load(Ordering::SeqCst);
push_back_request();
push_back_request();
assert_eq!(heard.load(Ordering::SeqCst), before + 2);
let _ = take_back_requests();
}
#[test]
fn interception_defaults_off_and_toggles() {
set_back_interception(false);
assert!(!back_interception_enabled());
set_back_interception(true);
assert!(back_interception_enabled());
set_back_interception(false);
}
}