diff --git a/crates/bevy_animation/src/graph.rs b/crates/bevy_animation/src/graph.rs index 01a270ed53..7a703942aa 100644 --- a/crates/bevy_animation/src/graph.rs +++ b/crates/bevy_animation/src/graph.rs @@ -4,7 +4,7 @@ use std::io::{self, Write}; use std::ops::{Index, IndexMut}; use bevy_asset::io::Reader; -use bevy_asset::{Asset, AssetId, AssetLoader, AssetPath, AsyncReadExt as _, Handle, LoadContext}; +use bevy_asset::{Asset, AssetId, AssetLoader, AssetPath, Handle, LoadContext}; use bevy_reflect::{Reflect, ReflectSerialize}; use petgraph::graph::{DiGraph, NodeIndex}; use ron::de::SpannedError; @@ -337,7 +337,7 @@ impl AssetLoader for AnimationGraphAssetLoader { async fn load<'a>( &'a self, - reader: &'a mut Reader<'_>, + reader: &'a mut dyn Reader, _: &'a Self::Settings, load_context: &'a mut LoadContext<'_>, ) -> Result { diff --git a/crates/bevy_asset/Cargo.toml b/crates/bevy_asset/Cargo.toml index e380be18b2..c6fb68cada 100644 --- a/crates/bevy_asset/Cargo.toml +++ b/crates/bevy_asset/Cargo.toml @@ -28,6 +28,7 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.14.0-dev", features = [ bevy_tasks = { path = "../bevy_tasks", version = "0.14.0-dev" } bevy_utils = { path = "../bevy_utils", version = "0.14.0-dev" } +stackfuture = "0.3" async-broadcast = "0.5" async-fs = "2.0" async-lock = "3.0" diff --git a/crates/bevy_asset/src/io/android.rs b/crates/bevy_asset/src/io/android.rs index 18daac5949..1890a943c8 100644 --- a/crates/bevy_asset/src/io/android.rs +++ b/crates/bevy_asset/src/io/android.rs @@ -16,7 +16,7 @@ use std::{ffi::CString, path::Path}; pub struct AndroidAssetReader; impl AssetReader for AndroidAssetReader { - async fn read<'a>(&'a self, path: &'a Path) -> Result>, AssetReaderError> { + async fn read<'a>(&'a self, path: &'a Path) -> Result { let asset_manager = bevy_winit::ANDROID_APP .get() .expect("Bevy must be setup with the #[bevy_main] macro on Android") @@ -25,11 +25,11 @@ impl AssetReader for AndroidAssetReader { .open(&CString::new(path.to_str().unwrap()).unwrap()) .ok_or(AssetReaderError::NotFound(path.to_path_buf()))?; let bytes = opened_asset.buffer()?; - let reader: Box = Box::new(VecReader::new(bytes.to_vec())); + let reader = VecReader::new(bytes.to_vec()); Ok(reader) } - async fn read_meta<'a>(&'a self, path: &'a Path) -> Result>, AssetReaderError> { + async fn read_meta<'a>(&'a self, path: &'a Path) -> Result { let meta_path = get_meta_path(path); let asset_manager = bevy_winit::ANDROID_APP .get() @@ -39,7 +39,7 @@ impl AssetReader for AndroidAssetReader { .open(&CString::new(meta_path.to_str().unwrap()).unwrap()) .ok_or(AssetReaderError::NotFound(meta_path))?; let bytes = opened_asset.buffer()?; - let reader: Box = Box::new(VecReader::new(bytes.to_vec())); + let reader = VecReader::new(bytes.to_vec()); Ok(reader) } diff --git a/crates/bevy_asset/src/io/file/file_asset.rs b/crates/bevy_asset/src/io/file/file_asset.rs index 5826fe097d..56a566c219 100644 --- a/crates/bevy_asset/src/io/file/file_asset.rs +++ b/crates/bevy_asset/src/io/file/file_asset.rs @@ -9,40 +9,30 @@ use std::path::Path; use super::{FileAssetReader, FileAssetWriter}; +impl Reader for File {} + impl AssetReader for FileAssetReader { - async fn read<'a>(&'a self, path: &'a Path) -> Result>, AssetReaderError> { + async fn read<'a>(&'a self, path: &'a Path) -> Result { let full_path = self.root_path.join(path); - match File::open(&full_path).await { - Ok(file) => { - let reader: Box = Box::new(file); - Ok(reader) + File::open(&full_path).await.map_err(|e| { + if e.kind() == std::io::ErrorKind::NotFound { + AssetReaderError::NotFound(full_path) + } else { + e.into() } - Err(e) => { - if e.kind() == std::io::ErrorKind::NotFound { - Err(AssetReaderError::NotFound(full_path)) - } else { - Err(e.into()) - } - } - } + }) } - async fn read_meta<'a>(&'a self, path: &'a Path) -> Result>, AssetReaderError> { + async fn read_meta<'a>(&'a self, path: &'a Path) -> Result { let meta_path = get_meta_path(path); let full_path = self.root_path.join(meta_path); - match File::open(&full_path).await { - Ok(file) => { - let reader: Box = Box::new(file); - Ok(reader) + File::open(&full_path).await.map_err(|e| { + if e.kind() == std::io::ErrorKind::NotFound { + AssetReaderError::NotFound(full_path) + } else { + e.into() } - Err(e) => { - if e.kind() == std::io::ErrorKind::NotFound { - Err(AssetReaderError::NotFound(full_path)) - } else { - Err(e.into()) - } - } - } + }) } async fn read_directory<'a>( diff --git a/crates/bevy_asset/src/io/file/sync_file_asset.rs b/crates/bevy_asset/src/io/file/sync_file_asset.rs index 83eacd5649..302b7cd839 100644 --- a/crates/bevy_asset/src/io/file/sync_file_asset.rs +++ b/crates/bevy_asset/src/io/file/sync_file_asset.rs @@ -42,6 +42,16 @@ impl AsyncSeek for FileReader { } } +impl Reader for FileReader { + fn read_to_end<'a>( + &'a mut self, + buf: &'a mut Vec, + ) -> stackfuture::StackFuture<'a, std::io::Result, { crate::io::STACK_FUTURE_SIZE }> + { + stackfuture::StackFuture::from(async { self.0.read_to_end(buf) }) + } +} + struct FileWriter(File); impl AsyncWrite for FileWriter { @@ -87,13 +97,10 @@ impl Stream for DirReader { } impl AssetReader for FileAssetReader { - async fn read<'a>(&'a self, path: &'a Path) -> Result>, AssetReaderError> { + async fn read<'a>(&'a self, path: &'a Path) -> Result { let full_path = self.root_path.join(path); match File::open(&full_path) { - Ok(file) => { - let reader: Box = Box::new(FileReader(file)); - Ok(reader) - } + Ok(file) => Ok(FileReader(file)), Err(e) => { if e.kind() == std::io::ErrorKind::NotFound { Err(AssetReaderError::NotFound(full_path)) @@ -104,14 +111,11 @@ impl AssetReader for FileAssetReader { } } - async fn read_meta<'a>(&'a self, path: &'a Path) -> Result>, AssetReaderError> { + async fn read_meta<'a>(&'a self, path: &'a Path) -> Result { let meta_path = get_meta_path(path); let full_path = self.root_path.join(meta_path); match File::open(&full_path) { - Ok(file) => { - let reader: Box = Box::new(FileReader(file)); - Ok(reader) - } + Ok(file) => Ok(FileReader(file)), Err(e) => { if e.kind() == std::io::ErrorKind::NotFound { Err(AssetReaderError::NotFound(full_path)) diff --git a/crates/bevy_asset/src/io/gated.rs b/crates/bevy_asset/src/io/gated.rs index d3d2b35f1f..1f6e783ce8 100644 --- a/crates/bevy_asset/src/io/gated.rs +++ b/crates/bevy_asset/src/io/gated.rs @@ -55,7 +55,7 @@ impl GatedReader { } impl AssetReader for GatedReader { - async fn read<'a>(&'a self, path: &'a Path) -> Result>, AssetReaderError> { + async fn read<'a>(&'a self, path: &'a Path) -> Result { let receiver = { let mut gates = self.gates.write(); let gates = gates @@ -68,7 +68,7 @@ impl AssetReader for GatedReader { Ok(result) } - async fn read_meta<'a>(&'a self, path: &'a Path) -> Result>, AssetReaderError> { + async fn read_meta<'a>(&'a self, path: &'a Path) -> Result { self.reader.read_meta(path).await } diff --git a/crates/bevy_asset/src/io/memory.rs b/crates/bevy_asset/src/io/memory.rs index 782df9e3ef..03edf58d1f 100644 --- a/crates/bevy_asset/src/io/memory.rs +++ b/crates/bevy_asset/src/io/memory.rs @@ -277,29 +277,41 @@ impl AsyncSeek for DataReader { } } +impl Reader for DataReader { + fn read_to_end<'a>( + &'a mut self, + buf: &'a mut Vec, + ) -> stackfuture::StackFuture<'a, std::io::Result, { super::STACK_FUTURE_SIZE }> { + stackfuture::StackFuture::from(async { + if self.bytes_read >= self.data.value().len() { + Ok(0) + } else { + buf.extend_from_slice(&self.data.value()[self.bytes_read..]); + let n = self.data.value().len() - self.bytes_read; + self.bytes_read = self.data.value().len(); + Ok(n) + } + }) + } +} + impl AssetReader for MemoryAssetReader { - async fn read<'a>(&'a self, path: &'a Path) -> Result>, AssetReaderError> { + async fn read<'a>(&'a self, path: &'a Path) -> Result { self.root .get_asset(path) - .map(|data| { - let reader: Box = Box::new(DataReader { - data, - bytes_read: 0, - }); - reader + .map(|data| DataReader { + data, + bytes_read: 0, }) .ok_or_else(|| AssetReaderError::NotFound(path.to_path_buf())) } - async fn read_meta<'a>(&'a self, path: &'a Path) -> Result>, AssetReaderError> { + async fn read_meta<'a>(&'a self, path: &'a Path) -> Result { self.root .get_metadata(path) - .map(|data| { - let reader: Box = Box::new(DataReader { - data, - bytes_read: 0, - }); - reader + .map(|data| DataReader { + data, + bytes_read: 0, }) .ok_or_else(|| AssetReaderError::NotFound(path.to_path_buf())) } diff --git a/crates/bevy_asset/src/io/mod.rs b/crates/bevy_asset/src/io/mod.rs index a249d7d061..78fb62a1ed 100644 --- a/crates/bevy_asset/src/io/mod.rs +++ b/crates/bevy_asset/src/io/mod.rs @@ -18,7 +18,7 @@ pub mod wasm; mod source; -pub use futures_lite::{AsyncReadExt, AsyncWriteExt}; +pub use futures_lite::AsyncWriteExt; pub use source::*; use bevy_utils::{BoxedFuture, ConditionalSendFuture}; @@ -72,11 +72,59 @@ impl From for AssetReaderError { } } -pub trait AsyncReadAndSeek: AsyncRead + AsyncSeek {} +/// The maximum size of a future returned from [`Reader::read_to_end`]. +/// This is large enough to fit ten references. +// Ideally this would be even smaller (ReadToEndFuture only needs space for two references based on its definition), +// but compiler optimizations can apparently inflate the stack size of futures due to inlining, which makes +// a higher maximum necessary. +pub const STACK_FUTURE_SIZE: usize = 10 * std::mem::size_of::<&()>(); -impl AsyncReadAndSeek for T {} +pub use stackfuture::StackFuture; -pub type Reader<'a> = dyn AsyncReadAndSeek + Unpin + Send + Sync + 'a; +/// A type returned from [`AssetReader::read`], which is used to read the contents of a file +/// (or virtual file) corresponding to an asset. +/// +/// This is essentially a trait alias for types implementing [`AsyncRead`] and [`AsyncSeek`]. +/// The only reason a blanket implementation is not provided for applicable types is to allow +/// implementors to override the provided implementation of [`Reader::read_to_end`]. +pub trait Reader: AsyncRead + AsyncSeek + Unpin + Send + Sync { + /// Reads the entire contents of this reader and appends them to a vec. + /// + /// # Note for implementors + /// You should override the provided implementation if you can fill up the buffer more + /// efficiently than the default implementation, which calls `poll_read` repeatedly to + /// fill up the buffer 32 bytes at a time. + fn read_to_end<'a>( + &'a mut self, + buf: &'a mut Vec, + ) -> StackFuture<'a, std::io::Result, STACK_FUTURE_SIZE> { + let future = futures_lite::AsyncReadExt::read_to_end(self, buf); + StackFuture::from(future) + } +} + +impl Reader for Box { + fn read_to_end<'a>( + &'a mut self, + buf: &'a mut Vec, + ) -> StackFuture<'a, std::io::Result, STACK_FUTURE_SIZE> { + (**self).read_to_end(buf) + } +} + +/// A future that returns a value or an [`AssetReaderError`] +pub trait AssetReaderFuture: + ConditionalSendFuture> +{ + type Value; +} + +impl AssetReaderFuture for F +where + F: ConditionalSendFuture>, +{ + type Value = T; +} /// Performs read operations on an asset storage. [`AssetReader`] exposes a "virtual filesystem" /// API, where asset bytes and asset metadata bytes are both stored and accessible for a given @@ -85,15 +133,29 @@ pub type Reader<'a> = dyn AsyncReadAndSeek + Unpin + Send + Sync + 'a; /// Also see [`AssetWriter`]. pub trait AssetReader: Send + Sync + 'static { /// Returns a future to load the full file data at the provided path. - fn read<'a>( - &'a self, - path: &'a Path, - ) -> impl ConditionalSendFuture>, AssetReaderError>>; + /// + /// # Note for implementors + /// The preferred style for implementing this method is an `async fn` returning an opaque type. + /// + /// ```no_run + /// # use std::path::Path; + /// # use bevy_asset::{prelude::*, io::{AssetReader, PathStream, Reader, AssetReaderError}}; + /// # struct MyReader; + /// impl AssetReader for MyReader { + /// async fn read<'a>(&'a self, path: &'a Path) -> Result { + /// // ... + /// # let val: Box = unimplemented!(); Ok(val) + /// } + /// # async fn read_meta<'a>(&'a self, path: &'a Path) -> Result { + /// # let val: Box = unimplemented!(); Ok(val) } + /// # async fn read_directory<'a>(&'a self, path: &'a Path) -> Result, AssetReaderError> { unimplemented!() } + /// # async fn is_directory<'a>(&'a self, path: &'a Path) -> Result { unimplemented!() } + /// # async fn read_meta_bytes<'a>(&'a self, path: &'a Path) -> Result, AssetReaderError> { unimplemented!() } + /// } + /// ``` + fn read<'a>(&'a self, path: &'a Path) -> impl AssetReaderFuture; /// Returns a future to load the full file data at the provided path. - fn read_meta<'a>( - &'a self, - path: &'a Path, - ) -> impl ConditionalSendFuture>, AssetReaderError>>; + fn read_meta<'a>(&'a self, path: &'a Path) -> impl AssetReaderFuture; /// Returns an iterator of directory entry names at the provided path. fn read_directory<'a>( &'a self, @@ -123,13 +185,15 @@ pub trait AssetReader: Send + Sync + 'static { /// as [`AssetReader`] isn't currently object safe. pub trait ErasedAssetReader: Send + Sync + 'static { /// Returns a future to load the full file data at the provided path. - fn read<'a>(&'a self, path: &'a Path) - -> BoxedFuture>, AssetReaderError>>; + fn read<'a>( + &'a self, + path: &'a Path, + ) -> BoxedFuture, AssetReaderError>>; /// Returns a future to load the full file data at the provided path. fn read_meta<'a>( &'a self, path: &'a Path, - ) -> BoxedFuture>, AssetReaderError>>; + ) -> BoxedFuture, AssetReaderError>>; /// Returns an iterator of directory entry names at the provided path. fn read_directory<'a>( &'a self, @@ -149,14 +213,20 @@ impl ErasedAssetReader for T { fn read<'a>( &'a self, path: &'a Path, - ) -> BoxedFuture>, AssetReaderError>> { - Box::pin(Self::read(self, path)) + ) -> BoxedFuture, AssetReaderError>> { + Box::pin(async { + let reader = Self::read(self, path).await?; + Ok(Box::new(reader) as Box) + }) } fn read_meta<'a>( &'a self, path: &'a Path, - ) -> BoxedFuture>, AssetReaderError>> { - Box::pin(Self::read_meta(self, path)) + ) -> BoxedFuture, AssetReaderError>> { + Box::pin(async { + let reader = Self::read_meta(self, path).await?; + Ok(Box::new(reader) as Box) + }) } fn read_directory<'a>( &'a self, @@ -498,6 +568,24 @@ impl AsyncSeek for VecReader { } } +impl Reader for VecReader { + fn read_to_end<'a>( + &'a mut self, + buf: &'a mut Vec, + ) -> StackFuture<'a, std::io::Result, STACK_FUTURE_SIZE> { + StackFuture::from(async { + if self.bytes_read >= self.bytes.len() { + Ok(0) + } else { + buf.extend_from_slice(&self.bytes[self.bytes_read..]); + let n = self.bytes.len() - self.bytes_read; + self.bytes_read = self.bytes.len(); + Ok(n) + } + }) + } +} + /// An [`AsyncRead`] implementation capable of reading a [`&[u8]`]. pub struct SliceReader<'a> { bytes: &'a [u8], @@ -565,6 +653,24 @@ impl<'a> AsyncSeek for SliceReader<'a> { } } +impl Reader for SliceReader<'_> { + fn read_to_end<'a>( + &'a mut self, + buf: &'a mut Vec, + ) -> StackFuture<'a, std::io::Result, STACK_FUTURE_SIZE> { + StackFuture::from(async { + if self.bytes_read >= self.bytes.len() { + Ok(0) + } else { + buf.extend_from_slice(&self.bytes[self.bytes_read..]); + let n = self.bytes.len() - self.bytes_read; + self.bytes_read = self.bytes.len(); + Ok(n) + } + }) + } +} + /// Appends `.meta` to the given path. pub(crate) fn get_meta_path(path: &Path) -> PathBuf { let mut meta_path = path.to_path_buf(); diff --git a/crates/bevy_asset/src/io/processor_gated.rs b/crates/bevy_asset/src/io/processor_gated.rs index f3d517b6b9..0c88cc63bf 100644 --- a/crates/bevy_asset/src/io/processor_gated.rs +++ b/crates/bevy_asset/src/io/processor_gated.rs @@ -51,7 +51,7 @@ impl ProcessorGatedReader { } impl AssetReader for ProcessorGatedReader { - async fn read<'a>(&'a self, path: &'a Path) -> Result>, AssetReaderError> { + async fn read<'a>(&'a self, path: &'a Path) -> Result { let asset_path = AssetPath::from(path.to_path_buf()).with_source(self.source.clone()); trace!("Waiting for processing to finish before reading {asset_path}"); let process_result = self @@ -67,11 +67,11 @@ impl AssetReader for ProcessorGatedReader { trace!("Processing finished with {asset_path}, reading {process_result:?}",); let lock = self.get_transaction_lock(&asset_path).await?; let asset_reader = self.reader.read(path).await?; - let reader: Box> = Box::new(TransactionLockedReader::new(asset_reader, lock)); + let reader = TransactionLockedReader::new(asset_reader, lock); Ok(reader) } - async fn read_meta<'a>(&'a self, path: &'a Path) -> Result>, AssetReaderError> { + async fn read_meta<'a>(&'a self, path: &'a Path) -> Result { let asset_path = AssetPath::from(path.to_path_buf()).with_source(self.source.clone()); trace!("Waiting for processing to finish before reading meta for {asset_path}",); let process_result = self @@ -87,7 +87,7 @@ impl AssetReader for ProcessorGatedReader { trace!("Processing finished with {process_result:?}, reading meta for {asset_path}",); let lock = self.get_transaction_lock(&asset_path).await?; let meta_reader = self.reader.read_meta(path).await?; - let reader: Box> = Box::new(TransactionLockedReader::new(meta_reader, lock)); + let reader = TransactionLockedReader::new(meta_reader, lock); Ok(reader) } @@ -119,12 +119,12 @@ impl AssetReader for ProcessorGatedReader { /// An [`AsyncRead`] impl that will hold its asset's transaction lock until [`TransactionLockedReader`] is dropped. pub struct TransactionLockedReader<'a> { - reader: Box>, + reader: Box, _file_transaction_lock: RwLockReadGuardArc<()>, } impl<'a> TransactionLockedReader<'a> { - fn new(reader: Box>, file_transaction_lock: RwLockReadGuardArc<()>) -> Self { + fn new(reader: Box, file_transaction_lock: RwLockReadGuardArc<()>) -> Self { Self { reader, _file_transaction_lock: file_transaction_lock, @@ -132,7 +132,7 @@ impl<'a> TransactionLockedReader<'a> { } } -impl<'a> AsyncRead for TransactionLockedReader<'a> { +impl AsyncRead for TransactionLockedReader<'_> { fn poll_read( mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>, @@ -142,7 +142,7 @@ impl<'a> AsyncRead for TransactionLockedReader<'a> { } } -impl<'a> AsyncSeek for TransactionLockedReader<'a> { +impl AsyncSeek for TransactionLockedReader<'_> { fn poll_seek( mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>, @@ -151,3 +151,12 @@ impl<'a> AsyncSeek for TransactionLockedReader<'a> { Pin::new(&mut self.reader).poll_seek(cx, pos) } } + +impl Reader for TransactionLockedReader<'_> { + fn read_to_end<'a>( + &'a mut self, + buf: &'a mut Vec, + ) -> stackfuture::StackFuture<'a, std::io::Result, { super::STACK_FUTURE_SIZE }> { + self.reader.read_to_end(buf) + } +} diff --git a/crates/bevy_asset/src/io/wasm.rs b/crates/bevy_asset/src/io/wasm.rs index e8b99a1cc6..98163e43a8 100644 --- a/crates/bevy_asset/src/io/wasm.rs +++ b/crates/bevy_asset/src/io/wasm.rs @@ -51,7 +51,7 @@ fn js_value_to_err(context: &str) -> impl FnOnce(JsValue) -> std::io::Error + '_ } impl HttpWasmAssetReader { - async fn fetch_bytes<'a>(&self, path: PathBuf) -> Result>, AssetReaderError> { + async fn fetch_bytes<'a>(&self, path: PathBuf) -> Result { // The JS global scope includes a self-reference via a specialising name, which can be used to determine the type of global context available. let global: Global = js_sys::global().unchecked_into(); let promise = if !global.window().is_undefined() { @@ -77,7 +77,7 @@ impl HttpWasmAssetReader { 200 => { let data = JsFuture::from(resp.array_buffer().unwrap()).await.unwrap(); let bytes = Uint8Array::new(&data).to_vec(); - let reader: Box = Box::new(VecReader::new(bytes)); + let reader = VecReader::new(bytes); Ok(reader) } 404 => Err(AssetReaderError::NotFound(path)), @@ -87,12 +87,12 @@ impl HttpWasmAssetReader { } impl AssetReader for HttpWasmAssetReader { - async fn read<'a>(&'a self, path: &'a Path) -> Result>, AssetReaderError> { + async fn read<'a>(&'a self, path: &'a Path) -> Result { let path = self.root_path.join(path); self.fetch_bytes(path).await } - async fn read_meta<'a>(&'a self, path: &'a Path) -> Result>, AssetReaderError> { + async fn read_meta<'a>(&'a self, path: &'a Path) -> Result { let meta_path = get_meta_path(&self.root_path.join(path)); self.fetch_bytes(meta_path).await } diff --git a/crates/bevy_asset/src/lib.rs b/crates/bevy_asset/src/lib.rs index bf3730224f..a13144015b 100644 --- a/crates/bevy_asset/src/lib.rs +++ b/crates/bevy_asset/src/lib.rs @@ -460,7 +460,6 @@ mod tests { use bevy_log::LogPlugin; use bevy_reflect::TypePath; use bevy_utils::{Duration, HashMap}; - use futures_lite::AsyncReadExt; use serde::{Deserialize, Serialize}; use std::{path::Path, sync::Arc}; use thiserror::Error; @@ -510,7 +509,7 @@ mod tests { async fn load<'a>( &'a self, - reader: &'a mut Reader<'_>, + reader: &'a mut dyn Reader, _settings: &'a Self::Settings, load_context: &'a mut LoadContext<'_>, ) -> Result { @@ -584,13 +583,13 @@ mod tests { async fn read_meta<'a>( &'a self, path: &'a Path, - ) -> Result>, AssetReaderError> { + ) -> Result { self.memory_reader.read_meta(path).await } async fn read<'a>( &'a self, path: &'a Path, - ) -> Result>, bevy_asset::io::AssetReaderError> { + ) -> Result { let attempt_number = { let mut attempt_counters = self.attempt_counters.lock().unwrap(); if let Some(existing) = attempt_counters.get_mut(path) { diff --git a/crates/bevy_asset/src/loader.rs b/crates/bevy_asset/src/loader.rs index 8f5032161d..3103115e53 100644 --- a/crates/bevy_asset/src/loader.rs +++ b/crates/bevy_asset/src/loader.rs @@ -9,7 +9,6 @@ use crate::{ use bevy_ecs::world::World; use bevy_utils::{BoxedFuture, ConditionalSendFuture, CowArc, HashMap, HashSet}; use downcast_rs::{impl_downcast, Downcast}; -use futures_lite::AsyncReadExt; use ron::error::SpannedError; use serde::{Deserialize, Serialize}; use std::{ @@ -30,7 +29,7 @@ pub trait AssetLoader: 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, + reader: &'a mut dyn Reader, settings: &'a Self::Settings, load_context: &'a mut LoadContext, ) -> impl ConditionalSendFuture>; @@ -47,7 +46,7 @@ pub trait ErasedAssetLoader: Send + Sync + 'static { /// Asynchronously loads the asset(s) from the bytes provided by [`Reader`]. fn load<'a>( &'a self, - reader: &'a mut Reader, + reader: &'a mut dyn Reader, meta: Box, load_context: LoadContext<'a>, ) -> BoxedFuture< @@ -78,7 +77,7 @@ where /// Processes the asset in an asynchronous closure. fn load<'a>( &'a self, - reader: &'a mut Reader, + reader: &'a mut dyn Reader, meta: Box, mut load_context: LoadContext<'a>, ) -> BoxedFuture< @@ -519,7 +518,7 @@ impl<'a> LoadContext<'a> { path: AssetPath<'static>, meta: Box, loader: &dyn ErasedAssetLoader, - reader: &mut Reader<'_>, + reader: &mut dyn Reader, ) -> Result { let loaded_asset = self .asset_server diff --git a/crates/bevy_asset/src/loader_builders.rs b/crates/bevy_asset/src/loader_builders.rs index 929f122266..4cdce4a734 100644 --- a/crates/bevy_asset/src/loader_builders.rs +++ b/crates/bevy_asset/src/loader_builders.rs @@ -11,16 +11,16 @@ use std::any::TypeId; use std::sync::Arc; // Utility type for handling the sources of reader references -enum ReaderRef<'a, 'b> { - Borrowed(&'a mut Reader<'b>), - Boxed(Box>), +enum ReaderRef<'a> { + Borrowed(&'a mut dyn Reader), + Boxed(Box), } -impl<'a, 'b> ReaderRef<'a, 'b> { - pub fn as_mut(&mut self) -> &mut Reader { +impl ReaderRef<'_> { + pub fn as_mut(&mut self) -> &mut dyn Reader { match self { - ReaderRef::Borrowed(r) => r, - ReaderRef::Boxed(b) => &mut *b, + ReaderRef::Borrowed(r) => &mut **r, + ReaderRef::Boxed(b) => &mut **b, } } } @@ -168,13 +168,13 @@ impl<'ctx, 'builder> UntypedNestedLoader<'ctx, 'builder> { /// - `reader`: the lifetime of the [`Reader`] reference used to read the asset data pub struct DirectNestedLoader<'ctx, 'builder, 'reader> { base: NestedLoader<'ctx, 'builder>, - reader: Option<&'builder mut Reader<'reader>>, + reader: Option<&'builder mut (dyn Reader + 'reader)>, } impl<'ctx: 'reader, 'builder, 'reader> DirectNestedLoader<'ctx, 'builder, 'reader> { /// Specify the reader to use to read the asset data. #[must_use] - pub fn with_reader(mut self, reader: &'builder mut Reader<'reader>) -> Self { + pub fn with_reader(mut self, reader: &'builder mut (dyn Reader + 'reader)) -> Self { self.reader = Some(reader); self } diff --git a/crates/bevy_asset/src/meta.rs b/crates/bevy_asset/src/meta.rs index 1fcefbb00f..b0a7a9cab0 100644 --- a/crates/bevy_asset/src/meta.rs +++ b/crates/bevy_asset/src/meta.rs @@ -196,7 +196,7 @@ impl AssetLoader for () { type Error = std::io::Error; async fn load<'a>( &'a self, - _reader: &'a mut crate::io::Reader<'_>, + _reader: &'a mut dyn crate::io::Reader, _settings: &'a Self::Settings, _load_context: &'a mut crate::LoadContext<'_>, ) -> Result { diff --git a/crates/bevy_asset/src/server/loaders.rs b/crates/bevy_asset/src/server/loaders.rs index 324602d89c..b0ecba7ae3 100644 --- a/crates/bevy_asset/src/server/loaders.rs +++ b/crates/bevy_asset/src/server/loaders.rs @@ -310,7 +310,7 @@ impl AssetLoader for InstrumentedAssetLoader { fn load<'a>( &'a self, - reader: &'a mut crate::io::Reader, + reader: &'a mut dyn crate::io::Reader, settings: &'a Self::Settings, load_context: &'a mut crate::LoadContext, ) -> impl ConditionalSendFuture> { @@ -382,7 +382,7 @@ mod tests { async fn load<'a>( &'a self, - _: &'a mut crate::io::Reader<'_>, + _: &'a mut dyn crate::io::Reader, _: &'a Self::Settings, _: &'a mut crate::LoadContext<'_>, ) -> Result { diff --git a/crates/bevy_asset/src/server/mod.rs b/crates/bevy_asset/src/server/mod.rs index 830459f06d..10b5079de9 100644 --- a/crates/bevy_asset/src/server/mod.rs +++ b/crates/bevy_asset/src/server/mod.rs @@ -1065,7 +1065,7 @@ impl AssetServer { ( Box, Arc, - Box>, + Box, ), AssetLoadError, > { @@ -1169,7 +1169,7 @@ impl AssetServer { asset_path: &AssetPath<'_>, meta: Box, loader: &dyn ErasedAssetLoader, - reader: &mut Reader<'_>, + reader: &mut dyn Reader, load_dependencies: bool, populate_hashes: bool, ) -> Result { diff --git a/crates/bevy_audio/src/audio_source.rs b/crates/bevy_audio/src/audio_source.rs index b501eaeea0..64a481b328 100644 --- a/crates/bevy_audio/src/audio_source.rs +++ b/crates/bevy_audio/src/audio_source.rs @@ -1,7 +1,4 @@ -use bevy_asset::{ - io::{AsyncReadExt, Reader}, - Asset, AssetLoader, LoadContext, -}; +use bevy_asset::{io::Reader, Asset, AssetLoader, LoadContext}; use bevy_reflect::TypePath; use std::{io::Cursor, sync::Arc}; @@ -46,7 +43,7 @@ impl AssetLoader for AudioLoader { async fn load<'a>( &'a self, - reader: &'a mut Reader<'_>, + reader: &'a mut dyn Reader, _settings: &'a Self::Settings, _load_context: &'a mut LoadContext<'_>, ) -> Result { diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index 8725e46f32..07a96746ee 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -6,7 +6,7 @@ use crate::{ #[cfg(feature = "bevy_animation")] use bevy_animation::{AnimationTarget, AnimationTargetId}; use bevy_asset::{ - io::Reader, AssetLoadError, AssetLoader, AsyncReadExt, Handle, LoadContext, ReadAssetBytesError, + io::Reader, AssetLoadError, AssetLoader, Handle, LoadContext, ReadAssetBytesError, }; use bevy_color::{Color, LinearRgba}; use bevy_core::Name; @@ -176,7 +176,7 @@ impl AssetLoader for GltfLoader { type Error = GltfError; async fn load<'a>( &'a self, - reader: &'a mut Reader<'_>, + reader: &'a mut dyn Reader, settings: &'a GltfLoaderSettings, load_context: &'a mut LoadContext<'_>, ) -> Result { diff --git a/crates/bevy_pbr/src/meshlet/asset.rs b/crates/bevy_pbr/src/meshlet/asset.rs index d6a2740dbf..31f6ecd66e 100644 --- a/crates/bevy_pbr/src/meshlet/asset.rs +++ b/crates/bevy_pbr/src/meshlet/asset.rs @@ -1,5 +1,5 @@ use bevy_asset::{ - io::{AsyncReadAndSeek, Reader, Writer}, + io::{Reader, Writer}, saver::{AssetSaver, SavedAsset}, Asset, AssetLoader, AsyncReadExt, AsyncWriteExt, LoadContext, }; @@ -85,7 +85,7 @@ impl AssetLoader for MeshletMeshSaverLoad { async fn load<'a>( &'a self, - reader: &'a mut Reader<'_>, + reader: &'a mut dyn Reader, _settings: &'a Self::Settings, _load_context: &'a mut LoadContext<'_>, ) -> Result { @@ -144,9 +144,7 @@ pub enum MeshletMeshSaveOrLoadError { Io(#[from] std::io::Error), } -async fn read_u64( - reader: &mut (dyn AsyncReadAndSeek + Sync + Send + Unpin), -) -> Result { +async fn read_u64(reader: &mut dyn Reader) -> Result { let mut bytes = [0u8; 8]; reader.read_exact(&mut bytes).await?; Ok(u64::from_le_bytes(bytes)) diff --git a/crates/bevy_render/src/render_resource/shader.rs b/crates/bevy_render/src/render_resource/shader.rs index 49d61533ea..33055de58c 100644 --- a/crates/bevy_render/src/render_resource/shader.rs +++ b/crates/bevy_render/src/render_resource/shader.rs @@ -3,7 +3,6 @@ use crate::define_atomic_id; use bevy_asset::{io::Reader, Asset, AssetLoader, AssetPath, Handle, LoadContext}; use bevy_reflect::TypePath; use bevy_utils::tracing::error; -use futures_lite::AsyncReadExt; use std::{borrow::Cow, marker::Copy}; use thiserror::Error; @@ -261,7 +260,7 @@ impl AssetLoader for ShaderLoader { type Error = ShaderLoaderError; async fn load<'a>( &'a self, - reader: &'a mut Reader<'_>, + reader: &'a mut dyn Reader, _settings: &'a Self::Settings, load_context: &'a mut LoadContext<'_>, ) -> Result { diff --git a/crates/bevy_render/src/texture/exr_texture_loader.rs b/crates/bevy_render/src/texture/exr_texture_loader.rs index d5f39aa3c0..aba2d9196c 100644 --- a/crates/bevy_render/src/texture/exr_texture_loader.rs +++ b/crates/bevy_render/src/texture/exr_texture_loader.rs @@ -2,10 +2,7 @@ use crate::{ render_asset::RenderAssetUsages, texture::{Image, TextureFormatPixelInfo}, }; -use bevy_asset::{ - io::{AsyncReadExt, Reader}, - AssetLoader, LoadContext, -}; +use bevy_asset::{io::Reader, AssetLoader, LoadContext}; use image::ImageDecoder; use serde::{Deserialize, Serialize}; use thiserror::Error; @@ -37,7 +34,7 @@ impl AssetLoader for ExrTextureLoader { async fn load<'a>( &'a self, - reader: &'a mut Reader<'_>, + reader: &'a mut dyn Reader, settings: &'a Self::Settings, _load_context: &'a mut LoadContext<'_>, ) -> Result { diff --git a/crates/bevy_render/src/texture/hdr_texture_loader.rs b/crates/bevy_render/src/texture/hdr_texture_loader.rs index b1ab398f42..ab5624fa08 100644 --- a/crates/bevy_render/src/texture/hdr_texture_loader.rs +++ b/crates/bevy_render/src/texture/hdr_texture_loader.rs @@ -2,7 +2,7 @@ use crate::{ render_asset::RenderAssetUsages, texture::{Image, TextureFormatPixelInfo}, }; -use bevy_asset::{io::Reader, AssetLoader, AsyncReadExt, LoadContext}; +use bevy_asset::{io::Reader, AssetLoader, LoadContext}; use image::DynamicImage; use serde::{Deserialize, Serialize}; use thiserror::Error; @@ -32,7 +32,7 @@ impl AssetLoader for HdrTextureLoader { type Error = HdrTextureLoaderError; async fn load<'a>( &'a self, - reader: &'a mut Reader<'_>, + reader: &'a mut dyn Reader, settings: &'a Self::Settings, _load_context: &'a mut LoadContext<'_>, ) -> Result { diff --git a/crates/bevy_render/src/texture/image_loader.rs b/crates/bevy_render/src/texture/image_loader.rs index 3f5f4e3124..85a97ad431 100644 --- a/crates/bevy_render/src/texture/image_loader.rs +++ b/crates/bevy_render/src/texture/image_loader.rs @@ -1,4 +1,4 @@ -use bevy_asset::{io::Reader, AssetLoader, AsyncReadExt, LoadContext}; +use bevy_asset::{io::Reader, AssetLoader, LoadContext}; use bevy_ecs::prelude::{FromWorld, World}; use thiserror::Error; @@ -88,7 +88,7 @@ impl AssetLoader for ImageLoader { type Error = ImageLoaderError; async fn load<'a>( &'a self, - reader: &'a mut Reader<'_>, + reader: &'a mut dyn Reader, settings: &'a ImageLoaderSettings, load_context: &'a mut LoadContext<'_>, ) -> Result { diff --git a/crates/bevy_scene/src/scene_loader.rs b/crates/bevy_scene/src/scene_loader.rs index 46d0484f0e..566a573560 100644 --- a/crates/bevy_scene/src/scene_loader.rs +++ b/crates/bevy_scene/src/scene_loader.rs @@ -2,7 +2,7 @@ use crate::ron; #[cfg(feature = "serialize")] use crate::serde::SceneDeserializer; use crate::DynamicScene; -use bevy_asset::{io::Reader, AssetLoader, AsyncReadExt, LoadContext}; +use bevy_asset::{io::Reader, AssetLoader, LoadContext}; use bevy_ecs::reflect::AppTypeRegistry; use bevy_ecs::world::{FromWorld, World}; use bevy_reflect::TypeRegistryArc; @@ -47,7 +47,7 @@ impl AssetLoader for SceneLoader { async fn load<'a>( &'a self, - reader: &'a mut Reader<'_>, + reader: &'a mut dyn Reader, _settings: &'a (), _load_context: &'a mut LoadContext<'_>, ) -> Result { diff --git a/crates/bevy_text/src/font_loader.rs b/crates/bevy_text/src/font_loader.rs index a03e96f036..1ff170f0a8 100644 --- a/crates/bevy_text/src/font_loader.rs +++ b/crates/bevy_text/src/font_loader.rs @@ -1,5 +1,5 @@ use crate::Font; -use bevy_asset::{io::Reader, AssetLoader, AsyncReadExt, LoadContext}; +use bevy_asset::{io::Reader, AssetLoader, LoadContext}; use thiserror::Error; #[derive(Default)] @@ -23,7 +23,7 @@ impl AssetLoader for FontLoader { type Error = FontLoaderError; async fn load<'a>( &'a self, - reader: &'a mut Reader<'_>, + reader: &'a mut dyn Reader, _settings: &'a (), _load_context: &'a mut LoadContext<'_>, ) -> Result { diff --git a/examples/asset/asset_decompression.rs b/examples/asset/asset_decompression.rs index b17d4c2259..4101d24bb2 100644 --- a/examples/asset/asset_decompression.rs +++ b/examples/asset/asset_decompression.rs @@ -3,7 +3,7 @@ use bevy::{ asset::{ io::{Reader, VecReader}, - AssetLoader, AsyncReadExt, ErasedLoadedAsset, LoadContext, LoadDirectError, + AssetLoader, ErasedLoadedAsset, LoadContext, LoadDirectError, }, prelude::*, reflect::TypePath, @@ -42,7 +42,7 @@ impl AssetLoader for GzAssetLoader { type Error = GzAssetLoaderError; async fn load<'a>( &'a self, - reader: &'a mut Reader<'_>, + reader: &'a mut dyn Reader, _settings: &'a (), load_context: &'a mut LoadContext<'_>, ) -> Result { diff --git a/examples/asset/custom_asset.rs b/examples/asset/custom_asset.rs index 3c02f73249..f534207062 100644 --- a/examples/asset/custom_asset.rs +++ b/examples/asset/custom_asset.rs @@ -1,7 +1,7 @@ //! Implements loader for a custom asset type. use bevy::{ - asset::{io::Reader, AssetLoader, AsyncReadExt, LoadContext}, + asset::{io::Reader, AssetLoader, LoadContext}, prelude::*, reflect::TypePath, }; @@ -35,7 +35,7 @@ impl AssetLoader for CustomAssetLoader { type Error = CustomAssetLoaderError; async fn load<'a>( &'a self, - reader: &'a mut Reader<'_>, + reader: &'a mut dyn Reader, _settings: &'a (), _load_context: &'a mut LoadContext<'_>, ) -> Result { @@ -74,7 +74,7 @@ impl AssetLoader for BlobAssetLoader { async fn load<'a>( &'a self, - reader: &'a mut Reader<'_>, + reader: &'a mut dyn Reader, _settings: &'a (), _load_context: &'a mut LoadContext<'_>, ) -> Result { diff --git a/examples/asset/custom_asset_reader.rs b/examples/asset/custom_asset_reader.rs index d302ebbf7f..7ee270c2c8 100644 --- a/examples/asset/custom_asset_reader.rs +++ b/examples/asset/custom_asset_reader.rs @@ -15,11 +15,11 @@ use std::path::Path; struct CustomAssetReader(Box); impl AssetReader for CustomAssetReader { - async fn read<'a>(&'a self, path: &'a Path) -> Result>, AssetReaderError> { + async fn read<'a>(&'a self, path: &'a Path) -> Result { info!("Reading {:?}", path); self.0.read(path).await } - async fn read_meta<'a>(&'a self, path: &'a Path) -> Result>, AssetReaderError> { + async fn read_meta<'a>(&'a self, path: &'a Path) -> Result { self.0.read_meta(path).await } diff --git a/examples/asset/processing/asset_processing.rs b/examples/asset/processing/asset_processing.rs index cceb959ee7..d2439dd0cc 100644 --- a/examples/asset/processing/asset_processing.rs +++ b/examples/asset/processing/asset_processing.rs @@ -7,7 +7,7 @@ use bevy::{ processor::LoadTransformAndSave, saver::{AssetSaver, SavedAsset}, transformer::{AssetTransformer, TransformedAsset}, - AssetLoader, AsyncReadExt, AsyncWriteExt, LoadContext, + AssetLoader, AsyncWriteExt, LoadContext, }, prelude::*, reflect::TypePath, @@ -83,7 +83,7 @@ impl AssetLoader for TextLoader { type Error = std::io::Error; async fn load<'a>( &'a self, - reader: &'a mut Reader<'_>, + reader: &'a mut dyn Reader, settings: &'a TextSettings, _load_context: &'a mut LoadContext<'_>, ) -> Result { @@ -137,7 +137,7 @@ impl AssetLoader for CoolTextLoader { async fn load<'a>( &'a self, - reader: &'a mut Reader<'_>, + reader: &'a mut dyn Reader, _settings: &'a Self::Settings, load_context: &'a mut LoadContext<'_>, ) -> Result {