use crate::core::error::{Error, Result};
use std::sync::{Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
#[macro_export]
macro_rules! lock_safe {
($lock:expr, $context:expr) => {
$lock
.lock()
.map_err(|e| $crate::core::error::Error::lock_poisoned(format!("{}: {}", $context, e)))
};
}
#[macro_export]
macro_rules! read_lock_safe {
($lock:expr, $context:expr) => {
$lock
.read()
.map_err(|e| $crate::core::error::Error::lock_poisoned(format!("{}: {}", $context, e)))
};
}
#[macro_export]
macro_rules! write_lock_safe {
($lock:expr, $context:expr) => {
$lock
.write()
.map_err(|e| $crate::core::error::Error::lock_poisoned(format!("{}: {}", $context, e)))
};
}
#[macro_export]
macro_rules! lock_and_clone {
($lock:expr, $context:expr) => {
$lock
.lock()
.map_err(|e| $crate::core::error::Error::lock_poisoned(format!("{}: {}", $context, e)))
.map(|guard| guard.clone())
};
}
pub fn with_write<T, F, R>(lock: &RwLock<T>, context: &str, f: F) -> Result<R>
where
F: FnOnce(&mut T) -> R,
{
let mut guard = lock
.write()
.map_err(|e| Error::lock_poisoned(format!("{}: {}", context, e)))?;
Ok(f(&mut *guard))
}
pub fn with_read<T, F, R>(lock: &RwLock<T>, context: &str, f: F) -> Result<R>
where
F: FnOnce(&T) -> R,
{
let guard = lock
.read()
.map_err(|e| Error::lock_poisoned(format!("{}: {}", context, e)))?;
Ok(f(&*guard))
}
pub fn with_mutex<T, F, R>(lock: &Mutex<T>, context: &str, f: F) -> Result<R>
where
F: FnOnce(&mut T) -> R,
{
let mut guard = lock
.lock()
.map_err(|e| Error::lock_poisoned(format!("{}: {}", context, e)))?;
Ok(f(&mut *guard))
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::{Arc, Mutex, RwLock};
#[test]
fn test_lock_safe_macro() {
let mutex = Arc::new(Mutex::new(42));
let result = lock_safe!(mutex, "test context");
assert!(result.is_ok());
assert_eq!(*result.expect("operation should succeed"), 42);
}
#[test]
fn test_read_lock_safe_macro() {
let rwlock = Arc::new(RwLock::new(42));
let result = read_lock_safe!(rwlock, "test read");
assert!(result.is_ok());
assert_eq!(*result.expect("operation should succeed"), 42);
}
#[test]
fn test_write_lock_safe_macro() {
let rwlock = Arc::new(RwLock::new(42));
let result = write_lock_safe!(rwlock, "test write");
assert!(result.is_ok());
let mut guard = result.expect("operation should succeed");
*guard = 100;
drop(guard);
assert_eq!(*rwlock.read().expect("operation should succeed"), 100);
}
#[test]
fn test_lock_and_clone_macro() {
let mutex = Arc::new(Mutex::new(String::from("test")));
let result = lock_and_clone!(mutex, "clone test");
assert!(result.is_ok());
assert_eq!(result.expect("operation should succeed"), "test");
}
#[test]
fn test_with_write_helper() {
let rwlock = RwLock::new(42);
let result = with_write(&rwlock, "test write", |value| {
*value = 100;
*value
});
assert!(result.is_ok());
assert_eq!(result.expect("operation should succeed"), 100);
assert_eq!(*rwlock.read().expect("operation should succeed"), 100);
}
#[test]
fn test_with_read_helper() {
let rwlock = RwLock::new(42);
let result = with_read(&rwlock, "test read", |value| *value * 2);
assert!(result.is_ok());
assert_eq!(result.expect("operation should succeed"), 84);
}
#[test]
fn test_with_mutex_helper() {
let mutex = Mutex::new(42);
let result = with_mutex(&mutex, "test mutex", |value| {
*value = 100;
*value
});
assert!(result.is_ok());
assert_eq!(result.expect("operation should succeed"), 100);
assert_eq!(*mutex.lock().expect("operation should succeed"), 100);
}
}