From 82252daf78e6389c8086e7c1b9dc582a59c15b54 Mon Sep 17 00:00:00 2001 From: Alex Kocharin Date: Thu, 9 Nov 2023 01:45:45 +0400 Subject: [PATCH] return type-erased Errors in AssetLoader::load this fixes https://github.com/bevyengine/bevy/issues/10350 Previous change made in https://github.com/bevyengine/bevy/pull/10003 resulted in inability for users to have ?Sized errors, which caused usability issues with crates like anyhow. --- crates/bevy_asset/src/lib.rs | 8 +++----- crates/bevy_asset/src/loader.rs | 20 +++++++------------ crates/bevy_asset/src/meta.rs | 3 +-- crates/bevy_asset/src/processor/process.rs | 4 ++-- crates/bevy_asset/src/saver.rs | 12 +++++------ crates/bevy_asset/src/server/mod.rs | 6 +++--- crates/bevy_audio/src/audio_source.rs | 5 ++--- crates/bevy_gltf/src/loader.rs | 5 ++--- .../bevy_render/src/render_resource/shader.rs | 3 +-- .../src/texture/hdr_texture_loader.rs | 3 +-- .../bevy_render/src/texture/image_loader.rs | 3 +-- crates/bevy_scene/src/scene_loader.rs | 3 +-- crates/bevy_text/src/font_loader.rs | 3 +-- examples/asset/custom_asset.rs | 3 +-- 14 files changed, 31 insertions(+), 50 deletions(-) diff --git a/crates/bevy_asset/src/lib.rs b/crates/bevy_asset/src/lib.rs index 9f9cd44c77b0dd..17ad7c5fc78979 100644 --- a/crates/bevy_asset/src/lib.rs +++ b/crates/bevy_asset/src/lib.rs @@ -89,7 +89,7 @@ pub enum AssetMode { /// /// When developing an app, you should enable the `asset_processor` cargo feature, which will run the asset processor at startup. This should generally /// be used in combination with the `file_watcher` cargo feature, which enables hot-reloading of assets that have changed. When both features are enabled, - /// changes to "original/source assets" will be detected, the asset will be re-processed, and then the final processed asset will be hot-reloaded in the app. + /// changes to "original/source assets" will be detected, the asset will be re-processed, and then the final processed asset will be hot-reloaded in the app. /// /// [`AssetMeta`]: crate::meta::AssetMeta /// [`AssetSource`]: crate::io::AssetSource @@ -459,14 +459,12 @@ mod tests { type Settings = (); - type Error = CoolTextLoaderError; - fn load<'a>( &'a self, reader: &'a mut Reader, _settings: &'a Self::Settings, load_context: &'a mut LoadContext, - ) -> BoxedFuture<'a, Result> { + ) -> BoxedFuture<'a, Result> { Box::pin(async move { let mut bytes = Vec::new(); reader.read_to_end(&mut bytes).await?; @@ -474,7 +472,7 @@ mod tests { let mut embedded = String::new(); for dep in ron.embedded_dependencies { let loaded = load_context.load_direct(&dep).await.map_err(|_| { - Self::Error::CannotLoadDependency { + CoolTextLoaderError::CannotLoadDependency { dependency: dep.into(), } })?; diff --git a/crates/bevy_asset/src/loader.rs b/crates/bevy_asset/src/loader.rs index 3a5bbc7d032aa9..9623ad061bc11d 100644 --- a/crates/bevy_asset/src/loader.rs +++ b/crates/bevy_asset/src/loader.rs @@ -20,6 +20,8 @@ use std::{ }; use thiserror::Error; +pub type Error = Box; + /// Loads an [`Asset`] from a given byte [`Reader`]. This can accept [`AssetLoader::Settings`], which configure how the [`Asset`] /// should be loaded. pub trait AssetLoader: Send + Sync + 'static { @@ -27,15 +29,13 @@ pub trait AssetLoader: Send + Sync + 'static { type Asset: crate::Asset; /// The settings type used by this [`AssetLoader`]. type Settings: Settings + Default + Serialize + for<'a> Deserialize<'a>; - /// The type of [error](`std::error::Error`) which could be encountered by this loader. - type Error: std::error::Error + Send + Sync + 'static; /// Asynchronously loads [`AssetLoader::Asset`] (and any other labeled assets) from the bytes provided by [`Reader`]. fn load<'a>( &'a self, reader: &'a mut Reader, settings: &'a Self::Settings, load_context: &'a mut LoadContext, - ) -> BoxedFuture<'a, Result>; + ) -> BoxedFuture<'a, Result>; /// Returns a list of extensions supported by this asset loader, without the preceding dot. fn extensions(&self) -> &[&str]; @@ -49,10 +49,7 @@ pub trait ErasedAssetLoader: Send + Sync + 'static { reader: &'a mut Reader, meta: Box, load_context: LoadContext<'a>, - ) -> BoxedFuture< - 'a, - Result>, - >; + ) -> BoxedFuture<'a, Result>; /// Returns a list of extensions supported by this asset loader, without the preceding dot. fn extensions(&self) -> &[&str]; @@ -80,10 +77,7 @@ where reader: &'a mut Reader, meta: Box, mut load_context: LoadContext<'a>, - ) -> BoxedFuture< - 'a, - Result>, - > { + ) -> BoxedFuture<'a, Result> { Box::pin(async move { let settings = meta .loader_settings() @@ -446,7 +440,7 @@ impl<'a> LoadContext<'a> { /// Retrieves a handle for the asset at the given path and adds that path as a dependency of the asset. /// If the current context is a normal [`AssetServer::load`], an actual asset load will be kicked off immediately, which ensures the load happens /// as soon as possible. - /// "Normal loads" kicked from within a normal Bevy App will generally configure the context to kick off loads immediately. + /// "Normal loads" kicked from within a normal Bevy App will generally configure the context to kick off loads immediately. /// If the current context is configured to not load dependencies automatically (ex: [`AssetProcessor`](crate::processor::AssetProcessor)), /// a load will not be kicked off automatically. It is then the calling context's responsibility to begin a load if necessary. pub fn load<'b, A: Asset>(&mut self, path: impl Into>) -> Handle { @@ -462,7 +456,7 @@ impl<'a> LoadContext<'a> { /// Loads the [`Asset`] of type `A` at the given `path` with the given [`AssetLoader::Settings`] settings `S`. This is a "deferred" /// load. If the settings type `S` does not match the settings expected by `A`'s asset loader, an error will be printed to the log - /// and the asset load will fail. + /// and the asset load will fail. pub fn load_with_settings<'b, A: Asset, S: Settings + Default>( &mut self, path: impl Into>, diff --git a/crates/bevy_asset/src/meta.rs b/crates/bevy_asset/src/meta.rs index dbcd7d7feb57dc..01574a3ff78801 100644 --- a/crates/bevy_asset/src/meta.rs +++ b/crates/bevy_asset/src/meta.rs @@ -193,13 +193,12 @@ impl VisitAssetDependencies for () { impl AssetLoader for () { type Asset = (); type Settings = (); - type Error = std::io::Error; fn load<'a>( &'a self, _reader: &'a mut crate::io::Reader, _settings: &'a Self::Settings, _load_context: &'a mut crate::LoadContext, - ) -> bevy_utils::BoxedFuture<'a, Result> { + ) -> bevy_utils::BoxedFuture<'a, Result> { unreachable!(); } diff --git a/crates/bevy_asset/src/processor/process.rs b/crates/bevy_asset/src/processor/process.rs index ef6a3fbb2f5c57..357ec1cc815bdc 100644 --- a/crates/bevy_asset/src/processor/process.rs +++ b/crates/bevy_asset/src/processor/process.rs @@ -107,7 +107,7 @@ pub enum ProcessError { #[error("The wrong meta type was passed into a processor. This is probably an internal implementation error.")] WrongMetaType, #[error("Encountered an error while saving the asset: {0}")] - AssetSaveError(#[from] Box), + AssetSaveError(#[from] crate::Error), #[error("Assets without extensions are not supported.")] ExtensionRequired, } @@ -138,7 +138,7 @@ impl> Process .saver .save(writer, saved_asset, &settings.saver_settings) .await - .map_err(|error| ProcessError::AssetSaveError(Box::new(error)))?; + .map_err(|error| ProcessError::AssetSaveError(error))?; Ok(output_settings) }) } diff --git a/crates/bevy_asset/src/saver.rs b/crates/bevy_asset/src/saver.rs index 0b01b7d91e550c..5d8f77ce3d32ae 100644 --- a/crates/bevy_asset/src/saver.rs +++ b/crates/bevy_asset/src/saver.rs @@ -13,29 +13,27 @@ pub trait AssetSaver: Send + Sync + 'static { type Settings: Settings + Default + Serialize + for<'a> Deserialize<'a>; /// The type of [`AssetLoader`] used to load this [`Asset`] type OutputLoader: AssetLoader; - /// The type of [error](`std::error::Error`) which could be encountered by this saver. - type Error: std::error::Error + Send + Sync + 'static; /// Saves the given runtime [`Asset`] by writing it to a byte format using `writer`. The passed in `settings` can influence how the - /// `asset` is saved. + /// `asset` is saved. fn save<'a>( &'a self, writer: &'a mut Writer, asset: SavedAsset<'a, Self::Asset>, settings: &'a Self::Settings, - ) -> BoxedFuture<'a, Result<::Settings, Self::Error>>; + ) -> BoxedFuture<'a, Result<::Settings, crate::Error>>; } /// A type-erased dynamic variant of [`AssetSaver`] that allows callers to save assets without knowing the actual type of the [`AssetSaver`]. pub trait ErasedAssetSaver: Send + Sync + 'static { /// Saves the given runtime [`ErasedLoadedAsset`] by writing it to a byte format using `writer`. The passed in `settings` can influence how the - /// `asset` is saved. + /// `asset` is saved. fn save<'a>( &'a self, writer: &'a mut Writer, asset: &'a ErasedLoadedAsset, settings: &'a dyn Settings, - ) -> BoxedFuture<'a, Result<(), Box>>; + ) -> BoxedFuture<'a, Result<(), crate::Error>>; /// The type name of the [`AssetSaver`]. fn type_name(&self) -> &'static str; @@ -47,7 +45,7 @@ impl ErasedAssetSaver for S { writer: &'a mut Writer, asset: &'a ErasedLoadedAsset, settings: &'a dyn Settings, - ) -> BoxedFuture<'a, Result<(), Box>> { + ) -> BoxedFuture<'a, Result<(), crate::Error>> { Box::pin(async move { let settings = settings .downcast_ref::() diff --git a/crates/bevy_asset/src/server/mod.rs b/crates/bevy_asset/src/server/mod.rs index 864faf70fc71be..780b2713ea14bb 100644 --- a/crates/bevy_asset/src/server/mod.rs +++ b/crates/bevy_asset/src/server/mod.rs @@ -33,7 +33,7 @@ use thiserror::Error; /// The general process to load an asset is: /// 1. Initialize a new [`Asset`] type with the [`AssetServer`] via [`AssetApp::init_asset`], which will internally call [`AssetServer::register_asset`] /// and set up related ECS [`Assets`] storage and systems. -/// 2. Register one or more [`AssetLoader`]s for that asset with [`AssetApp::init_asset_loader`] +/// 2. Register one or more [`AssetLoader`]s for that asset with [`AssetApp::init_asset_loader`] /// 3. Add the asset to your asset folder (defaults to `assets`). /// 4. Call [`AssetServer::load`] with a path to your asset. /// @@ -957,7 +957,7 @@ enum MaybeAssetLoader { }, } -/// Internal events for asset load results +/// Internal events for asset load results #[allow(clippy::large_enum_variant)] pub(crate) enum InternalAssetEvent { Loaded { @@ -1046,7 +1046,7 @@ pub enum AssetLoadError { AssetLoaderError { path: AssetPath<'static>, loader_name: &'static str, - error: Box, + error: crate::Error, }, #[error("The file at '{base_path}' does not contain the labeled asset '{label}'.")] MissingLabel { diff --git a/crates/bevy_audio/src/audio_source.rs b/crates/bevy_audio/src/audio_source.rs index 30f9c8cf8da9e9..8f3509bc051fd7 100644 --- a/crates/bevy_audio/src/audio_source.rs +++ b/crates/bevy_audio/src/audio_source.rs @@ -41,14 +41,13 @@ pub struct AudioLoader; impl AssetLoader for AudioLoader { type Asset = AudioSource; type Settings = (); - type Error = std::io::Error; fn load<'a>( &'a self, reader: &'a mut Reader, _settings: &'a Self::Settings, _load_context: &'a mut LoadContext, - ) -> BoxedFuture<'a, Result> { + ) -> BoxedFuture<'a, Result> { Box::pin(async move { let mut bytes = Vec::new(); reader.read_to_end(&mut bytes).await?; @@ -113,7 +112,7 @@ pub trait AddAudioSource { /// so that it can be converted to a [`rodio::Source`] type, /// and [`Asset`], so that it can be registered as an asset. /// To use this method on [`App`][bevy_app::App], - /// the [audio][super::AudioPlugin] and [asset][bevy_asset::AssetPlugin] plugins must be added first. + /// the [audio][super::AudioPlugin] and [asset][bevy_asset::AssetPlugin] plugins must be added first. fn add_audio_source(&mut self) -> &mut Self where T: Decodable + Asset, diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index abdbc1a3cbe506..e5b35ffaba316d 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -108,17 +108,16 @@ pub struct GltfLoader { impl AssetLoader for GltfLoader { type Asset = Gltf; type Settings = (); - type Error = GltfError; fn load<'a>( &'a self, reader: &'a mut Reader, _settings: &'a (), load_context: &'a mut LoadContext, - ) -> bevy_utils::BoxedFuture<'a, Result> { + ) -> bevy_utils::BoxedFuture<'a, Result> { Box::pin(async move { let mut bytes = Vec::new(); reader.read_to_end(&mut bytes).await?; - load_gltf(self, &bytes, load_context).await + Ok(load_gltf(self, &bytes, load_context).await?) }) } diff --git a/crates/bevy_render/src/render_resource/shader.rs b/crates/bevy_render/src/render_resource/shader.rs index 465fbb193d35a3..71b140fadf19f4 100644 --- a/crates/bevy_render/src/render_resource/shader.rs +++ b/crates/bevy_render/src/render_resource/shader.rs @@ -250,13 +250,12 @@ pub enum ShaderLoaderError { impl AssetLoader for ShaderLoader { type Asset = Shader; type Settings = (); - type Error = ShaderLoaderError; fn load<'a>( &'a self, reader: &'a mut Reader, _settings: &'a Self::Settings, load_context: &'a mut LoadContext, - ) -> BoxedFuture<'a, Result> { + ) -> BoxedFuture<'a, Result> { Box::pin(async move { let ext = load_context.path().extension().unwrap().to_str().unwrap(); diff --git a/crates/bevy_render/src/texture/hdr_texture_loader.rs b/crates/bevy_render/src/texture/hdr_texture_loader.rs index e54b38b806606e..c2c3be924bb232 100644 --- a/crates/bevy_render/src/texture/hdr_texture_loader.rs +++ b/crates/bevy_render/src/texture/hdr_texture_loader.rs @@ -19,13 +19,12 @@ pub enum HdrTextureLoaderError { impl AssetLoader for HdrTextureLoader { type Asset = Image; type Settings = (); - type Error = HdrTextureLoaderError; fn load<'a>( &'a self, reader: &'a mut Reader, _settings: &'a (), _load_context: &'a mut LoadContext, - ) -> bevy_utils::BoxedFuture<'a, Result> { + ) -> bevy_utils::BoxedFuture<'a, Result> { Box::pin(async move { let format = TextureFormat::Rgba32Float; debug_assert_eq!( diff --git a/crates/bevy_render/src/texture/image_loader.rs b/crates/bevy_render/src/texture/image_loader.rs index ec79c9d13e4cbe..e95a8f2b07dbd3 100644 --- a/crates/bevy_render/src/texture/image_loader.rs +++ b/crates/bevy_render/src/texture/image_loader.rs @@ -81,13 +81,12 @@ pub enum ImageLoaderError { impl AssetLoader for ImageLoader { type Asset = Image; type Settings = ImageLoaderSettings; - type Error = ImageLoaderError; fn load<'a>( &'a self, reader: &'a mut Reader, settings: &'a ImageLoaderSettings, load_context: &'a mut LoadContext, - ) -> bevy_utils::BoxedFuture<'a, Result> { + ) -> bevy_utils::BoxedFuture<'a, Result> { Box::pin(async move { // use the file extension for the image type let ext = load_context.path().extension().unwrap().to_str().unwrap(); diff --git a/crates/bevy_scene/src/scene_loader.rs b/crates/bevy_scene/src/scene_loader.rs index 5d1e4de56ade46..858a015ffc1fb0 100644 --- a/crates/bevy_scene/src/scene_loader.rs +++ b/crates/bevy_scene/src/scene_loader.rs @@ -41,14 +41,13 @@ pub enum SceneLoaderError { impl AssetLoader for SceneLoader { type Asset = DynamicScene; type Settings = (); - type Error = SceneLoaderError; fn load<'a>( &'a self, reader: &'a mut Reader, _settings: &'a (), _load_context: &'a mut LoadContext, - ) -> BoxedFuture<'a, Result> { + ) -> BoxedFuture<'a, Result> { Box::pin(async move { let mut bytes = Vec::new(); reader.read_to_end(&mut bytes).await?; diff --git a/crates/bevy_text/src/font_loader.rs b/crates/bevy_text/src/font_loader.rs index a47abbd9619a05..f9789af19355b5 100644 --- a/crates/bevy_text/src/font_loader.rs +++ b/crates/bevy_text/src/font_loader.rs @@ -20,13 +20,12 @@ pub enum FontLoaderError { impl AssetLoader for FontLoader { type Asset = Font; type Settings = (); - type Error = FontLoaderError; fn load<'a>( &'a self, reader: &'a mut Reader, _settings: &'a (), _load_context: &'a mut LoadContext, - ) -> bevy_utils::BoxedFuture<'a, Result> { + ) -> bevy_utils::BoxedFuture<'a, Result> { Box::pin(async move { let mut bytes = Vec::new(); reader.read_to_end(&mut bytes).await?; diff --git a/examples/asset/custom_asset.rs b/examples/asset/custom_asset.rs index c0aa0ad9b83b9c..682f31bf73fa43 100644 --- a/examples/asset/custom_asset.rs +++ b/examples/asset/custom_asset.rs @@ -34,13 +34,12 @@ pub enum CustomAssetLoaderError { impl AssetLoader for CustomAssetLoader { type Asset = CustomAsset; type Settings = (); - type Error = CustomAssetLoaderError; fn load<'a>( &'a self, reader: &'a mut Reader, _settings: &'a (), _load_context: &'a mut LoadContext, - ) -> BoxedFuture<'a, Result> { + ) -> BoxedFuture<'a, Result> { Box::pin(async move { let mut bytes = Vec::new(); reader.read_to_end(&mut bytes).await?;