use core::{
cell::UnsafeCell,
ops::{Deref, DerefMut},
};
use crate::semaphore::Semaphore;
pub struct RwLock<T> {
data: UnsafeCell<T>,
semaphore: Semaphore,
max_readers: usize,
}
impl<T> RwLock<T> {
pub const fn new(data: T) -> Self {
Self::with_max_readers(data, usize::MAX)
}
pub const fn with_max_readers(data: T, max_readers: usize) -> Self {
Self {
data: UnsafeCell::new(data),
semaphore: Semaphore::new(max_readers),
max_readers,
}
}
pub async fn read(&self) -> ReadGuard<'_, T> {
self.semaphore.acquire(1).await;
ReadGuard { rwlock: self }
}
pub async fn write(&self) -> WriteGuard<'_, T> {
self.semaphore.acquire(self.max_readers).await;
WriteGuard { rwlock: self }
}
}
unsafe impl<T: Send> Send for RwLock<T> {}
unsafe impl<T: Send> Sync for RwLock<T> {}
pub struct ReadGuard<'a, T> {
rwlock: &'a RwLock<T>,
}
impl<T> Deref for ReadGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.rwlock.data.get() }
}
}
impl<T> Drop for ReadGuard<'_, T> {
fn drop(&mut self) {
self.rwlock.semaphore.release(1);
}
}
pub struct WriteGuard<'a, T> {
rwlock: &'a RwLock<T>,
}
impl<T> Deref for WriteGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.rwlock.data.get() }
}
}
impl<T> DerefMut for WriteGuard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.rwlock.data.get() }
}
}
impl<T> Drop for WriteGuard<'_, T> {
fn drop(&mut self) {
self.rwlock.semaphore.release(self.rwlock.max_readers);
}
}