use crate::eval::Value;
use crate::diagnostics::{Error, Result};
use std::sync::Arc;
use tokio::sync::{RwLock as AsyncRwLock};
#[derive(Debug, Clone)]
pub struct RwLock {
inner: Arc<AsyncRwLock<Value>>,
name: Option<String>,
}
impl RwLock {
pub fn new(value: Value) -> Self {
Self {
inner: Arc::new(AsyncRwLock::new(value)),
name: None,
}
}
pub fn with_name(value: Value, name: String) -> Self {
Self {
inner: Arc::new(AsyncRwLock::new(value)),
name: Some(name),
}
}
pub async fn read(&self) -> ReadGuard<'_> {
let guard = self.inner.read().await;
ReadGuard { guard }
}
pub async fn write(&self) -> WriteGuard<'_> {
let guard = self.inner.write().await;
WriteGuard { guard }
}
pub fn try_read(&self) -> Result<ReadGuard<'_>> {
match self.inner.try_read() {
Ok(guard) => Ok(ReadGuard { guard }),
Err(_) => Err(Box::new(Error::runtime_error("RwLock is write-locked".to_string(), None))),
}
}
pub fn try_write(&self) -> Result<WriteGuard<'_>> {
match self.inner.try_write() {
Ok(guard) => Ok(WriteGuard { guard }),
Err(_) => Err(Box::new(Error::runtime_error("RwLock is locked".to_string(), None))),
}
}
pub fn name(&self) -> Option<&str> {
self.name.as_deref()
}
}
pub struct ReadGuard<'a> {
guard: tokio::sync::RwLockReadGuard<'a, Value>,
}
impl<'a> ReadGuard<'a> {
pub fn get(&self) -> &Value {
&self.guard
}
}
pub struct WriteGuard<'a> {
guard: tokio::sync::RwLockWriteGuard<'a, Value>,
}
impl<'a> WriteGuard<'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;
}
}