//! Advisory lock acquisition and guard lifetime. use super::*; /// An advisory lock acquisition. #[must_use = "await the lock to acquire it"] pub struct Lock { path: String, wait: bool, } /// Acquire an advisory lock on a path. pub fn lock(path: impl AsRef) -> Lock { Lock { path: path.as_ref().to_string_lossy().into_owned(), wait: true, } } impl Lock { /// Return immediately, without waiting for a held lock. pub fn try_now(mut self) -> Self { self.wait = false; self } } /// Releases its lock on drop, unless kept until process exit. #[must_use = "bind the guard to hold the lock"] pub struct Guard { path: Option, } impl Guard { /// Hold this lock until process exit. pub fn keep(mut self) { self.path.take(); } /// Report whether this guard holds the lock. pub fn held(&self) -> bool { self.path.is_some() } } impl Drop for Guard { fn drop(&mut self) { if let Some(path) = self.path.take() { let _ = notify("core.unlock", json!({"path":path})); } } } impl IntoFuture for Lock { type Output = Result; type IntoFuture = LocalBoxFuture<'static, Self::Output>; fn into_future(self) -> Self::IntoFuture { Box::pin(async move { let lease = std::rc::Rc::new(Lease { path: self.path.clone(), held: std::cell::Cell::new(false), }); let mut c = call("core.lock", json!({"path":self.path,"wait":self.wait})); c.unlock = Some(lease.clone()); let result = c.await?; lease.held.set(false); Ok(Guard { path: if result["held"] == true { Some(self.path) } else { None }, }) }) } }