#![deny(missing_docs)]
#![doc = include_str!("../README.md")]
use parking_lot::Mutex;
use std::sync::Arc;
#[derive(Clone, Default, Debug)]
pub struct EasyMutex<T>(Arc<Mutex<T>>);
impl<T> EasyMutex<T> {
pub fn new(value: T) -> Self {
Self(Arc::new(Mutex::new(value)))
}
pub fn read(&self) -> T
where
T: Clone,
{
self.0.lock().clone()
}
pub fn write(&self, new_value: T) {
*self.0.lock() = new_value;
}
}
impl<T> From<T> for EasyMutex<T> {
fn from(value: T) -> Self {
Self::new(value)
}
}
#[cfg(test)]
mod tests {
use super::EasyMutex;
use std::thread;
use std::time::{Duration, Instant};
#[test]
fn basic_read_write() {
let m = EasyMutex::new(10);
assert_eq!(m.read(), 10);
m.write(20);
assert_eq!(m.read(), 20);
}
#[test]
fn clone_mutex_and_share() {
let m = EasyMutex::new(0);
let m2 = m.clone();
m.write(5);
assert_eq!(m2.read(), 5);
}
#[test]
fn test_from_impl() {
let data: EasyMutex<String> = "hello".to_string().into();
assert_eq!(data.read(), "hello");
}
#[test]
fn concurrent_modify() {
let m = EasyMutex::new(0);
let mut handles = vec![];
for _ in 0..10 {
let m_clone = m.clone();
let handle = thread::spawn(move || {
let start = Instant::now();
while Instant::now().duration_since(start) < Duration::from_secs(10) {
m_clone.write(m_clone.read() + 1);
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
let final_val = m.read();
assert!(final_val >= 10000 && final_val <= 100000000);
}
}