1use 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
47pub 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
124pub(crate) struct CacheEntry(Arc<UntypedHandle>);
126
127impl CacheEntry {
128 #[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 #[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 #[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 #[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
176pub 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 #[inline]
190 pub fn type_id(&self) -> TypeId {
191 self.type_id
192 }
193
194 #[inline]
196 pub fn is<T: 'static>(&self) -> bool {
197 self.type_id == TypeId::of::<T>()
198 }
199
200 #[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 #[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 #[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 #[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 #[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 unsafe { ManuallyDrop::new(Arc::from_raw(self)) }
279 }
280
281 #[inline]
283 pub fn strong(&self) -> ArcHandle<T> {
284 ArcHandle(Arc::clone(&self.as_arc()))
285 }
286
287 #[inline]
289 pub fn weak(&self) -> WeakHandle<T> {
290 WeakHandle(Arc::downgrade(&self.as_arc()))
291 }
292
293 #[inline]
295 pub fn strong_count(&self) -> usize {
296 Arc::strong_count(&self.as_arc())
297 }
298
299 #[inline]
301 pub fn weak_count(&self) -> usize {
302 Arc::weak_count(&self.as_arc())
303 }
304
305 #[inline]
331 pub fn reload_watcher(&self) -> ReloadWatcher<'_> {
332 ReloadWatcher::new(self.either(|| None, |d| Some(&d.reload)))
333 }
334
335 #[inline]
340 pub fn last_reload_id(&self) -> ReloadId {
341 self.either(|| ReloadId::NEVER, |this| this.reload.load())
342 }
343
344 #[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 #[inline]
371 pub fn copied(&self) -> T {
372 *self.read()
373 }
374}
375
376impl<T> Handle<T>
377where
378 T: Clone,
379{
380 #[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
399pub struct ArcHandle<T: ?Sized>(Arc<Handle<T>>);
404
405impl ArcUntypedHandle {
406 #[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
447pub struct WeakHandle<T: ?Sized>(Weak<Handle<T>>);
452
453impl<T> WeakHandle<T> {
454 #[inline]
459 pub const fn new() -> Self {
460 Self(Weak::new())
461 }
462}
463
464impl<T: ?Sized> WeakHandle<T> {
465 #[inline]
471 pub fn upgrade(&self) -> Option<ArcHandle<T>> {
472 let arc = self.0.upgrade()?;
473 Some(ArcHandle(arc))
474 }
475
476 #[inline]
480 pub fn strong_count(&self) -> usize {
481 Weak::strong_count(&self.0)
482 }
483
484 #[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
514pub type ArcUntypedHandle = ArcHandle<dyn Any + Send + Sync>;
516pub type WeakUntypedHandle = WeakHandle<dyn Any + Send + Sync>;
518
519pub 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 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 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 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 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 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#[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 #[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 #[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 #[inline]
691 fn default() -> Self {
692 Self::new(None)
693 }
694}
695
696#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
708pub struct ReloadId(usize);
709
710impl ReloadId {
711 pub const NEVER: Self = Self(0);
713
714 #[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#[derive(Debug)]
741pub struct AtomicReloadId(AtomicUsize);
742
743impl AtomicReloadId {
744 #[inline]
746 pub const fn new() -> Self {
747 Self::with_value(ReloadId::NEVER)
748 }
749
750 #[inline]
752 pub const fn with_value(value: ReloadId) -> Self {
753 Self(AtomicUsize::new(value.0))
754 }
755
756 #[inline]
759 pub fn update(&self, new: ReloadId) -> bool {
760 new > self.fetch_max(new)
761 }
762
763 #[inline]
765 pub fn load(&self) -> ReloadId {
766 ReloadId(self.0.load(Ordering::Acquire))
767 }
768
769 #[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 #[inline]
783 pub fn swap(&self, new: ReloadId) -> ReloadId {
784 ReloadId(self.0.swap(new.0, Ordering::AcqRel))
785 }
786
787 #[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}