use std::{
fmt,
hash,
mem,
ops::Deref,
ptr,
};
#[cfg(feature = "parking_lot")]
pub use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
#[cfg(not(feature = "parking_lot"))]
pub use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
pub(crate) mod rwlock {
use super::{RwLock, RwLockReadGuard, RwLockWriteGuard};
#[inline]
pub fn read<T: ?Sized>(this: &RwLock<T>) -> RwLockReadGuard<T> {
#[cfg(feature = "parking_lot")]
let guard = this.read();
#[cfg(not(feature = "parking_lot"))]
let guard = this.read().unwrap();
guard
}
#[inline]
pub fn write<T: ?Sized>(this: &RwLock<T>) -> RwLockWriteGuard<T> {
#[cfg(feature = "parking_lot")]
let guard = this.write();
#[cfg(not(feature = "parking_lot"))]
let guard = this.write().unwrap();
guard
}
#[inline]
pub fn get_mut<T: ?Sized>(this: &mut RwLock<T>) -> &mut T {
#[cfg(feature = "parking_lot")]
let guard = this.get_mut();
#[cfg(not(feature = "parking_lot"))]
let guard = this.get_mut().unwrap();
guard
}
#[inline]
pub fn into_inner<T>(this: RwLock<T>) -> T {
#[cfg(feature = "parking_lot")]
let inner = this.into_inner();
#[cfg(not(feature = "parking_lot"))]
let inner = this.into_inner().unwrap();
inner
}
}
#[repr(C)]
pub(crate) struct CacheEntry {
data: *const RwLock<()>,
drop_concrete: unsafe fn(&mut CacheEntry),
}
impl<'a> CacheEntry {
#[inline]
pub fn new<T: Send + Sync>(asset: T) -> Self {
let concrete = ContreteCacheEntry {
data: Box::new(RwLock::new(asset)),
drop: CacheEntry::drop_data::<T>,
};
unsafe { mem::transmute(concrete) }
}
unsafe fn drop_data<T: Send + Sync>(&mut self) {
let my_box = &mut self.data as *mut *const RwLock<()> as *mut Box<RwLock<T>>;
ptr::drop_in_place(my_box);
}
#[inline]
pub unsafe fn get_ref<T: Send + Sync>(&self) -> AssetRefLock<'a, T> {
let concrete = {
let ptr = self as *const CacheEntry as *const ContreteCacheEntry<T>;
&*ptr
};
concrete.get_ref()
}
pub unsafe fn write<T: Send + Sync>(&self, asset: T) -> AssetRefLock<'a, T> {
let lock = self.get_ref();
let mut cached_guard = rwlock::write(&lock.data);
*cached_guard = asset;
drop(cached_guard);
lock
}
#[inline]
pub unsafe fn into_inner<T: Send + Sync>(self) -> T {
let concrete: ContreteCacheEntry<T> = mem::transmute(self);
concrete.into_inner()
}
}
unsafe impl Send for CacheEntry {}
unsafe impl Sync for CacheEntry {}
impl fmt::Debug for CacheEntry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad("CacheEntry { ... }")
}
}
impl Drop for CacheEntry {
fn drop(&mut self) {
unsafe {
(self.drop_concrete)(self);
}
}
}
#[repr(C)]
struct ContreteCacheEntry<T> {
data: Box<RwLock<T>>,
drop: unsafe fn(&mut CacheEntry),
}
impl<T: Send + Sync> ContreteCacheEntry<T> {
#[inline]
fn get_ref(&self) -> AssetRefLock<T> {
AssetRefLock { data: &*self.data }
}
#[inline]
fn into_inner(self) -> T {
rwlock::into_inner(*self.data)
}
}
impl<T> fmt::Debug for ContreteCacheEntry<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.data.read().fmt(f)
}
}
pub struct AssetRefLock<'a, A> {
data: &'a RwLock<A>,
}
impl<A> AssetRefLock<'_, A> {
#[inline]
pub fn read(&self) -> AssetRef<'_, A> {
AssetRef {
guard: rwlock::read(self.data),
}
}
#[inline]
pub fn ptr_eq(&self, other: &Self) -> bool {
std::ptr::eq(self.data, other.data)
}
}
impl<A> Clone for AssetRefLock<'_, A> {
fn clone(&self) -> Self {
Self {
data: self.data,
}
}
}
impl<A> Copy for AssetRefLock<'_, A> {}
impl<A> hash::Hash for AssetRefLock<'_, A>
where
A: hash::Hash,
{
fn hash<H: hash::Hasher>(&self, state: &mut H) {
rwlock::read(self.data).hash(state);
}
}
impl<A> fmt::Debug for AssetRefLock<'_, A>
where
A: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AssetRefLock").field("data", &*rwlock::read(&self.data)).finish()
}
}
pub struct AssetRef<'a, A> {
guard: RwLockReadGuard<'a, A>,
}
impl<A> Deref for AssetRef<'_, A> {
type Target = A;
#[inline]
fn deref(&self) -> &A {
&self.guard
}
}
impl<A> fmt::Display for AssetRef<'_, A>
where
A: fmt::Display,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}
impl<A> fmt::Debug for AssetRef<'_, A>
where
A: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}