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 holder_cnt: isize,
29 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 unsafe {
56 alloc::dealloc(self.ptr.as_ptr().cast(), layout);
57 }
58 }
59 }
60
61 pub(crate) fn cell(&self) -> &StateCell<D> {
62 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 unsafe { self.drop_data() }
112 }
113 }
114
115 pub(crate) unsafe fn move_data(&self) -> D
117 where D: Sized {
118 self.state.set(self.state.get().drop());
119 unsafe { ptr::read(self.data.get()) }
121 }
122
123 pub(crate) unsafe fn drop_data(&self) {
125 self.state.set(self.state.get().drop());
126 unsafe {
128 ptr::drop_in_place(self.data.get());
129 }
130 }
131
132 pub(crate) unsafe fn reinit_data(&self, d: D)
134 where D: Sized {
135 self.state.set(self.state.get().reinit());
136 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 pub(crate) unsafe fn deref<'a>(&self) -> &'a D {
148 unsafe { self.data.get().as_ref().unwrap() }
150 }
151
152 pub(crate) unsafe fn deref_mut<'a>(&self) -> &'a mut D {
154 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 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}