Skip to main content

euv_engine/asset/
struct.rs

1use super::*;
2
3/// An entry in the asset cache containing the loaded data and its state.
4#[derive(Clone, Data, Debug, New, PartialEq)]
5pub struct AssetEntry {
6    /// The type of this asset.
7    #[get(pub(crate), type(copy))]
8    #[get_mut(pub(crate))]
9    #[set(pub(crate))]
10    pub(crate) asset_type: AssetType,
11    /// The current loading state.
12    #[get(type(copy))]
13    #[get_mut(pub(crate))]
14    pub(crate) state: AssetState,
15    /// The loaded image element, if this is an image asset.
16    #[get(type(clone))]
17    #[get_mut(pub(crate))]
18    #[set(pub(crate))]
19    pub(crate) image: Option<HtmlImageElement>,
20    /// The URL this asset was loaded from.
21    #[get_mut(pub(crate))]
22    #[set(pub(crate))]
23    pub(crate) url: String,
24}
25
26/// A cache for storing loaded game assets, keyed by URL.
27#[derive(Clone, Data, Debug, New, PartialEq)]
28pub struct AssetCache {
29    /// All cached assets keyed by their source URL.
30    #[get_mut(pub(crate))]
31    #[set(pub(crate))]
32    #[new(skip)]
33    pub(crate) entries: HashMap<String, AssetEntry>,
34}
35
36/// An asynchronous asset loader that fetches resources over HTTP
37/// and populates a shared `AssetCache`.
38#[derive(Clone, Data, New)]
39pub struct AssetLoader {
40    /// The shared cache that loaded assets are stored into.
41    #[new(skip)]
42    #[get(pub(crate))]
43    #[get_mut(pub(crate))]
44    #[set(pub(crate))]
45    pub(crate) cache: Rc<EngineCell<AssetCache>>,
46    /// The shared counter of loads that have been requested but have not
47    /// settled yet. Read through [`AssetLoader::pending_count`].
48    #[new(skip)]
49    #[get_mut(pub(crate))]
50    #[set(pub(crate))]
51    pub(crate) pending: AssetPending,
52    /// Stored closures keeping `onload`/`onerror` callbacks alive, preventing memory leaks.
53    #[new(skip)]
54    #[get_mut(pub(crate))]
55    #[set(pub(crate))]
56    pub(crate) closures: AssetClosures,
57}
58
59/// The backing store behind [`AssetClosures`].
60///
61/// Slots are appended in pairs by [`AssetLoader::load_image`] — even indices
62/// hold an `onload` closure, odd indices the matching `onerror` closure — so
63/// a callback can identify its own slot with one captured index.
64///
65/// The fields are public because the type is reachable from the public
66/// [`AssetClosures`] alias: a private-field type exposed through a public
67/// alias would be unusable to callers, and the retained-slot count is
68/// genuinely useful as a leak diagnostic.
69#[derive(Debug, Default)]
70pub struct AssetClosureStore {
71    /// The load callbacks, in registration order. A `None` slot is one that
72    /// has already been released by [`AssetLoader::collect`].
73    pub slots: Vec<Option<Closure<dyn FnMut()>>>,
74    /// Whether the closure in the slot at the same index has run. A settled
75    /// closure cannot free itself (see [`AssetClosures`]) but is no longer
76    /// keeping anything alive that the cache still needs.
77    pub settled: Vec<bool>,
78}