use std::{collections::hash_map::RandomState, ptr::NonNull};
use crate::{
core::{Handle, MapAccess, MapIndex, ReaderStatus, RefCount},
loom::cell::UnsafeCell,
loom::sync::Arc,
view::sealed::ReadAccess,
Map, View,
};
pub struct ReadHandle<K, V, S = RandomState> {
inner: Arc<Handle<K, V, S>>,
map_access: MapAccess<K, V, S>,
refcount: NonNull<RefCount>,
refcount_key: usize,
}
unsafe impl<K, V, S> Send for ReadHandle<K, V, S>
where
K: Send + Sync,
V: Send + Sync,
S: Send + Sync,
{
}
unsafe impl<K, V, S> Sync for ReadHandle<K, V, S>
where
K: Send + Sync,
V: Send + Sync,
S: Send + Sync,
{
}
impl<K, V, S> ReadHandle<K, V, S> {
pub(crate) fn new(
inner: Arc<Handle<K, V, S>>,
map_access: MapAccess<K, V, S>,
refcount: NonNull<RefCount>,
refcount_key: usize,
) -> Self {
Self {
refcount,
map_access,
inner,
refcount_key,
}
}
#[inline]
pub fn guard(&self) -> View<ReadGuard<'_, K, V, S>> {
let map_index = unsafe { Handle::<K, V, S>::start_read(self.refcount.as_ref()) };
View::new(ReadGuard {
handle: self,
map: unsafe { self.map_access.get(map_index) },
map_index,
})
}
}
impl<K, V, S> Clone for ReadHandle<K, V, S> {
fn clone(&self) -> Self {
Handle::new_reader(Arc::clone(&self.inner))
}
}
impl<K, V, S> Drop for ReadHandle<K, V, S> {
fn drop(&mut self) {
unsafe {
self.inner.release_refcount(self.refcount_key);
}
}
}
pub struct ReadGuard<'guard, K, V, S> {
handle: &'guard ReadHandle<K, V, S>,
map: &'guard UnsafeCell<Map<K, V, S>>,
map_index: MapIndex,
}
unsafe impl<K, V, S> Send for ReadGuard<'_, K, V, S>
where
K: Send + Sync,
V: Send + Sync,
S: Send + Sync,
{
}
unsafe impl<K, V, S> Sync for ReadGuard<'_, K, V, S>
where
K: Send + Sync,
V: Send + Sync,
S: Send + Sync,
{
}
impl<'guard, K, V, S> ReadAccess for ReadGuard<'guard, K, V, S> {
type Map = Map<K, V, S>;
fn with_map<'read, F, R>(&'read self, op: F) -> R
where
F: FnOnce(&'read Self::Map) -> R,
{
self.map.with(|ptr| op(unsafe { &*ptr }))
}
}
impl<'guard, K, V, S> Drop for ReadGuard<'guard, K, V, S> {
fn drop(&mut self) {
let refcount = unsafe { self.handle.refcount.as_ref() };
if Handle::<K, V, S>::finish_read(refcount, self.map_index) == ReaderStatus::Residual {
unsafe { self.handle.inner.release_residual() };
}
}
}