Skip to main content

extendable_assets/asset/
mod.rs

1mod data;
2mod id;
3mod serialize;
4
5pub use data::*;
6pub use id::*;
7pub use serialize::*;
8
9use std::sync::Weak;
10
11use crate::asset_type::AssetType;
12use crate::loader::AssetLoadError;
13use crate::manager::AssetManager;
14
15/// Errors that can occur during asset operations.
16///
17/// This enum represents all possible errors that can happen when working with assets,
18/// including loading, type resolution, and general asset manipulation.
19#[derive(Debug, thiserror::Error)]
20#[non_exhaustive]
21pub enum AssetError {
22    /// Error occurred during asset loading from bytes.
23    ///
24    /// This variant wraps loader-specific errors that can happen when attempting
25    /// to deserialize asset data from raw bytes using an asset type's loader.
26    #[error("Error loading asset data from bytes: {0}")]
27    Loader(#[from] AssetLoadError),
28
29    /// The asset type reference has been dropped and is no longer available.
30    ///
31    /// This error occurs when trying to access an asset type through a weak reference
32    /// that can no longer be upgraded because the asset type has been dropped from memory.
33    #[error("A weak pointer to an AssetType could not be upgraded")]
34    TypeDropped,
35
36    /// The specified asset type could not be found in the asset manager.
37    ///
38    /// This error occurs when attempting to look up an asset type by name that
39    /// is not registered in the asset manager.
40    #[error("Asset type was not found: {0}")]
41    TypeNotFound(String),
42
43    /// Any other error that doesn't fit into the specific categories above.
44    ///
45    /// This is a catch-all variant for wrapping other error types that may
46    /// occur during asset operations.
47    #[error(transparent)]
48    Other(#[from] anyhow::Error),
49}
50
51/// An asset containing type information and data.
52///
53/// Assets are the core data containers in the asset system. Each asset has
54/// a unique ID, an asset type that defines how to load and save it, and the
55/// actual data payload.
56pub struct Asset {
57    /// Unique identifier for this asset
58    id: AssetId,
59    /// Type definition that specifies how to handle this asset
60    asset_type: Weak<dyn AssetType>,
61    /// The actual asset data
62    data: Box<dyn AssetData>,
63}
64impl Asset {
65    /// Creates a new asset with the given type and data.
66    ///
67    /// The asset ID is initially set to 0 and will be assigned by the asset manager when the asset is registered.
68    ///
69    /// # Arguments
70    ///
71    /// * `asset_type` - The type definition for this asset
72    /// * `data` - The actual asset data
73    #[inline]
74    pub fn new(asset_type: Weak<dyn AssetType>, data: Box<dyn AssetData>) -> Self {
75        Self {
76            // ID will be set by the asset manager during registration
77            id: AssetId::from(0),
78            asset_type,
79            data,
80        }
81    }
82    /// Creates an asset from a serialized representation.
83    ///
84    /// This method reconstructs an asset from its serialized form by looking up
85    /// the asset type from the manager and deserializing the data using the
86    /// appropriate loader.
87    ///
88    /// # Arguments
89    ///
90    /// * `mgr` - The asset manager to use for type lookup
91    /// * `serialized` - The serialized asset data
92    ///
93    /// # Returns
94    ///
95    /// `Ok(Asset)` if deserialization succeeds, `Err(AssetError)` if the asset type
96    /// is not found or deserialization fails.
97    pub fn from_serialized(
98        mgr: &AssetManager,
99        serialized: SerializedAsset,
100    ) -> Result<Self, AssetError> {
101        // Extract the asset ID from serialized data
102        let id = serialized.id;
103        // Look up the asset type by name in the manager
104        let asset_type = mgr
105            .asset_type_by_name(&serialized.asset_type)
106            .ok_or_else(|| AssetError::TypeNotFound(serialized.asset_type))?;
107        // Upgrade the weak reference to ensure the asset type is still valid
108        let asset_type_ptr = asset_type.upgrade().ok_or(AssetError::TypeDropped)?;
109        // Get the serialized data bytes
110        let decompressed_data;
111        let data_bytes = if let Some(compression_mode) = serialized.data.compression_mode() {
112            decompressed_data = compression_mode
113                .decompress(serialized.data.data())
114                .ok_or_else(|| {
115                    AssetError::Other(anyhow::anyhow!("Failed to decompress asset data"))
116                })?;
117            &decompressed_data
118        } else {
119            serialized.data.data()
120        };
121        // Use the asset type's loader to deserialize the data
122        let data = asset_type_ptr
123            .loader()
124            .asset_from_bytes(data_bytes, mgr.context())
125            .map_err(AssetError::from)?;
126        Ok(Self {
127            id,
128            asset_type,
129            data,
130        })
131    }
132    /// Returns the unique identifier for this asset.
133    #[inline]
134    pub fn id(&self) -> AssetId {
135        self.id
136    }
137    /// Sets the asset's unique identifier.
138    ///
139    /// This is only used internally by the asset manager during registration.
140    #[inline]
141    pub(crate) fn set_id(&mut self, new_id: AssetId) {
142        self.id = new_id;
143    }
144    /// Returns a clone of the asset type definition.
145    #[inline]
146    pub fn asset_type(&self) -> Weak<dyn AssetType> {
147        Weak::clone(&self.asset_type)
148    }
149    /// Returns a reference to the asset's data.
150    ///
151    /// The data can be downcast to the specific type using the downcast methods
152    /// provided by the `DowncastSync` super-trait.
153    #[inline]
154    pub fn data(&self) -> &dyn AssetData {
155        self.data.as_ref()
156    }
157}