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}