use std::sync::{
Arc, Mutex, OnceLock,
atomic::{AtomicUsize, Ordering},
};
pub trait BackgroundActivity: Send + Sync {
fn set_active(&self, active: bool);
}
pub type BackgroundActivityRef = Arc<dyn BackgroundActivity>;
fn slot() -> &'static Mutex<Option<BackgroundActivityRef>> {
static SLOT: OnceLock<Mutex<Option<BackgroundActivityRef>>> = OnceLock::new();
SLOT.get_or_init(|| Mutex::new(None))
}
pub fn set_platform_background_activity(activity: BackgroundActivityRef) {
if background_active() {
activity.set_active(true);
}
if let Ok(mut s) = slot().lock() {
*s = Some(activity);
}
}
pub fn clear_platform_background_activity() {
if let Ok(mut s) = slot().lock() {
*s = None;
}
}
pub fn background_activity() -> Option<BackgroundActivityRef> {
slot().lock().ok().and_then(|s| s.clone())
}
static ACTIVE_LEASES: AtomicUsize = AtomicUsize::new(0);
pub struct BackgroundWorkLease {
active: bool,
}
impl Drop for BackgroundWorkLease {
fn drop(&mut self) {
if !self.active {
return;
}
self.active = false;
if ACTIVE_LEASES.fetch_sub(1, Ordering::AcqRel) == 1
&& let Some(activity) = background_activity()
{
activity.set_active(false);
}
}
}
pub fn acquire_background_work() -> BackgroundWorkLease {
if ACTIVE_LEASES.fetch_add(1, Ordering::AcqRel) == 0
&& let Some(activity) = background_activity()
{
activity.set_active(true);
}
BackgroundWorkLease { active: true }
}
pub fn background_active() -> bool {
ACTIVE_LEASES.load(Ordering::Acquire) != 0
}
#[cfg(test)]
#[path = "tests/background_tests.rs"]
mod tests;