keket/fetch/
mod.rs

1pub mod collections;
2pub mod container;
3pub mod deferred;
4pub mod extract;
5pub mod fallback;
6pub mod file;
7pub mod future;
8#[cfg(feature = "hotreload")]
9pub mod hotreload;
10pub mod rewrite;
11pub mod router;
12pub mod throttled;
13
14use crate::database::{
15    events::{AssetEvent, AssetEventBindings, AssetEventKind},
16    handle::AssetHandle,
17    path::AssetPath,
18};
19use anput::{bundle::DynamicBundle, world::World};
20use std::error::Error;
21
22/// Marker type for assets that are awaiting resolution of their path.
23pub struct AssetAwaitsResolution;
24
25/// Represents raw byte data that is ready to be processed.
26#[derive(Debug, Default, Clone, PartialEq, Eq)]
27pub struct AssetBytesAreReadyToProcess(pub Vec<u8>);
28
29/// Marker component used to signify that the asset fetch for an asset is
30/// asynchronous and it's pending completion.
31pub struct AssetAwaitsAsyncFetch;
32
33/// Defines the interface for fetching asset data from an external source.
34pub trait AssetFetch: Send + Sync + 'static {
35    /// Loads the raw bytes of an asset given its path.
36    ///
37    /// # Arguments
38    /// - `path`: The path to the asset.
39    ///
40    /// # Returns
41    /// - A `DynamicBundle` containing the asset data or an error if loading fails.
42    fn load_bytes(&self, path: AssetPath) -> Result<DynamicBundle, Box<dyn Error>>;
43
44    /// Maintains the fetcher's state.
45    ///
46    /// Can be used for handling periodic or deferred operations.
47    ///
48    /// # Arguments
49    /// - `storage`: The world storage where asset state is maintained.
50    ///
51    /// # Returns
52    /// - `Ok(())` if maintenance succeeds, otherwise an error.
53    #[allow(unused_variables)]
54    fn maintain(&mut self, storage: &mut World) -> Result<(), Box<dyn Error>> {
55        Ok(())
56    }
57}
58
59pub(crate) struct AssetFetchEngine {
60    fetch: Box<dyn AssetFetch>,
61}
62
63impl AssetFetchEngine {
64    pub fn new(fetch: impl AssetFetch) -> Self {
65        Self {
66            fetch: Box::new(fetch),
67        }
68    }
69
70    pub fn into_inner(self) -> Box<dyn AssetFetch> {
71        self.fetch
72    }
73
74    pub fn load_bytes(
75        &self,
76        handle: AssetHandle,
77        path: AssetPath,
78        storage: &mut World,
79    ) -> Result<(), Box<dyn Error>> {
80        let result = self.fetch.load_bytes(path.clone());
81        if result.is_err()
82            && let Ok(mut bindings) =
83                storage.component_mut::<true, AssetEventBindings>(handle.entity())
84        {
85            bindings.dispatch(AssetEvent {
86                handle,
87                kind: AssetEventKind::BytesFetchingFailed,
88                path: path.into_static(),
89            })?;
90        }
91        storage.insert(handle.entity(), result?)?;
92        Ok(())
93    }
94
95    pub fn maintain(&mut self, storage: &mut World) -> Result<(), Box<dyn Error>> {
96        self.fetch.maintain(storage)
97    }
98}