bevy_asset/
event.rs

1use crate::{Asset, AssetId, AssetLoadError, AssetPath, UntypedAssetId};
2use bevy_ecs::event::Event;
3use std::fmt::Debug;
4
5/// An event emitted when a specific [`Asset`] fails to load.
6///
7/// For an untyped equivalent, see [`UntypedAssetLoadFailedEvent`].
8#[derive(Event, Clone, Debug)]
9pub struct AssetLoadFailedEvent<A: Asset> {
10    pub id: AssetId<A>,
11    /// The asset path that was attempted.
12    pub path: AssetPath<'static>,
13    /// Why the asset failed to load.
14    pub error: AssetLoadError,
15}
16
17impl<A: Asset> AssetLoadFailedEvent<A> {
18    /// Converts this to an "untyped" / "generic-less" asset error event that stores the type information.
19    pub fn untyped(&self) -> UntypedAssetLoadFailedEvent {
20        self.into()
21    }
22}
23
24/// An untyped version of [`AssetLoadFailedEvent`].
25#[derive(Event, Clone, Debug)]
26pub struct UntypedAssetLoadFailedEvent {
27    pub id: UntypedAssetId,
28    /// The asset path that was attempted.
29    pub path: AssetPath<'static>,
30    /// Why the asset failed to load.
31    pub error: AssetLoadError,
32}
33
34impl<A: Asset> From<&AssetLoadFailedEvent<A>> for UntypedAssetLoadFailedEvent {
35    fn from(value: &AssetLoadFailedEvent<A>) -> Self {
36        UntypedAssetLoadFailedEvent {
37            id: value.id.untyped(),
38            path: value.path.clone(),
39            error: value.error.clone(),
40        }
41    }
42}
43
44/// Events that occur for a specific loaded [`Asset`], such as "value changed" events and "dependency" events.
45#[derive(Event)]
46pub enum AssetEvent<A: Asset> {
47    /// Emitted whenever an [`Asset`] is added.
48    Added { id: AssetId<A> },
49    /// Emitted whenever an [`Asset`] value is modified.
50    Modified { id: AssetId<A> },
51    /// Emitted whenever an [`Asset`] is removed.
52    Removed { id: AssetId<A> },
53    /// Emitted when the last [`super::Handle::Strong`] of an [`Asset`] is dropped.
54    Unused { id: AssetId<A> },
55    /// Emitted whenever an [`Asset`] has been fully loaded (including its dependencies and all "recursive dependencies").
56    LoadedWithDependencies { id: AssetId<A> },
57}
58
59impl<A: Asset> AssetEvent<A> {
60    /// Returns `true` if this event is [`AssetEvent::LoadedWithDependencies`] and matches the given `id`.
61    pub fn is_loaded_with_dependencies(&self, asset_id: impl Into<AssetId<A>>) -> bool {
62        matches!(self, AssetEvent::LoadedWithDependencies { id } if *id == asset_id.into())
63    }
64
65    /// Returns `true` if this event is [`AssetEvent::Added`] and matches the given `id`.
66    pub fn is_added(&self, asset_id: impl Into<AssetId<A>>) -> bool {
67        matches!(self, AssetEvent::Added { id } if *id == asset_id.into())
68    }
69
70    /// Returns `true` if this event is [`AssetEvent::Modified`] and matches the given `id`.
71    pub fn is_modified(&self, asset_id: impl Into<AssetId<A>>) -> bool {
72        matches!(self, AssetEvent::Modified { id } if *id == asset_id.into())
73    }
74
75    /// Returns `true` if this event is [`AssetEvent::Removed`] and matches the given `id`.
76    pub fn is_removed(&self, asset_id: impl Into<AssetId<A>>) -> bool {
77        matches!(self, AssetEvent::Removed { id } if *id == asset_id.into())
78    }
79
80    /// Returns `true` if this event is [`AssetEvent::Unused`] and matches the given `id`.
81    pub fn is_unused(&self, asset_id: impl Into<AssetId<A>>) -> bool {
82        matches!(self, AssetEvent::Unused { id } if *id == asset_id.into())
83    }
84}
85
86impl<A: Asset> Clone for AssetEvent<A> {
87    fn clone(&self) -> Self {
88        *self
89    }
90}
91
92impl<A: Asset> Copy for AssetEvent<A> {}
93
94impl<A: Asset> Debug for AssetEvent<A> {
95    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96        match self {
97            Self::Added { id } => f.debug_struct("Added").field("id", id).finish(),
98            Self::Modified { id } => f.debug_struct("Modified").field("id", id).finish(),
99            Self::Removed { id } => f.debug_struct("Removed").field("id", id).finish(),
100            Self::Unused { id } => f.debug_struct("Unused").field("id", id).finish(),
101            Self::LoadedWithDependencies { id } => f
102                .debug_struct("LoadedWithDependencies")
103                .field("id", id)
104                .finish(),
105        }
106    }
107}
108
109impl<A: Asset> PartialEq for AssetEvent<A> {
110    fn eq(&self, other: &Self) -> bool {
111        match (self, other) {
112            (Self::Added { id: l_id }, Self::Added { id: r_id })
113            | (Self::Modified { id: l_id }, Self::Modified { id: r_id })
114            | (Self::Removed { id: l_id }, Self::Removed { id: r_id })
115            | (Self::Unused { id: l_id }, Self::Unused { id: r_id })
116            | (
117                Self::LoadedWithDependencies { id: l_id },
118                Self::LoadedWithDependencies { id: r_id },
119            ) => l_id == r_id,
120            _ => false,
121        }
122    }
123}
124
125impl<A: Asset> Eq for AssetEvent<A> {}