use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use parking_lot::{Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
use super::scanner::ScanOptions;
static LANE: Mutex<()> = Mutex::new(());
static IMPORTS: RwLock<()> = RwLock::new(());
static RUNNING: Mutex<Option<Running>> = Mutex::new(None);
struct Running {
roots: Vec<PathBuf>,
cancel: Arc<AtomicBool>,
}
pub(crate) struct Turn {
_lane: MutexGuard<'static, ()>,
}
impl Drop for Turn {
fn drop(&mut self) {
*RUNNING.lock() = None;
}
}
pub(crate) fn enter(roots: &[PathBuf], opts: &mut ScanOptions) -> Turn {
let lane = LANE.lock();
let cancel = opts
.cancel
.get_or_insert_with(|| Arc::new(AtomicBool::new(false)))
.clone();
*RUNNING.lock() = Some(Running {
roots: roots.to_vec(),
cancel,
});
Turn { _lane: lane }
}
pub(crate) struct Quiet {
_lane: MutexGuard<'static, ()>,
_imports: RwLockWriteGuard<'static, ()>,
}
pub(crate) fn wait() -> Quiet {
let lane = LANE.lock();
Quiet {
_lane: lane,
_imports: IMPORTS.write(),
}
}
pub(crate) fn importing() -> RwLockReadGuard<'static, ()> {
IMPORTS.read()
}
pub fn cancel_all() {
if let Some(running) = RUNNING.lock().as_ref() {
running.cancel.store(true, Ordering::Relaxed);
}
}
pub fn cancel_under(path: &Path) {
if let Some(running) = RUNNING.lock().as_ref()
&& running
.roots
.iter()
.any(|root| root.starts_with(path) || path.starts_with(root))
{
running.cancel.store(true, Ordering::Relaxed);
}
}