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}