1use crossbeam_epoch::{Atomic, Owned};
2use std::{marker::PhantomData, sync::atomic::Ordering};
3
4const fn drop_inner(flag: u8) -> u8 {
5 flag & 0b01
6}
7
8const fn is_outer_live(flag: u8) -> bool {
9 flag & 0b01 > 0
10}
11
12#[derive(Debug)]
13pub struct Inner<T> {
14 flag_ptr: usize,
15 data_ptr: usize,
16 _type: PhantomData<T>,
17}
18
19impl<T> Inner<T> {
20 pub(crate) const fn new(flag_ptr: usize, data_ptr: usize) -> Self {
21 Self {
22 flag_ptr,
23 data_ptr,
24 _type: PhantomData,
25 }
26 }
27 #[must_use]
28 pub fn get(&self) -> Option<&T> {
29 let guard = crossbeam_epoch::pin();
30 let flag_ptr = unsafe { &*(self.flag_ptr as *const Atomic<u8>) };
31 let flag = flag_ptr.load(Ordering::Acquire, &guard);
32 let old = unsafe { *flag.deref() };
33 if is_outer_live(old) {
34 Some(unsafe { &*(self.data_ptr as *const T) })
35 } else {
36 None
37 }
38 }
39}
40impl<T> Drop for Inner<T> {
41 fn drop(&mut self) {
42 let guard = crossbeam_epoch::pin();
43 let flag_ptr = unsafe { &*(self.flag_ptr as *const Atomic<u8>) };
44 loop {
45 let flag = flag_ptr.load(Ordering::Acquire, &guard);
46 let old = unsafe { *flag.deref() };
47 let n = drop_inner(old);
48
49 if let Ok(t) = flag_ptr.compare_and_set(flag, Owned::new(n), Ordering::Release, &guard)
50 {
51 if n == 0 {
52 unsafe {
53 guard.defer_destroy(t);
54 std::ptr::drop_in_place(self.data_ptr as *mut T);
55 }
56 }
57 break;
58 }
59 }
60 }
61}