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