use crate::eval::Value;
use crate::diagnostics::{Error, Result};
use super::ConcurrencyError;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::{Mutex as AsyncMutex};
#[derive(Debug, Clone)]
pub struct Mutex {
inner: Arc<AsyncMutex<Value>>,
name: Option<String>,
}
impl Mutex {
pub fn new(value: Value) -> Self {
Self {
inner: Arc::new(AsyncMutex::new(value)),
name: None,
}
}
pub fn with_name(value: Value, name: String) -> Self {
Self {
inner: Arc::new(AsyncMutex::new(value)),
name: Some(name),
}
}
pub async fn lock(&self) -> MutexGuard<'_> {
let guard = self.inner.lock().await;
MutexGuard { guard }
}
pub fn try_lock(&self) -> Result<MutexGuard<'_>> {
match self.inner.try_lock() {
Ok(guard) => Ok(MutexGuard { guard }),
Err(_) => Err(Box::new(Error::runtime_error("Mutex is locked".to_string(), None))),
}
}
pub async fn lock_timeout(&self, duration: Duration) -> Result<MutexGuard<'_>> {
match tokio::time::timeout(duration, self.lock()).await {
Ok(guard) => Ok(guard),
Err(_) => Err(ConcurrencyError::Timeout.into()),
}
}
pub fn name(&self) -> Option<&str> {
self.name.as_deref()
}
}
pub struct MutexGuard<'a> {
guard: tokio::sync::MutexGuard<'a, Value>,
}
impl<'a> MutexGuard<'a> {
pub fn get(&self) -> &Value {
&self.guard
}
pub fn get_mut(&mut self) -> &mut Value {
&mut self.guard
}
pub fn set(&mut self, value: Value) {
*self.guard = value;
}
}