rt_own/
ptr.rs

1use std::alloc;
2use std::cell::Cell;
3use std::cell::UnsafeCell;
4use std::fmt::Debug;
5use std::fmt::Formatter;
6use std::hash::Hash;
7use std::hash::Hasher;
8use std::marker::PhantomData;
9use std::ptr;
10use std::ptr::NonNull;
11
12pub(crate) struct Ptr<D: ?Sized> {
13    ptr: NonNull<StateCell<D>>,
14    phantom: PhantomData<StateCell<D>>,
15}
16
17#[derive(Debug, Copy, Clone)]
18pub(crate) enum Role {
19    Holder,
20    Viewer,
21    Owner,
22}
23
24#[derive(Copy, Clone, PartialEq, Eq, Hash)]
25pub struct State {
26    // the sign bit indicates whether data has been dropped (negative)
27    // other bits indicates holder cnt
28    holder_cnt: isize,
29    // the sign bit indicates whether data has been owned (negative)
30    // other bits indicates viewer cnt
31    viewer_cnt: isize,
32}
33
34impl<D: ?Sized> Ptr<D> {
35    pub(crate) fn new(d: D, role: Role) -> Self
36    where D: Sized {
37        let ptr = Box::leak(Box::new(StateCell::new(d, role)));
38        Ptr { ptr: ptr.into(), phantom: PhantomData }
39    }
40
41    pub(crate) fn clone_to(&self, role: Role) -> Result<Ptr<D>, State> {
42        self.cell().clone_to(role)?;
43        Ok(Ptr { ptr: self.ptr, phantom: PhantomData })
44    }
45
46    pub(crate) fn drop_from(&self, role: Role) {
47        self.cell().drop_from(role);
48
49        if self.cell().should_dealloc() {
50            let layout = alloc::Layout::for_value(self.cell());
51            // SAFETY:
52            // state promises that we can and should dealloc
53            // we are the last Ptr accessible to the ptr of PtrCell, and we are dropped
54            // we carefully don't make any ref to PtrCell when calling dealloc
55            unsafe {
56                alloc::dealloc(self.ptr.as_ptr().cast(), layout);
57            }
58        }
59    }
60
61    pub(crate) fn cell(&self) -> &StateCell<D> {
62        // SAFETY: when self is alive, ptr is always valid, and we never call ptr.as_mut()
63        unsafe { self.ptr.as_ref() }
64    }
65}
66
67impl<D: ?Sized> Debug for Ptr<D> {
68    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
69        self.ptr.fmt(f)
70    }
71}
72
73impl<D: ?Sized> PartialEq for Ptr<D> {
74    fn eq(&self, other: &Self) -> bool {
75        ptr::addr_eq(self.ptr.as_ptr(), other.ptr.as_ptr())
76    }
77}
78
79impl<D: ?Sized> Eq for Ptr<D> {}
80
81impl<D: ?Sized> Hash for Ptr<D> {
82    fn hash<H: Hasher>(&self, state: &mut H) {
83        self.ptr.hash(state);
84    }
85}
86
87pub(crate) struct StateCell<D: ?Sized> {
88    state: Cell<State>,
89    data: UnsafeCell<D>,
90}
91
92impl<D: ?Sized> StateCell<D> {
93    fn new(d: D, role: Role) -> Self
94    where D: Sized {
95        StateCell { state: Cell::new(State::new(role)), data: UnsafeCell::new(d) }
96    }
97
98    pub(crate) fn state(&self) -> State {
99        self.state.get()
100    }
101
102    fn clone_to(&self, role: Role) -> Result<(), State> {
103        self.state.set(self.state.get().clone_to(role)?);
104        Ok(())
105    }
106
107    fn drop_from(&self, role: Role) {
108        self.state.set(self.state.get().drop_from(role));
109        if self.state.get().should_drop() {
110            // SAFETY: state promises that we can and should drop
111            unsafe { self.drop_data() }
112        }
113    }
114
115    // SAFETY: call only once and there is no ref
116    pub(crate) unsafe fn move_data(&self) -> D
117    where D: Sized {
118        self.state.set(self.state.get().drop());
119        // SAFETY: call only once and there is no ref
120        unsafe { ptr::read(self.data.get()) }
121    }
122
123    // SAFETY: call only once and there is no ref
124    pub(crate) unsafe fn drop_data(&self) {
125        self.state.set(self.state.get().drop());
126        // SAFETY: call only once and there is no ref
127        unsafe {
128            ptr::drop_in_place(self.data.get());
129        }
130    }
131
132    // SAFETY: data is dropped
133    pub(crate) unsafe fn reinit_data(&self, d: D)
134    where D: Sized {
135        self.state.set(self.state.get().reinit());
136        // SAFETY: data is dropped
137        unsafe {
138            ptr::write(self.data.get(), d);
139        }
140    }
141
142    fn should_dealloc(&self) -> bool {
143        self.state.get().should_dealloc()
144    }
145
146    // SAFETY: make sure data not dropped and there is no owner
147    pub(crate) unsafe fn deref<'a>(&self) -> &'a D {
148        // SAFETY: make sure data not dropped and there is no owner
149        unsafe { self.data.get().as_ref().unwrap() }
150    }
151
152    // SAFETY: make sure data not dropped and there is no ref
153    pub(crate) unsafe fn deref_mut<'a>(&self) -> &'a mut D {
154        // SAFETY: make sure data not dropped and there is no ref
155        unsafe { self.data.get().as_mut().unwrap() }
156    }
157}
158
159impl State {
160    pub fn is_dropped(&self) -> bool {
161        self.holder_cnt < 0
162    }
163
164    pub fn holder_count(&self) -> usize {
165        (self.holder_cnt & isize::MAX) as usize
166    }
167
168    pub fn viewer_count(&self) -> usize {
169        (self.viewer_cnt & isize::MAX) as usize
170    }
171
172    pub fn is_owned(&self) -> bool {
173        self.viewer_cnt < 0
174    }
175
176    fn new(role: Role) -> Self {
177        let (holder_cnt, viewer_cnt) = match role {
178            Role::Holder => (1, 0),
179            Role::Viewer => (0, 1),
180            Role::Owner => (0, isize::MIN),
181        };
182        State { holder_cnt, viewer_cnt }
183    }
184
185    fn clone_to(mut self, role: Role) -> Result<State, State> {
186        match role {
187            Role::Holder => {
188                self.holder_cnt += 1;
189                Ok(self)
190            }
191            Role::Viewer => {
192                if self.is_dropped() || self.is_owned() {
193                    Err(self)
194                } else {
195                    self.viewer_cnt += 1;
196                    Ok(self)
197                }
198            }
199            Role::Owner => {
200                if self.is_dropped() || self.viewer_cnt != 0 {
201                    Err(self)
202                } else {
203                    self.viewer_cnt = isize::MIN;
204                    Ok(self)
205                }
206            }
207        }
208    }
209
210    fn drop_from(mut self, role: Role) -> State {
211        match role {
212            Role::Holder => self.holder_cnt -= 1,
213            Role::Viewer => self.viewer_cnt -= 1,
214            Role::Owner => self.viewer_cnt = 0,
215        }
216        self
217    }
218
219    fn drop(mut self) -> State {
220        self.holder_cnt |= isize::MIN;
221        self
222    }
223
224    fn reinit(mut self) -> State {
225        self.holder_cnt &= isize::MAX;
226        self
227    }
228
229    // if already dropped, return false
230    fn should_drop(&self) -> bool {
231        self.holder_cnt == 0 && self.viewer_cnt == 0
232    }
233
234    fn should_dealloc(&self) -> bool {
235        self.holder_cnt == isize::MIN && self.viewer_cnt == 0
236    }
237}
238
239impl Debug for State {
240    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
241        f.debug_struct("State")
242            .field("dropped", &self.is_dropped())
243            .field("holder", &self.holder_count())
244            .field("viewer", &self.viewer_count())
245            .field("owned", &self.is_owned())
246            .finish()
247    }
248}