#![allow(clippy::needless_lifetimes)]
use alloc::sync::Arc;
#[cfg(feature = "std")]
extern crate std;
use core::marker::{PhantomData, Send};
use core::ops::Deref;
#[cfg(feature = "std")]
use std::sync::{RwLock, RwLockReadGuard};
#[cfg(not(feature = "std"))]
use spin::{RwLock, RwLockReadGuard};
pub enum ResourceEntry<T> {
Empty,
Owned(T),
Borrowed(Arc<RwLock<bool>>, *const T),
}
unsafe impl<T: Send> Send for ResourceEntry<T> {}
pub struct LentResourceGuard<'a> {
flag: Arc<RwLock<bool>>,
already_revoked: bool,
_phantom: core::marker::PhantomData<&'a mut ()>,
}
impl<'a> LentResourceGuard<'a> {
pub fn revoke_nonblocking(&mut self) -> bool {
#[cfg(feature = "std")]
let Ok(mut flag) = self.flag.try_write() else {
return false;
};
#[cfg(not(feature = "std"))]
let Some(mut flag) = self.flag.try_write() else {
return false;
};
*flag = false;
self.already_revoked = true;
true
}
}
impl<'a> Drop for LentResourceGuard<'a> {
fn drop(&mut self) {
if !self.already_revoked {
#[allow(unused_mut)] let mut guard = self.flag.write();
#[cfg(feature = "std")]
#[allow(clippy::unwrap_used)]
{
*guard.unwrap() = false;
}
#[cfg(not(feature = "std"))]
{
*guard = false;
}
}
}
}
pub struct BorrowedResourceGuard<'a, T> {
_flag: Option<RwLockReadGuard<'a, bool>>,
reference: &'a T,
}
impl<'a, T> Deref for BorrowedResourceGuard<'a, T> {
type Target = T;
fn deref(&self) -> &T {
self.reference
}
}
impl<T> ResourceEntry<T> {
pub fn give(x: T) -> ResourceEntry<T> {
ResourceEntry::Owned(x)
}
pub fn lend<'a>(x: &'a T) -> (LentResourceGuard<'a>, ResourceEntry<T>) {
let flag = Arc::new(RwLock::new(true));
(
LentResourceGuard {
flag: flag.clone(),
already_revoked: false,
_phantom: PhantomData {},
},
ResourceEntry::Borrowed(flag, x as *const T),
)
}
pub fn borrow<'a>(&'a self) -> Option<BorrowedResourceGuard<'a, T>> {
match self {
ResourceEntry::Empty => None,
ResourceEntry::Owned(t) => Some(BorrowedResourceGuard {
_flag: None,
reference: t,
}),
ResourceEntry::Borrowed(flag, t) => {
let guard = flag.read();
#[allow(clippy::unwrap_used)]
let flag = {
#[cfg(feature = "std")]
{
guard.unwrap()
}
#[cfg(not(feature = "std"))]
{
guard
}
};
if *flag {
Some(BorrowedResourceGuard {
_flag: Some(flag),
reference: unsafe { &**t },
})
} else {
None
}
}
}
}
pub fn take(&mut self) -> Option<T> {
match core::mem::replace(self, ResourceEntry::Empty) {
ResourceEntry::Owned(t) => Some(t),
_ => None,
}
}
}