Skip to main content

assets_manager/
entry.rs

1//! Definitions of cache entries
2
3use crate::{Asset, SharedString, asset::Storable, key::Type, utils::RwLock};
4use std::{
5    any::{Any, TypeId},
6    cell::UnsafeCell,
7    fmt,
8    marker::PhantomData,
9    mem::ManuallyDrop,
10    ops::Deref,
11    sync::{
12        Arc, Weak,
13        atomic::{AtomicBool, AtomicUsize, Ordering},
14    },
15};
16
17#[cfg(feature = "hot-reloading")]
18use crate::utils::RwLockReadGuard;
19
20#[cfg(feature = "hot-reloading")]
21unsafe fn swap_any(a: &mut dyn Any, b: &mut dyn Any) {
22    debug_assert_eq!((a as &dyn Any).type_id(), (b as &dyn Any).type_id());
23    debug_assert_eq!(
24        std::alloc::Layout::for_value(a),
25        std::alloc::Layout::for_value(b)
26    );
27
28    let len = std::mem::size_of_val(a);
29    unsafe {
30        std::ptr::swap_nonoverlapping(
31            a as *mut dyn Any as *mut u8,
32            b as *mut dyn Any as *mut u8,
33            len,
34        );
35    }
36}
37
38#[allow(dead_code)]
39pub(crate) struct Dynamic {
40    typ: &'static Type,
41
42    lock: RwLock<()>,
43    reload_global: AtomicBool,
44    reload: AtomicReloadId,
45}
46
47/// A handle on an asset.
48///
49/// It can be obtained through an [`AssetCache`].
50///
51/// If feature `hot-reloading` is used, this structure may wrap a `RwLock`, so
52/// assets can be written to be reloaded. As such, any number of read guard can
53/// exist at the same time, but none can exist while reloading an asset.
54///
55/// You can use this structure to reference an asset directly. However you can
56/// only get *references* to this type, never own it. If you don't want to deal
57/// with lifetimes, you can:
58/// - Get a `&'static AssetCache` (eg with a `static` `LazyLock`), to get a
59///   `'static` `Handle` refernce.
60/// - Store the id of the asset and get it from the cache as needed.
61/// - Get a [`ArcHandle`] through [`strong`] method.
62///
63/// [`AssetCache`]: `crate::AssetCache`
64/// [`strong`]: `Self::strong`
65pub struct Handle<T: ?Sized> {
66    id: SharedString,
67    type_id: TypeId,
68    #[cfg(feature = "hot-reloading")]
69    dynamic: Option<Dynamic>,
70    value: UnsafeCell<T>,
71}
72
73unsafe impl<T: Sync + ?Sized> Sync for Handle<T> {}
74
75impl<T: Storable> Handle<T> {
76    fn new_static(id: SharedString, value: T) -> Self {
77        Self {
78            id,
79            type_id: TypeId::of::<T>(),
80            #[cfg(feature = "hot-reloading")]
81            dynamic: None,
82            value: UnsafeCell::new(value),
83        }
84    }
85
86    #[cfg(feature = "hot-reloading")]
87    fn new_dynamic(id: SharedString, value: T) -> Self
88    where
89        T: Asset,
90    {
91        Self {
92            id,
93            type_id: TypeId::of::<T>(),
94            dynamic: Some(Dynamic {
95                typ: Type::of_asset::<T>(),
96                lock: RwLock::new(()),
97                reload_global: AtomicBool::new(false),
98                reload: AtomicReloadId::new(),
99            }),
100            value: UnsafeCell::new(value),
101        }
102    }
103}
104
105impl UntypedHandle {
106    #[cfg(feature = "hot-reloading")]
107    pub(crate) fn write(&self, mut value: CacheEntry) {
108        assert!(self.type_id == value.0.type_id);
109
110        let Some(d) = &self.dynamic else {
111            wrong_handle_type();
112        };
113        let storage = Arc::get_mut(&mut value.0).unwrap();
114
115        unsafe {
116            let _g = d.lock.write();
117            swap_any(&mut *self.value.get(), storage.value.get_mut());
118            d.reload.increment();
119            d.reload_global.store(true, Ordering::Release);
120        }
121    }
122}
123
124/// An entry in the cache.
125pub(crate) struct CacheEntry(Arc<UntypedHandle>);
126
127impl CacheEntry {
128    /// Creates a new `CacheEntry` containing an asset of type `T`.
129    ///
130    /// The returned structure can safely use its methods with type parameter `T`.
131    #[inline]
132    pub fn new<T: Asset>(asset: T, id: SharedString, _mutable: bool) -> Self {
133        #[cfg(not(feature = "hot-reloading"))]
134        let inner = Handle::new_static(id, asset);
135
136        // Even if hot-reloading is enabled, we can avoid the lock in some cases.
137        #[cfg(feature = "hot-reloading")]
138        let inner = if T::HOT_RELOADED && _mutable {
139            Handle::new_dynamic(id, asset)
140        } else {
141            Handle::new_static(id, asset)
142        };
143
144        CacheEntry(Arc::new(inner))
145    }
146
147    /// Creates a new `CacheEntry` containing a value of type `T`.
148    ///
149    /// The returned structure can safely use its methods with type parameter `T`.
150    #[inline]
151    pub fn new_any<T: Storable>(value: T, id: SharedString) -> Self {
152        CacheEntry(Arc::new(Handle::new_static(id, value)))
153    }
154
155    #[inline]
156    pub(crate) fn as_key(&self) -> (TypeId, &str) {
157        (self.0.type_id, &self.0.id)
158    }
159
160    /// Returns a reference on the inner storage of the entry.
161    #[inline]
162    pub(crate) fn inner(&self) -> &UntypedHandle {
163        &self.0
164    }
165}
166
167impl fmt::Debug for CacheEntry {
168    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169        f.debug_struct("CacheEntry")
170            .field("id", &self.0.id)
171            .field("type_id", &self.0.type_id)
172            .finish()
173    }
174}
175
176/// A untyped handle on an asset.
177///
178/// This is an type-erased version of [`Handle`].
179/// As with `dyn Any`, the underlying type can be queried at runtime.
180pub type UntypedHandle = Handle<dyn Any + Send + Sync>;
181
182impl UntypedHandle {
183    #[inline]
184    pub(crate) unsafe fn extend_lifetime<'a>(&self) -> &'a UntypedHandle {
185        unsafe { &*(self as *const Self) }
186    }
187
188    /// Gets the `TypeId` of the underlying type.
189    #[inline]
190    pub fn type_id(&self) -> TypeId {
191        self.type_id
192    }
193
194    /// Returns `true` if the inner type is the same as T.
195    #[inline]
196    pub fn is<T: 'static>(&self) -> bool {
197        self.type_id == TypeId::of::<T>()
198    }
199
200    /// Returns a handle to the asset if it is of type `T`.
201    #[inline]
202    pub fn downcast_ref<T: Storable>(&self) -> Option<&Handle<T>> {
203        if self.is::<T>() {
204            unsafe { Some(&*(self as *const Self as *const Handle<T>)) }
205        } else {
206            None
207        }
208    }
209
210    /// Like `downcast_ref`, but panics in the wrong type is given.
211    #[inline]
212    pub(crate) fn downcast_ref_ok<T: Storable>(&self) -> &Handle<T> {
213        match self.downcast_ref() {
214            Some(h) => h,
215            None => wrong_handle_type(),
216        }
217    }
218}
219
220impl<T: ?Sized> Handle<T> {
221    #[inline]
222    fn either<'a, U>(
223        &'a self,
224        on_static: impl FnOnce() -> U,
225        _on_dynamic: impl FnOnce(&'a Dynamic) -> U,
226    ) -> U {
227        #[cfg(feature = "hot-reloading")]
228        if let Some(d) = &self.dynamic {
229            return _on_dynamic(d);
230        }
231
232        on_static()
233    }
234
235    /// Locks the pointed asset for reading.
236    ///
237    /// If hot-reloading is disabled for `T` or globally, no reloading can occur
238    /// so there is no actual lock. In these cases, calling this function does
239    /// not involve synchronisation.
240    ///
241    /// Returns a RAII guard which will release the lock once dropped.
242    #[inline]
243    pub fn read(&self) -> AssetReadGuard<'_, T> {
244        #[cfg(feature = "hot-reloading")]
245        let guard = self.dynamic.as_ref().map(|d| d.lock.read());
246
247        AssetReadGuard {
248            value: unsafe { &*self.value.get() },
249            #[cfg(feature = "hot-reloading")]
250            guard,
251        }
252    }
253
254    /// Returns the id of the asset.
255    #[inline]
256    pub fn id(&self) -> &SharedString {
257        &self.id
258    }
259
260    #[cfg(feature = "hot-reloading")]
261    #[inline]
262    pub(crate) fn typ(&self) -> Option<&'static Type> {
263        self.either(|| None, |d| Some(d.typ))
264    }
265
266    /// Returns an untyped version of the handle.
267    #[inline]
268    pub fn as_untyped(&self) -> &UntypedHandle
269    where
270        T: Storable,
271    {
272        self
273    }
274
275    #[inline]
276    fn as_arc(&self) -> ManuallyDrop<Arc<Handle<T>>> {
277        // Safety: a `Handle<T>` is always in a `Arc`
278        unsafe { ManuallyDrop::new(Arc::from_raw(self)) }
279    }
280
281    /// Make a `ArcHandle` that points to this handle.
282    #[inline]
283    pub fn strong(&self) -> ArcHandle<T> {
284        ArcHandle(Arc::clone(&self.as_arc()))
285    }
286
287    /// Make a `WeakHandle` that points to this handle.
288    #[inline]
289    pub fn weak(&self) -> WeakHandle<T> {
290        WeakHandle(Arc::downgrade(&self.as_arc()))
291    }
292
293    /// Gets the number of strong ([`ArcHandle`]) pointers to this allocation.
294    #[inline]
295    pub fn strong_count(&self) -> usize {
296        Arc::strong_count(&self.as_arc())
297    }
298
299    /// Gets the number of [`WeakHandle`] pointers to this allocation.
300    #[inline]
301    pub fn weak_count(&self) -> usize {
302        Arc::weak_count(&self.as_arc())
303    }
304
305    /// Returns a `ReloadWatcher` that can be used to check whether this asset
306    /// was reloaded.
307    ///
308    /// # Example
309    ///
310    /// ```no_run
311    /// # cfg_if::cfg_if! { if #[cfg(feature = "hot-reloading")] {
312    /// use assets_manager::{AssetCache, ReloadWatcher};
313    ///
314    /// let cache = AssetCache::new("assets")?;
315    /// let asset = cache.load::<String>("common.some_text")?;
316    /// let mut watcher = asset.reload_watcher();
317    ///
318    /// // The handle has just been created, so `reloaded` returns false
319    /// assert!(!watcher.reloaded());
320    ///
321    /// loop {
322    ///     if watcher.reloaded() {
323    ///         println!("The asset was reloaded !")
324    ///     }
325    /// }
326    ///
327    /// # }}
328    /// # Ok::<_, Box<dyn std::error::Error>>(())
329    /// ```
330    #[inline]
331    pub fn reload_watcher(&self) -> ReloadWatcher<'_> {
332        ReloadWatcher::new(self.either(|| None, |d| Some(&d.reload)))
333    }
334
335    /// Returns the last `ReloadId` associated with this asset.
336    ///
337    /// It is only meaningful when compared to other `ReloadId`s returned by the
338    /// same handle or to [`ReloadId::NEVER`].
339    #[inline]
340    pub fn last_reload_id(&self) -> ReloadId {
341        self.either(|| ReloadId::NEVER, |this| this.reload.load())
342    }
343
344    /// Returns `true` if the asset has been reloaded since last call to this
345    /// method with **any** handle on this asset.
346    ///
347    /// Note that this method and [`reload_watcher`] are totally independant,
348    /// and the result of the two functions do not depend on whether the other
349    /// was called.
350    ///
351    /// [`reload_watcher`]: Self::reload_watcher
352    #[deprecated = "store and compare the result of `self.last_reload_id()` instead"]
353    #[inline]
354    pub fn reloaded_global(&self) -> bool {
355        self.either(
356            || false,
357            |this| this.reload_global.swap(false, Ordering::Acquire),
358        )
359    }
360}
361
362impl<T> Handle<T>
363where
364    T: Copy,
365{
366    /// Returns a copy of the inner asset.
367    ///
368    /// This is functionnally equivalent to `cloned`, but it ensures that no
369    /// expensive operation is used (eg if a type is refactored).
370    #[inline]
371    pub fn copied(&self) -> T {
372        *self.read()
373    }
374}
375
376impl<T> Handle<T>
377where
378    T: Clone,
379{
380    /// Returns a clone of the inner asset.
381    #[inline]
382    pub fn cloned(&self) -> T {
383        self.read().clone()
384    }
385}
386
387impl<T> fmt::Debug for Handle<T>
388where
389    T: fmt::Debug + ?Sized,
390{
391    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
392        f.debug_struct("Handle")
393            .field("id", self.id())
394            .field("value", &&*self.read())
395            .finish()
396    }
397}
398
399/// A strong pointer to a handle.
400///
401/// Like a [`Arc`]`<`[`Handle`]`<T>>`, it deref to [`Handle`]`<T>`, can be
402/// cloned and can be downgraded to [`WeakHandle`]`<T>`.
403pub struct ArcHandle<T: ?Sized>(Arc<Handle<T>>);
404
405impl ArcUntypedHandle {
406    /// Attempt to downcast the handle to a concrete type.
407    #[inline]
408    pub fn downcast<T: 'static>(self) -> Result<ArcHandle<T>, Self> {
409        if self.is::<T>() {
410            unsafe {
411                Ok(ArcHandle(Arc::from_raw(
412                    Arc::into_raw(self.0) as *mut Handle<T>
413                )))
414            }
415        } else {
416            Err(self)
417        }
418    }
419}
420
421impl<T: ?Sized> Clone for ArcHandle<T> {
422    #[inline]
423    fn clone(&self) -> Self {
424        Self(self.0.clone())
425    }
426}
427
428impl<T: ?Sized> Deref for ArcHandle<T> {
429    type Target = Handle<T>;
430
431    #[inline]
432    fn deref(&self) -> &Handle<T> {
433        &self.0
434    }
435}
436
437impl<T> fmt::Debug for ArcHandle<T>
438where
439    T: fmt::Debug + ?Sized,
440{
441    #[inline]
442    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
443        (**self).fmt(f)
444    }
445}
446
447/// A weak pointer to a handle.
448///
449/// Like a [`Weak`]`<`[`Handle`]`<T>>`, it can be upgraded to an
450/// [`ArcHandle`]`<T>`.
451pub struct WeakHandle<T: ?Sized>(Weak<Handle<T>>);
452
453impl<T> WeakHandle<T> {
454    /// Constructs a new `WeakHandle<T>`, without allocating any memory.
455    /// Calling [`upgrade`] on the return value always gives `None`.
456    ///
457    /// [`upgrade`]: WeakHandle::upgrade
458    #[inline]
459    pub const fn new() -> Self {
460        Self(Weak::new())
461    }
462}
463
464impl<T: ?Sized> WeakHandle<T> {
465    /// Attempts to upgrade the `WeakHandle` to an `ArcHandle`.
466    ///
467    /// Returns `None` if the inner value has since been dropped.
468    ///
469    /// This is similar to [`Weak::upgrade`].
470    #[inline]
471    pub fn upgrade(&self) -> Option<ArcHandle<T>> {
472        let arc = self.0.upgrade()?;
473        Some(ArcHandle(arc))
474    }
475
476    /// Gets the number of strong (`Arc`) pointers pointing to this allocation.
477    ///
478    /// If `self` was created using [`WeakHandle::new`], this will return 0.
479    #[inline]
480    pub fn strong_count(&self) -> usize {
481        Weak::strong_count(&self.0)
482    }
483
484    /// Gets an approximation of the number of `Weak` pointers pointing to this
485    /// allocation.
486    ///
487    /// If `self` was created using [`WeakHandle::new`], or if there are no remaining
488    /// strong pointers, this will return 0.
489    #[inline]
490    pub fn weak_count(&self) -> usize {
491        Weak::weak_count(&self.0)
492    }
493}
494
495impl<T> Default for WeakHandle<T> {
496    fn default() -> Self {
497        Self::new()
498    }
499}
500
501impl<T: ?Sized> Clone for WeakHandle<T> {
502    #[inline]
503    fn clone(&self) -> Self {
504        Self(self.0.clone())
505    }
506}
507
508impl<T: ?Sized> fmt::Debug for WeakHandle<T> {
509    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
510        f.write_str("(WeakHandle)")
511    }
512}
513
514/// An untyped version of [`ArcHandle`].
515pub type ArcUntypedHandle = ArcHandle<dyn Any + Send + Sync>;
516/// An untyped version of [`WeakHandle`].
517pub type WeakUntypedHandle = WeakHandle<dyn Any + Send + Sync>;
518
519/// RAII guard used to keep a read lock on an asset and release it when dropped.
520///
521/// This type is a smart pointer to type `T`.
522///
523/// It can be obtained by calling [`Handle::read`].
524pub struct AssetReadGuard<'a, T: ?Sized> {
525    value: &'a T,
526
527    #[cfg(feature = "hot-reloading")]
528    guard: Option<RwLockReadGuard<'a, ()>>,
529}
530
531impl<'a, T: ?Sized> AssetReadGuard<'a, T> {
532    /// Make a new `AssetReadGuard` for a component of the locked data.
533    pub fn map<U: ?Sized, F>(this: Self, f: F) -> AssetReadGuard<'a, U>
534    where
535        F: FnOnce(&T) -> &U,
536    {
537        AssetReadGuard {
538            value: f(this.value),
539            #[cfg(feature = "hot-reloading")]
540            guard: this.guard,
541        }
542    }
543
544    /// Attempts to make a new `AssetReadGuard` for a component of the locked data.
545    ///
546    /// Returns the original guard if the closure returns None.
547    pub fn try_map<U: ?Sized, F>(this: Self, f: F) -> Result<AssetReadGuard<'a, U>, Self>
548    where
549        F: FnOnce(&T) -> Option<&U>,
550    {
551        match f(this.value) {
552            Some(value) => Ok(AssetReadGuard {
553                value,
554                #[cfg(feature = "hot-reloading")]
555                guard: this.guard,
556            }),
557            None => Err(this),
558        }
559    }
560}
561
562impl<'a> AssetReadGuard<'a, dyn Any> {
563    /// Attempt to downcast the guard to a concrete type.
564    pub fn downcast<T: Any>(self) -> Result<AssetReadGuard<'a, T>, Self> {
565        Self::try_map(self, |x| x.downcast_ref())
566    }
567}
568
569impl<'a> AssetReadGuard<'a, dyn Any + Send> {
570    /// Attempt to downcast the guard to a concrete type.
571    pub fn downcast<T: Any>(self) -> Result<AssetReadGuard<'a, T>, Self> {
572        Self::try_map(self, |x| x.downcast_ref())
573    }
574}
575
576impl<'a> AssetReadGuard<'a, dyn Any + Send + Sync> {
577    /// Attempt to downcast the guard to a concrete type.
578    pub fn downcast<T: Any>(self) -> Result<AssetReadGuard<'a, T>, Self> {
579        Self::try_map(self, |x| x.downcast_ref())
580    }
581}
582
583impl<T: ?Sized> Deref for AssetReadGuard<'_, T> {
584    type Target = T;
585
586    #[inline]
587    fn deref(&self) -> &T {
588        self.value
589    }
590}
591
592impl<T, U> AsRef<U> for AssetReadGuard<'_, T>
593where
594    T: AsRef<U> + ?Sized,
595{
596    #[inline]
597    fn as_ref(&self) -> &U {
598        (**self).as_ref()
599    }
600}
601
602impl<T> fmt::Display for AssetReadGuard<'_, T>
603where
604    T: fmt::Display + ?Sized,
605{
606    #[inline]
607    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
608        fmt::Display::fmt(&**self, f)
609    }
610}
611
612impl<T> fmt::Debug for AssetReadGuard<'_, T>
613where
614    T: fmt::Debug + ?Sized,
615{
616    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
617        fmt::Debug::fmt(&**self, f)
618    }
619}
620
621#[cfg(feature = "hot-reloading")]
622#[derive(Debug, Clone, Copy)]
623struct ReloadWatcherInner<'a> {
624    reload_id: &'a AtomicReloadId,
625    last_reload_id: ReloadId,
626}
627
628#[cfg(feature = "hot-reloading")]
629impl<'a> ReloadWatcherInner<'a> {
630    #[inline]
631    fn new(reload_id: &'a AtomicReloadId) -> Self {
632        Self {
633            reload_id,
634            last_reload_id: reload_id.load(),
635        }
636    }
637}
638
639/// A watcher that can tell when an asset is reloaded.
640///
641/// Each `ReloadWatcher` is associated to a single asset in a cache.
642///
643/// It can be obtained with [`Handle::reload_watcher`].
644#[derive(Debug, Clone, Copy)]
645pub struct ReloadWatcher<'a> {
646    #[cfg(feature = "hot-reloading")]
647    inner: Option<ReloadWatcherInner<'a>>,
648    _private: PhantomData<&'a ()>,
649}
650
651impl<'a> ReloadWatcher<'a> {
652    #[inline]
653    fn new(_reload_id: Option<&'a AtomicReloadId>) -> Self {
654        #[cfg(feature = "hot-reloading")]
655        let inner = _reload_id.map(ReloadWatcherInner::new);
656        Self {
657            #[cfg(feature = "hot-reloading")]
658            inner,
659            _private: PhantomData,
660        }
661    }
662
663    /// Returns `true` if the watched asset was reloaded since the last call to
664    /// this function.
665    #[inline]
666    pub fn reloaded(&mut self) -> bool {
667        #[cfg(feature = "hot-reloading")]
668        if let Some(inner) = &mut self.inner {
669            let new_id = inner.reload_id.load();
670            return inner.last_reload_id.update(new_id);
671        }
672
673        false
674    }
675
676    /// Returns the last `ReloadId` associated with this asset.
677    #[inline]
678    pub fn last_reload_id(&self) -> ReloadId {
679        #[cfg(feature = "hot-reloading")]
680        if let Some(inner) = &self.inner {
681            return inner.reload_id.load();
682        }
683
684        ReloadId::NEVER
685    }
686}
687
688impl Default for ReloadWatcher<'_> {
689    /// Returns a `ReloadWatcher` that never gets updated.
690    #[inline]
691    fn default() -> Self {
692        Self::new(None)
693    }
694}
695
696/// An id to know when an asset is reloaded.
697///
698/// Each time an asset is reloaded, it gets a new `ReloadId` that compares
699/// superior to the previous one.
700///
701/// `ReloadId`s are only meaningful when compared to other `ReloadId`s returned
702/// by the same handle or to [`ReloadId::NEVER`].
703///
704/// They are useful when you cannot afford the associated lifetime of a
705/// [`ReloadWatcher`]. In this case, you may be interested in using an
706/// [`AtomicReloadId`].
707#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
708pub struct ReloadId(usize);
709
710impl ReloadId {
711    /// A `ReloadId` for values that were never updated.
712    pub const NEVER: Self = Self(0);
713
714    /// Updates `self` if the argument if the argument is newer. Returns `true`
715    /// if `self` was updated.
716    #[inline]
717    pub fn update(&mut self, new: ReloadId) -> bool {
718        let newer = new > *self;
719        if newer {
720            *self = new;
721        }
722        newer
723    }
724}
725
726impl Default for ReloadId {
727    #[inline]
728    fn default() -> Self {
729        Self::NEVER
730    }
731}
732
733/// A [`ReloadId`] that can be shared between threads.
734///
735/// This type is useful when one cannot afford the associated lifetime of
736/// [`ReloadWatcher`] and is cheaper than a `Mutex<ReloadId>`.
737///
738/// `update` method is enough to satisfy most needs, but this type exposes more
739/// primitive operations too.
740#[derive(Debug)]
741pub struct AtomicReloadId(AtomicUsize);
742
743impl AtomicReloadId {
744    /// Creates a new atomic `ReloadId`.
745    #[inline]
746    pub const fn new() -> Self {
747        Self::with_value(ReloadId::NEVER)
748    }
749
750    /// Creates a new atomic `ReloadId`, initialized with the given value.
751    #[inline]
752    pub const fn with_value(value: ReloadId) -> Self {
753        Self(AtomicUsize::new(value.0))
754    }
755
756    /// Updates `self` if the argument if the argument is newer. Returns `true`
757    /// if `self` was updated.
758    #[inline]
759    pub fn update(&self, new: ReloadId) -> bool {
760        new > self.fetch_max(new)
761    }
762
763    /// Loads the inner `ReloadId`.
764    #[inline]
765    pub fn load(&self) -> ReloadId {
766        ReloadId(self.0.load(Ordering::Acquire))
767    }
768
769    /// Stores a `ReloadId`.
770    #[inline]
771    pub fn store(&self, new: ReloadId) {
772        self.0.store(new.0, Ordering::Release)
773    }
774
775    #[inline]
776    #[cfg(feature = "hot-reloading")]
777    fn increment(&self) {
778        self.0.fetch_add(1, Ordering::Release);
779    }
780
781    /// Stores a `ReloadId`, returning the previous one.
782    #[inline]
783    pub fn swap(&self, new: ReloadId) -> ReloadId {
784        ReloadId(self.0.swap(new.0, Ordering::AcqRel))
785    }
786
787    /// Stores the maximum of the two `ReloadId`, returning the previous one.
788    #[inline]
789    pub fn fetch_max(&self, new: ReloadId) -> ReloadId {
790        ReloadId(self.0.fetch_max(new.0, Ordering::AcqRel))
791    }
792}
793
794impl Default for AtomicReloadId {
795    #[inline]
796    fn default() -> Self {
797        Self::new()
798    }
799}
800
801#[cold]
802#[track_caller]
803fn wrong_handle_type() -> ! {
804    panic!("wrong handle type");
805}