use crate::{Event, EventListener};
use core::cell::{Cell, Ref, RefCell, RefMut};
use core::ops;
use core::pin::Pin;
pub struct RwLock<T: ?Sized> {
no_readers: Event<()>,
no_writers: Event<()>,
readers: Cell<usize>,
data: RefCell<T>,
}
pub struct RwLockReadGuard<'a, T: ?Sized> {
event: &'a Event<()>,
readers: &'a Cell<usize>,
data: Ref<'a, T>,
}
pub struct RwLockWriteGuard<'a, T: ?Sized> {
event: &'a Event<()>,
data: RefMut<'a, T>,
}
impl<T: Default> Default for RwLock<T> {
fn default() -> RwLock<T> {
RwLock::new(Default::default())
}
}
impl<T> RwLock<T> {
pub fn new(data: T) -> RwLock<T> {
RwLock {
no_readers: Event::new(),
no_writers: Event::new(),
readers: Cell::new(0),
data: RefCell::new(data),
}
}
pub fn into_inner(self) -> T {
self.data.into_inner()
}
}
impl<T: ?Sized> RwLock<T> {
pub fn get_mut(&mut self) -> &mut T {
self.data.get_mut()
}
pub fn try_read(&self) -> Option<RwLockReadGuard<'_, T>> {
self.data.try_borrow().ok().map(|data| {
self.readers
.set(self.readers.get().checked_add(1).expect("too many readers"));
RwLockReadGuard {
event: &self.no_readers,
readers: &self.readers,
data,
}
})
}
pub fn try_write(&self) -> Option<RwLockWriteGuard<'_, T>> {
self.data
.try_borrow_mut()
.ok()
.map(|data| RwLockWriteGuard {
event: &self.no_writers,
data,
})
}
pub async fn read(&self) -> RwLockReadGuard<'_, T> {
let mut listener = EventListener::new(&self.no_writers);
{
let mut listener = unsafe { Pin::new_unchecked(&mut listener) };
loop {
if let Some(guard) = self.try_read() {
return guard;
}
listener.as_mut().await;
}
}
}
pub async fn write(&self) -> RwLockWriteGuard<'_, T> {
let mut listener = EventListener::new(&self.no_readers);
{
let mut listener = unsafe { Pin::new_unchecked(&mut listener) };
loop {
if let Some(guard) = self.try_write() {
return guard;
}
listener.as_mut().await;
}
}
}
}
impl<T: ?Sized> ops::Deref for RwLockReadGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
&self.data
}
}
impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> {
fn drop(&mut self) {
let readers = self.readers.get().checked_sub(1).expect("too few readers");
self.readers.set(readers);
if readers == 0 {
self.event.notify(1);
}
}
}
impl<T: ?Sized> ops::Deref for RwLockWriteGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
&self.data
}
}
impl<T: ?Sized> ops::DerefMut for RwLockWriteGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.data
}
}
impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> {
fn drop(&mut self) {
self.event.notify(1);
}
}