use {crate::utils::thread_id::ThreadId, std::ops::Deref};
#[cfg(test)]
mod tests;
pub(crate) struct ReentrantMutex<T> {
ty: Ty,
val: T,
}
pub struct ReentrantMutexGuard<'a, T> {
val: &'a T,
_lock: Option<parking_lot::ReentrantMutexGuard<'a, ()>>,
}
enum Ty {
ThreadLocal(ThreadId),
Shared(parking_lot::ReentrantMutex<()>),
}
unsafe impl<T: Send> Sync for ReentrantMutex<T> {}
impl<T> ReentrantMutex<T> {
pub(crate) fn new_shared(val: T) -> Self {
Self {
ty: Ty::Shared(parking_lot::ReentrantMutex::new(())),
val,
}
}
pub(crate) fn new_thread_local(val: T) -> Self {
Self {
ty: Ty::ThreadLocal(ThreadId::current()),
val,
}
}
pub(crate) fn is_thread_local(&self) -> bool {
matches!(self.ty, Ty::ThreadLocal(_))
}
#[inline]
pub(crate) fn lock(&self) -> ReentrantMutexGuard<'_, T> {
let lock = match &self.ty {
Ty::ThreadLocal(tid) => {
if tid.is_not_current() {
panic!("Trying to lock thread-local mutex in other thread");
}
None
}
Ty::Shared(mutex) => Some(mutex.lock()),
};
ReentrantMutexGuard {
val: &self.val,
_lock: lock,
}
}
}
impl<T> Deref for ReentrantMutexGuard<'_, T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
self.val
}
}