1#![doc(html_favicon_url = "https://zng-ui.github.io/res/zng-logo-icon.png")]
2#![doc(html_logo_url = "https://zng-ui.github.io/res/zng-logo.png")]
3#![doc = include_str!(concat!("../", std::env!("CARGO_PKG_README")))]
9#![warn(unused_extern_crates)]
10#![warn(missing_docs)]
11
12use std::hash::Hash;
13use std::{
14 fmt,
15 hash::Hasher,
16 sync::{
17 Arc, Weak,
18 atomic::{AtomicU8, Ordering},
19 },
20};
21
22#[must_use = "the resource is dropped if the handle is dropped"]
36#[repr(transparent)]
37pub struct Handle<D: Send + Sync>(Arc<HandleState<D>>);
38struct HandleState<D> {
39 state: AtomicU8,
41 data: D,
42}
43impl<D: Send + Sync> Handle<D> {
44 pub fn new(data: D) -> (HandleOwner<D>, Handle<D>) {
46 let handle = Handle(Arc::new(HandleState {
47 state: AtomicU8::new(State::None as u8),
48 data,
49 }));
50 (HandleOwner(handle.clone()), handle)
51 }
52
53 pub fn dummy(data: D) -> Self {
57 Handle(Arc::new(HandleState {
58 state: AtomicU8::new(State::ForceDrop as u8),
59 data,
60 }))
61 }
62
63 pub fn data(&self) -> &D {
65 &self.0.data
66 }
67
68 pub fn perm(self) {
73 let _ = self.0.state.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |s| {
74 if s != State::ForceDrop as u8 {
75 Some(State::Permanent as u8)
76 } else {
77 None
78 }
79 });
80 }
81
82 pub fn is_permanent(&self) -> bool {
87 self.0.state.load(Ordering::Relaxed) == State::Permanent as u8
88 }
89
90 pub fn force_drop(self) {
92 self.0.state.store(State::ForceDrop as u8, Ordering::Relaxed);
93 }
94
95 pub fn is_dropped(&self) -> bool {
102 self.0.state.load(Ordering::Relaxed) == State::ForceDrop as u8
103 }
104
105 pub fn downgrade(&self) -> WeakHandle<D> {
107 WeakHandle(Arc::downgrade(&self.0))
108 }
109}
110impl<D: Send + Sync> Clone for Handle<D> {
111 fn clone(&self) -> Self {
112 Handle(Arc::clone(&self.0))
113 }
114}
115impl<D: Send + Sync> PartialEq for Handle<D> {
116 fn eq(&self, other: &Self) -> bool {
117 Arc::ptr_eq(&self.0, &other.0)
118 }
119}
120impl<D: Send + Sync> Eq for Handle<D> {}
121impl<D: Send + Sync> Hash for Handle<D> {
122 fn hash<H: Hasher>(&self, state: &mut H) {
123 let ptr = Arc::as_ptr(&self.0) as usize;
124 ptr.hash(state);
125 }
126}
127impl<D: Send + Sync> Drop for Handle<D> {
128 fn drop(&mut self) {
129 if !self.is_permanent() && Arc::strong_count(&self.0) == 2 {
130 self.0.state.store(State::ForceDrop as u8, Ordering::Relaxed);
134 }
135 }
136}
137impl<D: Send + Sync> fmt::Debug for Handle<D> {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 if self.is_permanent() {
140 write!(f, "permanent")
141 } else if self.is_dropped() {
142 write!(f, "dropped")
143 } else {
144 write!(f, "holding")
145 }
146 }
147}
148
149pub struct WeakHandle<D: Send + Sync>(Weak<HandleState<D>>);
151impl<D: Send + Sync> WeakHandle<D> {
152 pub fn new() -> Self {
154 WeakHandle(Weak::new())
155 }
156
157 pub fn upgrade(&self) -> Option<Handle<D>> {
159 if let Some(arc) = self.0.upgrade() {
160 let handle = Handle(arc);
161 if handle.is_dropped() { None } else { Some(handle) }
162 } else {
163 None
164 }
165 }
166}
167impl<D: Send + Sync> Default for WeakHandle<D> {
168 fn default() -> Self {
169 Self::new()
170 }
171}
172impl<D: Send + Sync> Clone for WeakHandle<D> {
173 fn clone(&self) -> Self {
174 WeakHandle(self.0.clone())
175 }
176}
177impl<D: Send + Sync> PartialEq for WeakHandle<D> {
178 fn eq(&self, other: &Self) -> bool {
179 Weak::ptr_eq(&self.0, &other.0)
180 }
181}
182impl<D: Send + Sync> Eq for WeakHandle<D> {}
183impl<D: Send + Sync> Hash for WeakHandle<D> {
184 fn hash<H: Hasher>(&self, state: &mut H) {
185 let ptr = self.0.as_ptr() as usize;
186 ptr.hash(state);
187 }
188}
189impl<D: Send + Sync> fmt::Debug for WeakHandle<D> {
190 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191 if self.0.strong_count() > 0 {
192 write!(f, "can-upgrade")
193 } else {
194 write!(f, "dropped")
195 }
196 }
197}
198
199pub struct HandleOwner<D: Send + Sync>(Handle<D>);
205impl<D: Send + Sync> HandleOwner<D> {
206 pub fn is_dropped(&self) -> bool {
211 let state = self.0.0.state.load(Ordering::Relaxed);
212 state == State::ForceDrop as u8 || (state != State::Permanent as u8 && Arc::strong_count(&self.0.0) <= 1)
213 }
214
215 pub fn weak_handle(&self) -> WeakHandle<D> {
217 self.0.downgrade()
218 }
219
220 pub fn data(&self) -> &D {
222 self.0.data()
223 }
224}
225impl<D: Send + Sync> Drop for HandleOwner<D> {
226 fn drop(&mut self) {
227 self.0.0.state.store(State::ForceDrop as u8, Ordering::Relaxed);
228 }
229}
230
231#[repr(u8)]
232enum State {
233 None = 0,
234 Permanent = 1,
235 ForceDrop = 2,
236}