use std::fmt::Debug;
use crate::sync::atomic;
use std::ops::Deref;
use std::sync::Arc;
use crate::queues::mpsc::jiffy;
use super::record::Record;
pub struct Guard<T> {
inner: *mut T,
record: *mut Record<()>,
record_returner: Arc<jiffy::Sender<*mut Record<()>>>,
}
impl<T> Debug for Guard<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Guard ()")
}
}
impl<T> Drop for Guard<T> {
fn drop(&mut self) {
let record = unsafe { &*self.record };
record.reset();
let _ = self.record_returner.enqueue(self.record);
}
}
impl<T> Deref for Guard<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.inner }
}
}
impl<T> Guard<T> {
pub(crate) fn new(
ptr: *mut T,
record: *mut Record<()>,
returner: Arc<jiffy::Sender<*mut Record<()>>>,
) -> Self {
Self {
inner: ptr,
record,
record_returner: returner,
}
}
pub fn raw(&self) -> *const T {
self.inner as *const T
}
pub fn protect(&mut self, atom_ptr: &atomic::AtomicPtr<T>, load_order: atomic::Ordering) {
let record = unsafe { &*self.record };
let mut protect_ptr = atom_ptr.load(load_order);
loop {
record
.ptr
.store(protect_ptr as *mut (), atomic::Ordering::SeqCst);
let n_ptr = atom_ptr.load(load_order);
if n_ptr == protect_ptr {
break;
}
protect_ptr = n_ptr;
}
self.inner = protect_ptr;
}
pub unsafe fn convert<O>(self) -> Guard<O> {
unsafe { std::mem::transmute(self) }
}
}