1#![doc(html_favicon_url = "https://raw.githubusercontent.com/zng-ui/zng/main/examples/image/res/zng-logo-icon.png")]
2#![doc(html_logo_url = "https://raw.githubusercontent.com/zng-ui/zng/main/examples/image/res/zng-logo.png")]
3//!
4//! Resource handle type.
5//!
6//! # Crate
7//!
8#![doc = include_str!(concat!("../", std::env!("CARGO_PKG_README")))]
9#![warn(unused_extern_crates)]
10#![warn(missing_docs)]
1112use std::hash::Hash;
13use std::{
14 fmt,
15 hash::Hasher,
16 sync::{
17 Arc, Weak,
18 atomic::{AtomicU8, Ordering},
19 },
20};
2122/// Represents a resource handle.
23///
24/// The resource stays in memory as long as a handle clone is alive. After the handle
25/// is dropped the resource will be removed after an indeterminate time at the discretion
26/// of the resource manager.
27///
28/// You can *forget* a handle by calling [`perm`](Self::perm), this releases the handle memory
29/// but the resource stays alive for the duration of the app, unlike calling [`std::mem::forget`] no memory is leaked.
30///
31/// Any handle can also [`force_drop`](Self::force_drop), meaning that even if there are various handles active the
32/// resource will be dropped regardless.
33///
34/// The parameter type `D` is any [`Sync`] data type that will be shared using the handle.
35#[must_use = "the resource id dropped if the handle is dropped"]
36#[repr(transparent)]
37pub struct Handle<D: Send + Sync>(Arc<HandleState<D>>);
38struct HandleState<D> {
39 state: AtomicU8,
40 data: D,
41}
42impl<D: Send + Sync> Handle<D> {
43/// Create a handle with owner pair.
44pub fn new(data: D) -> (HandleOwner<D>, Handle<D>) {
45let handle = Handle(Arc::new(HandleState {
46 state: AtomicU8::new(NONE),
47 data,
48 }));
49 (HandleOwner(handle.clone()), handle)
50 }
5152/// Create a handle to nothing, the handle always in the *dropped* state.
53 ///
54 /// Note that `Option<Handle<D>>` takes up the same space as `Handle<D>` and avoids an allocation.
55pub fn dummy(data: D) -> Self {
56 Handle(Arc::new(HandleState {
57 state: AtomicU8::new(FORCE_DROP),
58 data,
59 }))
60 }
6162/// Reference the attached data.
63pub fn data(&self) -> &D {
64&self.0.data
65 }
6667/// Mark the handle as permanent and drops this clone of it. This causes the resource to stay in memory
68 /// until the app exits, no need to hold a handle somewhere.
69pub fn perm(self) {
70self.0.state.fetch_or(PERMANENT, Ordering::Relaxed);
71 }
7273/// If [`perm`](Self::perm) was called in another clone of this handle.
74 ///
75 /// If `true` the resource will stay in memory for the duration of the app, unless [`force_drop`](Self::force_drop)
76 /// is also called.
77pub fn is_permanent(&self) -> bool {
78self.0.state.load(Ordering::Relaxed) == PERMANENT
79 }
8081/// Force drops the handle, meaning the resource will be dropped even if there are other handles active.
82pub fn force_drop(self) {
83self.0.state.store(FORCE_DROP, Ordering::Relaxed);
84 }
8586/// If the handle is in *dropped* state.
87 ///
88 /// The handle is considered dropped when all handle and clones are dropped or when [`force_drop`](Handle::force_drop)
89 /// was called in any of the clones.
90 ///
91 /// Note that in this method it can only be because [`force_drop`](Handle::force_drop) was called.
92pub fn is_dropped(&self) -> bool {
93self.0.state.load(Ordering::Relaxed) == FORCE_DROP
94 }
9596/// Create a [`WeakHandle`] to this handle.
97pub fn downgrade(&self) -> WeakHandle<D> {
98 WeakHandle(Arc::downgrade(&self.0))
99 }
100}
101impl<D: Send + Sync> Clone for Handle<D> {
102fn clone(&self) -> Self {
103 Handle(Arc::clone(&self.0))
104 }
105}
106impl<D: Send + Sync> PartialEq for Handle<D> {
107fn eq(&self, other: &Self) -> bool {
108 Arc::ptr_eq(&self.0, &other.0)
109 }
110}
111impl<D: Send + Sync> Eq for Handle<D> {}
112impl<D: Send + Sync> Hash for Handle<D> {
113fn hash<H: Hasher>(&self, state: &mut H) {
114let ptr = Arc::as_ptr(&self.0) as usize;
115 ptr.hash(state);
116 }
117}
118impl<D: Send + Sync> Drop for Handle<D> {
119fn drop(&mut self) {
120if !self.is_permanent() && Arc::strong_count(&self.0) == 2 {
121// if we are about to drop the last handle and it is not permanent, force-drop
122 // this causes potential weak-handles to not reanimate a dropping resource because
123 // of the handle that HandleOwner holds.
124self.0.state.store(FORCE_DROP, Ordering::Relaxed);
125 }
126 }
127}
128impl<D: Send + Sync> fmt::Debug for Handle<D> {
129fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130if self.is_permanent() {
131write!(f, "permanent")
132 } else if self.is_dropped() {
133write!(f, "dropped")
134 } else {
135write!(f, "holding")
136 }
137 }
138}
139140/// A weak reference to a [`Handle`].
141pub struct WeakHandle<D: Send + Sync>(Weak<HandleState<D>>);
142impl<D: Send + Sync> WeakHandle<D> {
143/// New weak handle that does not upgrade.
144pub fn new() -> Self {
145 WeakHandle(Weak::new())
146 }
147148/// Get a live handle if it was not dropped or force-dropped.
149pub fn upgrade(&self) -> Option<Handle<D>> {
150if let Some(arc) = self.0.upgrade() {
151let handle = Handle(arc);
152if handle.is_dropped() { None } else { Some(handle) }
153 } else {
154None
155}
156 }
157}
158impl<D: Send + Sync> Default for WeakHandle<D> {
159fn default() -> Self {
160Self::new()
161 }
162}
163impl<D: Send + Sync> Clone for WeakHandle<D> {
164fn clone(&self) -> Self {
165 WeakHandle(self.0.clone())
166 }
167}
168impl<D: Send + Sync> PartialEq for WeakHandle<D> {
169fn eq(&self, other: &Self) -> bool {
170 Weak::ptr_eq(&self.0, &other.0)
171 }
172}
173impl<D: Send + Sync> Eq for WeakHandle<D> {}
174impl<D: Send + Sync> Hash for WeakHandle<D> {
175fn hash<H: Hasher>(&self, state: &mut H) {
176let ptr = self.0.as_ptr() as usize;
177 ptr.hash(state);
178 }
179}
180impl<D: Send + Sync> fmt::Debug for WeakHandle<D> {
181fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182if self.0.strong_count() > 0 {
183write!(f, "can-upgrade")
184 } else {
185write!(f, "dropped")
186 }
187 }
188}
189190/// A [`Handle`] owner.
191///
192/// Use [`Handle::new`] to create.
193///
194/// Dropping the [`HandleOwner`] marks all active handles as *force-drop*.
195pub struct HandleOwner<D: Send + Sync>(Handle<D>);
196impl<D: Send + Sync> HandleOwner<D> {
197/// If the handle is in *dropped* state.
198 ///
199 /// The handle is considered dropped when all handle and clones are dropped or when [`force_drop`](Handle::force_drop)
200 /// was called in any of the clones.
201pub fn is_dropped(&self) -> bool {
202let state = self.0.0.state.load(Ordering::Relaxed);
203 state == FORCE_DROP || (state != PERMANENT && Arc::strong_count(&self.0.0) <= 1)
204 }
205206/*
207 /// New handle owner in the dropped state.
208 pub fn dropped(data: D) -> HandleOwner<D> {
209 HandleOwner(Handle(Arc::new(HandleState {
210 state: AtomicU8::new(FORCE_DROP),
211 data,
212 })))
213 }
214215 /// Gets a new handle and resets the state if it was *force-drop*.
216 ///
217 /// Note that handles are permanently dropped when the last handle is dropped.
218 pub fn reanimate(&self) -> Handle<D> {
219 if self.is_dropped() {
220 self.0 .0.state.store(NONE, Ordering::Relaxed);
221 }
222 self.0.clone()
223 }
224225 */
226227/// Gets an weak handle that may-not be able to upgrade.
228pub fn weak_handle(&self) -> WeakHandle<D> {
229self.0.downgrade()
230 }
231232/// Reference the attached data.
233pub fn data(&self) -> &D {
234self.0.data()
235 }
236}
237impl<D: Send + Sync> Drop for HandleOwner<D> {
238fn drop(&mut self) {
239self.0.0.state.store(FORCE_DROP, Ordering::Relaxed);
240 }
241}
242243const NONE: u8 = 0;
244const PERMANENT: u8 = 0b01;
245const FORCE_DROP: u8 = 0b11;