Optimize common usages of AssetReader
(#14082)
# Objective The `AssetReader` trait allows customizing the behavior of fetching bytes for an `AssetPath`, and expects implementors to return `dyn AsyncRead + AsyncSeek`. This gives implementors of `AssetLoader` great flexibility to tightly integrate their asset loading behavior with the asynchronous task system. However, almost all implementors of `AssetLoader` don't use the async functionality at all, and just call `AsyncReadExt::read_to_end(&mut Vec<u8>)`. This is incredibly inefficient, as this method repeatedly calls `poll_read` on the trait object, filling the vector 32 bytes at a time. At my work we have assets that are hundreds of megabytes which makes this a meaningful overhead. ## Solution Turn the `Reader` type alias into an actual trait, with a provided method `read_to_end`. This provided method should be more efficient than the existing extension method, as the compiler will know the underlying type of `Reader` when generating this function, which removes the repeated dynamic dispatches and allows the compiler to make further optimizations after inlining. Individual implementors are able to override the provided implementation -- for simple asset readers that just copy bytes from one buffer to another, this allows removing a large amount of overhead from the provided implementation. Now that `Reader` is an actual trait, I also improved the ergonomics for implementing `AssetReader`. Currently, implementors are expected to box their reader and return it as a trait object, which adds unnecessary boilerplate to implementations. This PR changes that trait method to return a pseudo trait alias, which allows implementors to return `impl Reader` instead of `Box<dyn Reader>`. Now, the boilerplate for boxing occurs in `ErasedAssetReader`. ## Testing I made identical changes to my company's fork of bevy. Our app, which makes heavy use of `read_to_end` for asset loading, still worked properly after this. I am not aware if we have a more systematic way of testing asset loading for correctness. --- ## Migration Guide The trait method `bevy_asset::io::AssetReader::read` (and `read_meta`) now return an opaque type instead of a boxed trait object. Implementors of these methods should change the type signatures appropriately ```rust impl AssetReader for MyReader { // Before async fn read<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> { let reader = // construct a reader Box::new(reader) as Box<Reader<'a>> } // After async fn read<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> { // create a reader } } ``` `bevy::asset::io::Reader` is now a trait, rather than a type alias for a trait object. Implementors of `AssetLoader::load` will need to adjust the method signature accordingly ```rust impl AssetLoader for MyLoader { async fn load<'a>( &'a self, // Before: reader: &'a mut bevy::asset::io::Reader, // After: reader: &'a mut dyn bevy::asset::io::Reader, _: &'a Self::Settings, load_context: &'a mut LoadContext<'_>, ) -> Result<Self::Asset, Self::Error> { } ``` Additionally, implementors of `AssetReader` that return a type implementing `futures_io::AsyncRead` and `AsyncSeek` might need to explicitly implement `bevy::asset::io::Reader` for that type. ```rust impl bevy::asset::io::Reader for MyAsyncReadAndSeek {} ```
This commit is contained in:
parent
bd7dcd3f6d
commit
5876352206
@ -4,7 +4,7 @@ use std::io::{self, Write};
|
|||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
|
|
||||||
use bevy_asset::io::Reader;
|
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 bevy_reflect::{Reflect, ReflectSerialize};
|
||||||
use petgraph::graph::{DiGraph, NodeIndex};
|
use petgraph::graph::{DiGraph, NodeIndex};
|
||||||
use ron::de::SpannedError;
|
use ron::de::SpannedError;
|
||||||
@ -337,7 +337,7 @@ impl AssetLoader for AnimationGraphAssetLoader {
|
|||||||
|
|
||||||
async fn load<'a>(
|
async fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
reader: &'a mut Reader<'_>,
|
reader: &'a mut dyn Reader,
|
||||||
_: &'a Self::Settings,
|
_: &'a Self::Settings,
|
||||||
load_context: &'a mut LoadContext<'_>,
|
load_context: &'a mut LoadContext<'_>,
|
||||||
) -> Result<Self::Asset, Self::Error> {
|
) -> Result<Self::Asset, Self::Error> {
|
||||||
|
@ -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_tasks = { path = "../bevy_tasks", version = "0.14.0-dev" }
|
||||||
bevy_utils = { path = "../bevy_utils", version = "0.14.0-dev" }
|
bevy_utils = { path = "../bevy_utils", version = "0.14.0-dev" }
|
||||||
|
|
||||||
|
stackfuture = "0.3"
|
||||||
async-broadcast = "0.5"
|
async-broadcast = "0.5"
|
||||||
async-fs = "2.0"
|
async-fs = "2.0"
|
||||||
async-lock = "3.0"
|
async-lock = "3.0"
|
||||||
|
@ -16,7 +16,7 @@ use std::{ffi::CString, path::Path};
|
|||||||
pub struct AndroidAssetReader;
|
pub struct AndroidAssetReader;
|
||||||
|
|
||||||
impl AssetReader for AndroidAssetReader {
|
impl AssetReader for AndroidAssetReader {
|
||||||
async fn read<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> {
|
async fn read<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
|
||||||
let asset_manager = bevy_winit::ANDROID_APP
|
let asset_manager = bevy_winit::ANDROID_APP
|
||||||
.get()
|
.get()
|
||||||
.expect("Bevy must be setup with the #[bevy_main] macro on Android")
|
.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())
|
.open(&CString::new(path.to_str().unwrap()).unwrap())
|
||||||
.ok_or(AssetReaderError::NotFound(path.to_path_buf()))?;
|
.ok_or(AssetReaderError::NotFound(path.to_path_buf()))?;
|
||||||
let bytes = opened_asset.buffer()?;
|
let bytes = opened_asset.buffer()?;
|
||||||
let reader: Box<Reader> = Box::new(VecReader::new(bytes.to_vec()));
|
let reader = VecReader::new(bytes.to_vec());
|
||||||
Ok(reader)
|
Ok(reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> {
|
async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
|
||||||
let meta_path = get_meta_path(path);
|
let meta_path = get_meta_path(path);
|
||||||
let asset_manager = bevy_winit::ANDROID_APP
|
let asset_manager = bevy_winit::ANDROID_APP
|
||||||
.get()
|
.get()
|
||||||
@ -39,7 +39,7 @@ impl AssetReader for AndroidAssetReader {
|
|||||||
.open(&CString::new(meta_path.to_str().unwrap()).unwrap())
|
.open(&CString::new(meta_path.to_str().unwrap()).unwrap())
|
||||||
.ok_or(AssetReaderError::NotFound(meta_path))?;
|
.ok_or(AssetReaderError::NotFound(meta_path))?;
|
||||||
let bytes = opened_asset.buffer()?;
|
let bytes = opened_asset.buffer()?;
|
||||||
let reader: Box<Reader> = Box::new(VecReader::new(bytes.to_vec()));
|
let reader = VecReader::new(bytes.to_vec());
|
||||||
Ok(reader)
|
Ok(reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,40 +9,30 @@ use std::path::Path;
|
|||||||
|
|
||||||
use super::{FileAssetReader, FileAssetWriter};
|
use super::{FileAssetReader, FileAssetWriter};
|
||||||
|
|
||||||
|
impl Reader for File {}
|
||||||
|
|
||||||
impl AssetReader for FileAssetReader {
|
impl AssetReader for FileAssetReader {
|
||||||
async fn read<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> {
|
async fn read<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
|
||||||
let full_path = self.root_path.join(path);
|
let full_path = self.root_path.join(path);
|
||||||
match File::open(&full_path).await {
|
File::open(&full_path).await.map_err(|e| {
|
||||||
Ok(file) => {
|
if e.kind() == std::io::ErrorKind::NotFound {
|
||||||
let reader: Box<Reader> = Box::new(file);
|
AssetReaderError::NotFound(full_path)
|
||||||
Ok(reader)
|
} 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<Box<Reader<'a>>, AssetReaderError> {
|
async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
|
||||||
let meta_path = get_meta_path(path);
|
let meta_path = get_meta_path(path);
|
||||||
let full_path = self.root_path.join(meta_path);
|
let full_path = self.root_path.join(meta_path);
|
||||||
match File::open(&full_path).await {
|
File::open(&full_path).await.map_err(|e| {
|
||||||
Ok(file) => {
|
if e.kind() == std::io::ErrorKind::NotFound {
|
||||||
let reader: Box<Reader> = Box::new(file);
|
AssetReaderError::NotFound(full_path)
|
||||||
Ok(reader)
|
} 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>(
|
async fn read_directory<'a>(
|
||||||
|
@ -42,6 +42,16 @@ impl AsyncSeek for FileReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Reader for FileReader {
|
||||||
|
fn read_to_end<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
buf: &'a mut Vec<u8>,
|
||||||
|
) -> stackfuture::StackFuture<'a, std::io::Result<usize>, { crate::io::STACK_FUTURE_SIZE }>
|
||||||
|
{
|
||||||
|
stackfuture::StackFuture::from(async { self.0.read_to_end(buf) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct FileWriter(File);
|
struct FileWriter(File);
|
||||||
|
|
||||||
impl AsyncWrite for FileWriter {
|
impl AsyncWrite for FileWriter {
|
||||||
@ -87,13 +97,10 @@ impl Stream for DirReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AssetReader for FileAssetReader {
|
impl AssetReader for FileAssetReader {
|
||||||
async fn read<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> {
|
async fn read<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
|
||||||
let full_path = self.root_path.join(path);
|
let full_path = self.root_path.join(path);
|
||||||
match File::open(&full_path) {
|
match File::open(&full_path) {
|
||||||
Ok(file) => {
|
Ok(file) => Ok(FileReader(file)),
|
||||||
let reader: Box<Reader> = Box::new(FileReader(file));
|
|
||||||
Ok(reader)
|
|
||||||
}
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if e.kind() == std::io::ErrorKind::NotFound {
|
if e.kind() == std::io::ErrorKind::NotFound {
|
||||||
Err(AssetReaderError::NotFound(full_path))
|
Err(AssetReaderError::NotFound(full_path))
|
||||||
@ -104,14 +111,11 @@ impl AssetReader for FileAssetReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> {
|
async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
|
||||||
let meta_path = get_meta_path(path);
|
let meta_path = get_meta_path(path);
|
||||||
let full_path = self.root_path.join(meta_path);
|
let full_path = self.root_path.join(meta_path);
|
||||||
match File::open(&full_path) {
|
match File::open(&full_path) {
|
||||||
Ok(file) => {
|
Ok(file) => Ok(FileReader(file)),
|
||||||
let reader: Box<Reader> = Box::new(FileReader(file));
|
|
||||||
Ok(reader)
|
|
||||||
}
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if e.kind() == std::io::ErrorKind::NotFound {
|
if e.kind() == std::io::ErrorKind::NotFound {
|
||||||
Err(AssetReaderError::NotFound(full_path))
|
Err(AssetReaderError::NotFound(full_path))
|
||||||
|
@ -55,7 +55,7 @@ impl<R: AssetReader> GatedReader<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<R: AssetReader> AssetReader for GatedReader<R> {
|
impl<R: AssetReader> AssetReader for GatedReader<R> {
|
||||||
async fn read<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> {
|
async fn read<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
|
||||||
let receiver = {
|
let receiver = {
|
||||||
let mut gates = self.gates.write();
|
let mut gates = self.gates.write();
|
||||||
let gates = gates
|
let gates = gates
|
||||||
@ -68,7 +68,7 @@ impl<R: AssetReader> AssetReader for GatedReader<R> {
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> {
|
async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
|
||||||
self.reader.read_meta(path).await
|
self.reader.read_meta(path).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,29 +277,41 @@ impl AsyncSeek for DataReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Reader for DataReader {
|
||||||
|
fn read_to_end<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
buf: &'a mut Vec<u8>,
|
||||||
|
) -> stackfuture::StackFuture<'a, std::io::Result<usize>, { 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 {
|
impl AssetReader for MemoryAssetReader {
|
||||||
async fn read<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> {
|
async fn read<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
|
||||||
self.root
|
self.root
|
||||||
.get_asset(path)
|
.get_asset(path)
|
||||||
.map(|data| {
|
.map(|data| DataReader {
|
||||||
let reader: Box<Reader> = Box::new(DataReader {
|
data,
|
||||||
data,
|
bytes_read: 0,
|
||||||
bytes_read: 0,
|
|
||||||
});
|
|
||||||
reader
|
|
||||||
})
|
})
|
||||||
.ok_or_else(|| AssetReaderError::NotFound(path.to_path_buf()))
|
.ok_or_else(|| AssetReaderError::NotFound(path.to_path_buf()))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> {
|
async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
|
||||||
self.root
|
self.root
|
||||||
.get_metadata(path)
|
.get_metadata(path)
|
||||||
.map(|data| {
|
.map(|data| DataReader {
|
||||||
let reader: Box<Reader> = Box::new(DataReader {
|
data,
|
||||||
data,
|
bytes_read: 0,
|
||||||
bytes_read: 0,
|
|
||||||
});
|
|
||||||
reader
|
|
||||||
})
|
})
|
||||||
.ok_or_else(|| AssetReaderError::NotFound(path.to_path_buf()))
|
.ok_or_else(|| AssetReaderError::NotFound(path.to_path_buf()))
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ pub mod wasm;
|
|||||||
|
|
||||||
mod source;
|
mod source;
|
||||||
|
|
||||||
pub use futures_lite::{AsyncReadExt, AsyncWriteExt};
|
pub use futures_lite::AsyncWriteExt;
|
||||||
pub use source::*;
|
pub use source::*;
|
||||||
|
|
||||||
use bevy_utils::{BoxedFuture, ConditionalSendFuture};
|
use bevy_utils::{BoxedFuture, ConditionalSendFuture};
|
||||||
@ -72,11 +72,59 @@ impl From<std::io::Error> 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<T: AsyncRead + AsyncSeek> 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<u8>,
|
||||||
|
) -> StackFuture<'a, std::io::Result<usize>, STACK_FUTURE_SIZE> {
|
||||||
|
let future = futures_lite::AsyncReadExt::read_to_end(self, buf);
|
||||||
|
StackFuture::from(future)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Reader for Box<dyn Reader + '_> {
|
||||||
|
fn read_to_end<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
buf: &'a mut Vec<u8>,
|
||||||
|
) -> StackFuture<'a, std::io::Result<usize>, STACK_FUTURE_SIZE> {
|
||||||
|
(**self).read_to_end(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A future that returns a value or an [`AssetReaderError`]
|
||||||
|
pub trait AssetReaderFuture:
|
||||||
|
ConditionalSendFuture<Output = Result<Self::Value, AssetReaderError>>
|
||||||
|
{
|
||||||
|
type Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F, T> AssetReaderFuture for F
|
||||||
|
where
|
||||||
|
F: ConditionalSendFuture<Output = Result<T, AssetReaderError>>,
|
||||||
|
{
|
||||||
|
type Value = T;
|
||||||
|
}
|
||||||
|
|
||||||
/// Performs read operations on an asset storage. [`AssetReader`] exposes a "virtual filesystem"
|
/// 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
|
/// 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`].
|
/// Also see [`AssetWriter`].
|
||||||
pub trait AssetReader: Send + Sync + 'static {
|
pub trait AssetReader: Send + Sync + 'static {
|
||||||
/// Returns a future to load the full file data at the provided path.
|
/// Returns a future to load the full file data at the provided path.
|
||||||
fn read<'a>(
|
///
|
||||||
&'a self,
|
/// # Note for implementors
|
||||||
path: &'a Path,
|
/// The preferred style for implementing this method is an `async fn` returning an opaque type.
|
||||||
) -> impl ConditionalSendFuture<Output = Result<Box<Reader<'a>>, AssetReaderError>>;
|
///
|
||||||
|
/// ```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<impl Reader + 'a, AssetReaderError> {
|
||||||
|
/// // ...
|
||||||
|
/// # let val: Box<dyn Reader> = unimplemented!(); Ok(val)
|
||||||
|
/// }
|
||||||
|
/// # async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
|
||||||
|
/// # let val: Box<dyn Reader> = unimplemented!(); Ok(val) }
|
||||||
|
/// # async fn read_directory<'a>(&'a self, path: &'a Path) -> Result<Box<PathStream>, AssetReaderError> { unimplemented!() }
|
||||||
|
/// # async fn is_directory<'a>(&'a self, path: &'a Path) -> Result<bool, AssetReaderError> { unimplemented!() }
|
||||||
|
/// # async fn read_meta_bytes<'a>(&'a self, path: &'a Path) -> Result<Vec<u8>, AssetReaderError> { unimplemented!() }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
fn read<'a>(&'a self, path: &'a Path) -> impl AssetReaderFuture<Value: Reader + 'a>;
|
||||||
/// Returns a future to load the full file data at the provided path.
|
/// Returns a future to load the full file data at the provided path.
|
||||||
fn read_meta<'a>(
|
fn read_meta<'a>(&'a self, path: &'a Path) -> impl AssetReaderFuture<Value: Reader + 'a>;
|
||||||
&'a self,
|
|
||||||
path: &'a Path,
|
|
||||||
) -> impl ConditionalSendFuture<Output = Result<Box<Reader<'a>>, AssetReaderError>>;
|
|
||||||
/// Returns an iterator of directory entry names at the provided path.
|
/// Returns an iterator of directory entry names at the provided path.
|
||||||
fn read_directory<'a>(
|
fn read_directory<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
@ -123,13 +185,15 @@ pub trait AssetReader: Send + Sync + 'static {
|
|||||||
/// as [`AssetReader`] isn't currently object safe.
|
/// as [`AssetReader`] isn't currently object safe.
|
||||||
pub trait ErasedAssetReader: Send + Sync + 'static {
|
pub trait ErasedAssetReader: Send + Sync + 'static {
|
||||||
/// Returns a future to load the full file data at the provided path.
|
/// Returns a future to load the full file data at the provided path.
|
||||||
fn read<'a>(&'a self, path: &'a Path)
|
fn read<'a>(
|
||||||
-> BoxedFuture<Result<Box<Reader<'a>>, AssetReaderError>>;
|
&'a self,
|
||||||
|
path: &'a Path,
|
||||||
|
) -> BoxedFuture<Result<Box<dyn Reader + 'a>, AssetReaderError>>;
|
||||||
/// Returns a future to load the full file data at the provided path.
|
/// Returns a future to load the full file data at the provided path.
|
||||||
fn read_meta<'a>(
|
fn read_meta<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
path: &'a Path,
|
path: &'a Path,
|
||||||
) -> BoxedFuture<Result<Box<Reader<'a>>, AssetReaderError>>;
|
) -> BoxedFuture<Result<Box<dyn Reader + 'a>, AssetReaderError>>;
|
||||||
/// Returns an iterator of directory entry names at the provided path.
|
/// Returns an iterator of directory entry names at the provided path.
|
||||||
fn read_directory<'a>(
|
fn read_directory<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
@ -149,14 +213,20 @@ impl<T: AssetReader> ErasedAssetReader for T {
|
|||||||
fn read<'a>(
|
fn read<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
path: &'a Path,
|
path: &'a Path,
|
||||||
) -> BoxedFuture<Result<Box<Reader<'a>>, AssetReaderError>> {
|
) -> BoxedFuture<Result<Box<dyn Reader + 'a>, AssetReaderError>> {
|
||||||
Box::pin(Self::read(self, path))
|
Box::pin(async {
|
||||||
|
let reader = Self::read(self, path).await?;
|
||||||
|
Ok(Box::new(reader) as Box<dyn Reader>)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn read_meta<'a>(
|
fn read_meta<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
path: &'a Path,
|
path: &'a Path,
|
||||||
) -> BoxedFuture<Result<Box<Reader<'a>>, AssetReaderError>> {
|
) -> BoxedFuture<Result<Box<dyn Reader + 'a>, AssetReaderError>> {
|
||||||
Box::pin(Self::read_meta(self, path))
|
Box::pin(async {
|
||||||
|
let reader = Self::read_meta(self, path).await?;
|
||||||
|
Ok(Box::new(reader) as Box<dyn Reader>)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn read_directory<'a>(
|
fn read_directory<'a>(
|
||||||
&'a self,
|
&'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<u8>,
|
||||||
|
) -> StackFuture<'a, std::io::Result<usize>, 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]`].
|
/// An [`AsyncRead`] implementation capable of reading a [`&[u8]`].
|
||||||
pub struct SliceReader<'a> {
|
pub struct SliceReader<'a> {
|
||||||
bytes: &'a [u8],
|
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<u8>,
|
||||||
|
) -> StackFuture<'a, std::io::Result<usize>, 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.
|
/// Appends `.meta` to the given path.
|
||||||
pub(crate) fn get_meta_path(path: &Path) -> PathBuf {
|
pub(crate) fn get_meta_path(path: &Path) -> PathBuf {
|
||||||
let mut meta_path = path.to_path_buf();
|
let mut meta_path = path.to_path_buf();
|
||||||
|
@ -51,7 +51,7 @@ impl ProcessorGatedReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AssetReader for ProcessorGatedReader {
|
impl AssetReader for ProcessorGatedReader {
|
||||||
async fn read<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> {
|
async fn read<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
|
||||||
let asset_path = AssetPath::from(path.to_path_buf()).with_source(self.source.clone());
|
let asset_path = AssetPath::from(path.to_path_buf()).with_source(self.source.clone());
|
||||||
trace!("Waiting for processing to finish before reading {asset_path}");
|
trace!("Waiting for processing to finish before reading {asset_path}");
|
||||||
let process_result = self
|
let process_result = self
|
||||||
@ -67,11 +67,11 @@ impl AssetReader for ProcessorGatedReader {
|
|||||||
trace!("Processing finished with {asset_path}, reading {process_result:?}",);
|
trace!("Processing finished with {asset_path}, reading {process_result:?}",);
|
||||||
let lock = self.get_transaction_lock(&asset_path).await?;
|
let lock = self.get_transaction_lock(&asset_path).await?;
|
||||||
let asset_reader = self.reader.read(path).await?;
|
let asset_reader = self.reader.read(path).await?;
|
||||||
let reader: Box<Reader<'a>> = Box::new(TransactionLockedReader::new(asset_reader, lock));
|
let reader = TransactionLockedReader::new(asset_reader, lock);
|
||||||
Ok(reader)
|
Ok(reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> {
|
async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
|
||||||
let asset_path = AssetPath::from(path.to_path_buf()).with_source(self.source.clone());
|
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}",);
|
trace!("Waiting for processing to finish before reading meta for {asset_path}",);
|
||||||
let process_result = self
|
let process_result = self
|
||||||
@ -87,7 +87,7 @@ impl AssetReader for ProcessorGatedReader {
|
|||||||
trace!("Processing finished with {process_result:?}, reading meta for {asset_path}",);
|
trace!("Processing finished with {process_result:?}, reading meta for {asset_path}",);
|
||||||
let lock = self.get_transaction_lock(&asset_path).await?;
|
let lock = self.get_transaction_lock(&asset_path).await?;
|
||||||
let meta_reader = self.reader.read_meta(path).await?;
|
let meta_reader = self.reader.read_meta(path).await?;
|
||||||
let reader: Box<Reader<'a>> = Box::new(TransactionLockedReader::new(meta_reader, lock));
|
let reader = TransactionLockedReader::new(meta_reader, lock);
|
||||||
Ok(reader)
|
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.
|
/// An [`AsyncRead`] impl that will hold its asset's transaction lock until [`TransactionLockedReader`] is dropped.
|
||||||
pub struct TransactionLockedReader<'a> {
|
pub struct TransactionLockedReader<'a> {
|
||||||
reader: Box<Reader<'a>>,
|
reader: Box<dyn Reader + 'a>,
|
||||||
_file_transaction_lock: RwLockReadGuardArc<()>,
|
_file_transaction_lock: RwLockReadGuardArc<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TransactionLockedReader<'a> {
|
impl<'a> TransactionLockedReader<'a> {
|
||||||
fn new(reader: Box<Reader<'a>>, file_transaction_lock: RwLockReadGuardArc<()>) -> Self {
|
fn new(reader: Box<dyn Reader + 'a>, file_transaction_lock: RwLockReadGuardArc<()>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
reader,
|
reader,
|
||||||
_file_transaction_lock: file_transaction_lock,
|
_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(
|
fn poll_read(
|
||||||
mut self: Pin<&mut Self>,
|
mut self: Pin<&mut Self>,
|
||||||
cx: &mut std::task::Context<'_>,
|
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(
|
fn poll_seek(
|
||||||
mut self: Pin<&mut Self>,
|
mut self: Pin<&mut Self>,
|
||||||
cx: &mut std::task::Context<'_>,
|
cx: &mut std::task::Context<'_>,
|
||||||
@ -151,3 +151,12 @@ impl<'a> AsyncSeek for TransactionLockedReader<'a> {
|
|||||||
Pin::new(&mut self.reader).poll_seek(cx, pos)
|
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<u8>,
|
||||||
|
) -> stackfuture::StackFuture<'a, std::io::Result<usize>, { super::STACK_FUTURE_SIZE }> {
|
||||||
|
self.reader.read_to_end(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -51,7 +51,7 @@ fn js_value_to_err(context: &str) -> impl FnOnce(JsValue) -> std::io::Error + '_
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl HttpWasmAssetReader {
|
impl HttpWasmAssetReader {
|
||||||
async fn fetch_bytes<'a>(&self, path: PathBuf) -> Result<Box<Reader<'a>>, AssetReaderError> {
|
async fn fetch_bytes<'a>(&self, path: PathBuf) -> Result<impl Reader, AssetReaderError> {
|
||||||
// The JS global scope includes a self-reference via a specialising name, which can be used to determine the type of global context available.
|
// 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 global: Global = js_sys::global().unchecked_into();
|
||||||
let promise = if !global.window().is_undefined() {
|
let promise = if !global.window().is_undefined() {
|
||||||
@ -77,7 +77,7 @@ impl HttpWasmAssetReader {
|
|||||||
200 => {
|
200 => {
|
||||||
let data = JsFuture::from(resp.array_buffer().unwrap()).await.unwrap();
|
let data = JsFuture::from(resp.array_buffer().unwrap()).await.unwrap();
|
||||||
let bytes = Uint8Array::new(&data).to_vec();
|
let bytes = Uint8Array::new(&data).to_vec();
|
||||||
let reader: Box<Reader> = Box::new(VecReader::new(bytes));
|
let reader = VecReader::new(bytes);
|
||||||
Ok(reader)
|
Ok(reader)
|
||||||
}
|
}
|
||||||
404 => Err(AssetReaderError::NotFound(path)),
|
404 => Err(AssetReaderError::NotFound(path)),
|
||||||
@ -87,12 +87,12 @@ impl HttpWasmAssetReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AssetReader for HttpWasmAssetReader {
|
impl AssetReader for HttpWasmAssetReader {
|
||||||
async fn read<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> {
|
async fn read<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
|
||||||
let path = self.root_path.join(path);
|
let path = self.root_path.join(path);
|
||||||
self.fetch_bytes(path).await
|
self.fetch_bytes(path).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> {
|
async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
|
||||||
let meta_path = get_meta_path(&self.root_path.join(path));
|
let meta_path = get_meta_path(&self.root_path.join(path));
|
||||||
self.fetch_bytes(meta_path).await
|
self.fetch_bytes(meta_path).await
|
||||||
}
|
}
|
||||||
|
@ -460,7 +460,6 @@ mod tests {
|
|||||||
use bevy_log::LogPlugin;
|
use bevy_log::LogPlugin;
|
||||||
use bevy_reflect::TypePath;
|
use bevy_reflect::TypePath;
|
||||||
use bevy_utils::{Duration, HashMap};
|
use bevy_utils::{Duration, HashMap};
|
||||||
use futures_lite::AsyncReadExt;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{path::Path, sync::Arc};
|
use std::{path::Path, sync::Arc};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
@ -510,7 +509,7 @@ mod tests {
|
|||||||
|
|
||||||
async fn load<'a>(
|
async fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
reader: &'a mut Reader<'_>,
|
reader: &'a mut dyn Reader,
|
||||||
_settings: &'a Self::Settings,
|
_settings: &'a Self::Settings,
|
||||||
load_context: &'a mut LoadContext<'_>,
|
load_context: &'a mut LoadContext<'_>,
|
||||||
) -> Result<Self::Asset, Self::Error> {
|
) -> Result<Self::Asset, Self::Error> {
|
||||||
@ -584,13 +583,13 @@ mod tests {
|
|||||||
async fn read_meta<'a>(
|
async fn read_meta<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
path: &'a Path,
|
path: &'a Path,
|
||||||
) -> Result<Box<bevy_asset::io::Reader<'a>>, AssetReaderError> {
|
) -> Result<impl bevy_asset::io::Reader + 'a, AssetReaderError> {
|
||||||
self.memory_reader.read_meta(path).await
|
self.memory_reader.read_meta(path).await
|
||||||
}
|
}
|
||||||
async fn read<'a>(
|
async fn read<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
path: &'a Path,
|
path: &'a Path,
|
||||||
) -> Result<Box<bevy_asset::io::Reader<'a>>, bevy_asset::io::AssetReaderError> {
|
) -> Result<impl bevy_asset::io::Reader + 'a, bevy_asset::io::AssetReaderError> {
|
||||||
let attempt_number = {
|
let attempt_number = {
|
||||||
let mut attempt_counters = self.attempt_counters.lock().unwrap();
|
let mut attempt_counters = self.attempt_counters.lock().unwrap();
|
||||||
if let Some(existing) = attempt_counters.get_mut(path) {
|
if let Some(existing) = attempt_counters.get_mut(path) {
|
||||||
|
@ -9,7 +9,6 @@ use crate::{
|
|||||||
use bevy_ecs::world::World;
|
use bevy_ecs::world::World;
|
||||||
use bevy_utils::{BoxedFuture, ConditionalSendFuture, CowArc, HashMap, HashSet};
|
use bevy_utils::{BoxedFuture, ConditionalSendFuture, CowArc, HashMap, HashSet};
|
||||||
use downcast_rs::{impl_downcast, Downcast};
|
use downcast_rs::{impl_downcast, Downcast};
|
||||||
use futures_lite::AsyncReadExt;
|
|
||||||
use ron::error::SpannedError;
|
use ron::error::SpannedError;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
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`].
|
/// Asynchronously loads [`AssetLoader::Asset`] (and any other labeled assets) from the bytes provided by [`Reader`].
|
||||||
fn load<'a>(
|
fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
reader: &'a mut Reader,
|
reader: &'a mut dyn Reader,
|
||||||
settings: &'a Self::Settings,
|
settings: &'a Self::Settings,
|
||||||
load_context: &'a mut LoadContext,
|
load_context: &'a mut LoadContext,
|
||||||
) -> impl ConditionalSendFuture<Output = Result<Self::Asset, Self::Error>>;
|
) -> impl ConditionalSendFuture<Output = Result<Self::Asset, Self::Error>>;
|
||||||
@ -47,7 +46,7 @@ pub trait ErasedAssetLoader: Send + Sync + 'static {
|
|||||||
/// Asynchronously loads the asset(s) from the bytes provided by [`Reader`].
|
/// Asynchronously loads the asset(s) from the bytes provided by [`Reader`].
|
||||||
fn load<'a>(
|
fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
reader: &'a mut Reader,
|
reader: &'a mut dyn Reader,
|
||||||
meta: Box<dyn AssetMetaDyn>,
|
meta: Box<dyn AssetMetaDyn>,
|
||||||
load_context: LoadContext<'a>,
|
load_context: LoadContext<'a>,
|
||||||
) -> BoxedFuture<
|
) -> BoxedFuture<
|
||||||
@ -78,7 +77,7 @@ where
|
|||||||
/// Processes the asset in an asynchronous closure.
|
/// Processes the asset in an asynchronous closure.
|
||||||
fn load<'a>(
|
fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
reader: &'a mut Reader,
|
reader: &'a mut dyn Reader,
|
||||||
meta: Box<dyn AssetMetaDyn>,
|
meta: Box<dyn AssetMetaDyn>,
|
||||||
mut load_context: LoadContext<'a>,
|
mut load_context: LoadContext<'a>,
|
||||||
) -> BoxedFuture<
|
) -> BoxedFuture<
|
||||||
@ -519,7 +518,7 @@ impl<'a> LoadContext<'a> {
|
|||||||
path: AssetPath<'static>,
|
path: AssetPath<'static>,
|
||||||
meta: Box<dyn AssetMetaDyn>,
|
meta: Box<dyn AssetMetaDyn>,
|
||||||
loader: &dyn ErasedAssetLoader,
|
loader: &dyn ErasedAssetLoader,
|
||||||
reader: &mut Reader<'_>,
|
reader: &mut dyn Reader,
|
||||||
) -> Result<ErasedLoadedAsset, LoadDirectError> {
|
) -> Result<ErasedLoadedAsset, LoadDirectError> {
|
||||||
let loaded_asset = self
|
let loaded_asset = self
|
||||||
.asset_server
|
.asset_server
|
||||||
|
@ -11,16 +11,16 @@ use std::any::TypeId;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
// Utility type for handling the sources of reader references
|
// Utility type for handling the sources of reader references
|
||||||
enum ReaderRef<'a, 'b> {
|
enum ReaderRef<'a> {
|
||||||
Borrowed(&'a mut Reader<'b>),
|
Borrowed(&'a mut dyn Reader),
|
||||||
Boxed(Box<Reader<'b>>),
|
Boxed(Box<dyn Reader + 'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> ReaderRef<'a, 'b> {
|
impl ReaderRef<'_> {
|
||||||
pub fn as_mut(&mut self) -> &mut Reader {
|
pub fn as_mut(&mut self) -> &mut dyn Reader {
|
||||||
match self {
|
match self {
|
||||||
ReaderRef::Borrowed(r) => r,
|
ReaderRef::Borrowed(r) => &mut **r,
|
||||||
ReaderRef::Boxed(b) => &mut *b,
|
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
|
/// - `reader`: the lifetime of the [`Reader`] reference used to read the asset data
|
||||||
pub struct DirectNestedLoader<'ctx, 'builder, 'reader> {
|
pub struct DirectNestedLoader<'ctx, 'builder, 'reader> {
|
||||||
base: NestedLoader<'ctx, 'builder>,
|
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> {
|
impl<'ctx: 'reader, 'builder, 'reader> DirectNestedLoader<'ctx, 'builder, 'reader> {
|
||||||
/// Specify the reader to use to read the asset data.
|
/// Specify the reader to use to read the asset data.
|
||||||
#[must_use]
|
#[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.reader = Some(reader);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -196,7 +196,7 @@ impl AssetLoader for () {
|
|||||||
type Error = std::io::Error;
|
type Error = std::io::Error;
|
||||||
async fn load<'a>(
|
async fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
_reader: &'a mut crate::io::Reader<'_>,
|
_reader: &'a mut dyn crate::io::Reader,
|
||||||
_settings: &'a Self::Settings,
|
_settings: &'a Self::Settings,
|
||||||
_load_context: &'a mut crate::LoadContext<'_>,
|
_load_context: &'a mut crate::LoadContext<'_>,
|
||||||
) -> Result<Self::Asset, Self::Error> {
|
) -> Result<Self::Asset, Self::Error> {
|
||||||
|
@ -310,7 +310,7 @@ impl<T: AssetLoader> AssetLoader for InstrumentedAssetLoader<T> {
|
|||||||
|
|
||||||
fn load<'a>(
|
fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
reader: &'a mut crate::io::Reader,
|
reader: &'a mut dyn crate::io::Reader,
|
||||||
settings: &'a Self::Settings,
|
settings: &'a Self::Settings,
|
||||||
load_context: &'a mut crate::LoadContext,
|
load_context: &'a mut crate::LoadContext,
|
||||||
) -> impl ConditionalSendFuture<Output = Result<Self::Asset, Self::Error>> {
|
) -> impl ConditionalSendFuture<Output = Result<Self::Asset, Self::Error>> {
|
||||||
@ -382,7 +382,7 @@ mod tests {
|
|||||||
|
|
||||||
async fn load<'a>(
|
async fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
_: &'a mut crate::io::Reader<'_>,
|
_: &'a mut dyn crate::io::Reader,
|
||||||
_: &'a Self::Settings,
|
_: &'a Self::Settings,
|
||||||
_: &'a mut crate::LoadContext<'_>,
|
_: &'a mut crate::LoadContext<'_>,
|
||||||
) -> Result<Self::Asset, Self::Error> {
|
) -> Result<Self::Asset, Self::Error> {
|
||||||
|
@ -1065,7 +1065,7 @@ impl AssetServer {
|
|||||||
(
|
(
|
||||||
Box<dyn AssetMetaDyn>,
|
Box<dyn AssetMetaDyn>,
|
||||||
Arc<dyn ErasedAssetLoader>,
|
Arc<dyn ErasedAssetLoader>,
|
||||||
Box<Reader<'a>>,
|
Box<dyn Reader + 'a>,
|
||||||
),
|
),
|
||||||
AssetLoadError,
|
AssetLoadError,
|
||||||
> {
|
> {
|
||||||
@ -1169,7 +1169,7 @@ impl AssetServer {
|
|||||||
asset_path: &AssetPath<'_>,
|
asset_path: &AssetPath<'_>,
|
||||||
meta: Box<dyn AssetMetaDyn>,
|
meta: Box<dyn AssetMetaDyn>,
|
||||||
loader: &dyn ErasedAssetLoader,
|
loader: &dyn ErasedAssetLoader,
|
||||||
reader: &mut Reader<'_>,
|
reader: &mut dyn Reader,
|
||||||
load_dependencies: bool,
|
load_dependencies: bool,
|
||||||
populate_hashes: bool,
|
populate_hashes: bool,
|
||||||
) -> Result<ErasedLoadedAsset, AssetLoadError> {
|
) -> Result<ErasedLoadedAsset, AssetLoadError> {
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
use bevy_asset::{
|
use bevy_asset::{io::Reader, Asset, AssetLoader, LoadContext};
|
||||||
io::{AsyncReadExt, Reader},
|
|
||||||
Asset, AssetLoader, LoadContext,
|
|
||||||
};
|
|
||||||
use bevy_reflect::TypePath;
|
use bevy_reflect::TypePath;
|
||||||
use std::{io::Cursor, sync::Arc};
|
use std::{io::Cursor, sync::Arc};
|
||||||
|
|
||||||
@ -46,7 +43,7 @@ impl AssetLoader for AudioLoader {
|
|||||||
|
|
||||||
async fn load<'a>(
|
async fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
reader: &'a mut Reader<'_>,
|
reader: &'a mut dyn Reader,
|
||||||
_settings: &'a Self::Settings,
|
_settings: &'a Self::Settings,
|
||||||
_load_context: &'a mut LoadContext<'_>,
|
_load_context: &'a mut LoadContext<'_>,
|
||||||
) -> Result<AudioSource, Self::Error> {
|
) -> Result<AudioSource, Self::Error> {
|
||||||
|
@ -6,7 +6,7 @@ use crate::{
|
|||||||
#[cfg(feature = "bevy_animation")]
|
#[cfg(feature = "bevy_animation")]
|
||||||
use bevy_animation::{AnimationTarget, AnimationTargetId};
|
use bevy_animation::{AnimationTarget, AnimationTargetId};
|
||||||
use bevy_asset::{
|
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_color::{Color, LinearRgba};
|
||||||
use bevy_core::Name;
|
use bevy_core::Name;
|
||||||
@ -176,7 +176,7 @@ impl AssetLoader for GltfLoader {
|
|||||||
type Error = GltfError;
|
type Error = GltfError;
|
||||||
async fn load<'a>(
|
async fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
reader: &'a mut Reader<'_>,
|
reader: &'a mut dyn Reader,
|
||||||
settings: &'a GltfLoaderSettings,
|
settings: &'a GltfLoaderSettings,
|
||||||
load_context: &'a mut LoadContext<'_>,
|
load_context: &'a mut LoadContext<'_>,
|
||||||
) -> Result<Gltf, Self::Error> {
|
) -> Result<Gltf, Self::Error> {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use bevy_asset::{
|
use bevy_asset::{
|
||||||
io::{AsyncReadAndSeek, Reader, Writer},
|
io::{Reader, Writer},
|
||||||
saver::{AssetSaver, SavedAsset},
|
saver::{AssetSaver, SavedAsset},
|
||||||
Asset, AssetLoader, AsyncReadExt, AsyncWriteExt, LoadContext,
|
Asset, AssetLoader, AsyncReadExt, AsyncWriteExt, LoadContext,
|
||||||
};
|
};
|
||||||
@ -85,7 +85,7 @@ impl AssetLoader for MeshletMeshSaverLoad {
|
|||||||
|
|
||||||
async fn load<'a>(
|
async fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
reader: &'a mut Reader<'_>,
|
reader: &'a mut dyn Reader,
|
||||||
_settings: &'a Self::Settings,
|
_settings: &'a Self::Settings,
|
||||||
_load_context: &'a mut LoadContext<'_>,
|
_load_context: &'a mut LoadContext<'_>,
|
||||||
) -> Result<Self::Asset, Self::Error> {
|
) -> Result<Self::Asset, Self::Error> {
|
||||||
@ -144,9 +144,7 @@ pub enum MeshletMeshSaveOrLoadError {
|
|||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_u64(
|
async fn read_u64(reader: &mut dyn Reader) -> Result<u64, bincode::Error> {
|
||||||
reader: &mut (dyn AsyncReadAndSeek + Sync + Send + Unpin),
|
|
||||||
) -> Result<u64, bincode::Error> {
|
|
||||||
let mut bytes = [0u8; 8];
|
let mut bytes = [0u8; 8];
|
||||||
reader.read_exact(&mut bytes).await?;
|
reader.read_exact(&mut bytes).await?;
|
||||||
Ok(u64::from_le_bytes(bytes))
|
Ok(u64::from_le_bytes(bytes))
|
||||||
|
@ -3,7 +3,6 @@ use crate::define_atomic_id;
|
|||||||
use bevy_asset::{io::Reader, Asset, AssetLoader, AssetPath, Handle, LoadContext};
|
use bevy_asset::{io::Reader, Asset, AssetLoader, AssetPath, Handle, LoadContext};
|
||||||
use bevy_reflect::TypePath;
|
use bevy_reflect::TypePath;
|
||||||
use bevy_utils::tracing::error;
|
use bevy_utils::tracing::error;
|
||||||
use futures_lite::AsyncReadExt;
|
|
||||||
use std::{borrow::Cow, marker::Copy};
|
use std::{borrow::Cow, marker::Copy};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
@ -261,7 +260,7 @@ impl AssetLoader for ShaderLoader {
|
|||||||
type Error = ShaderLoaderError;
|
type Error = ShaderLoaderError;
|
||||||
async fn load<'a>(
|
async fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
reader: &'a mut Reader<'_>,
|
reader: &'a mut dyn Reader,
|
||||||
_settings: &'a Self::Settings,
|
_settings: &'a Self::Settings,
|
||||||
load_context: &'a mut LoadContext<'_>,
|
load_context: &'a mut LoadContext<'_>,
|
||||||
) -> Result<Shader, Self::Error> {
|
) -> Result<Shader, Self::Error> {
|
||||||
|
@ -2,10 +2,7 @@ use crate::{
|
|||||||
render_asset::RenderAssetUsages,
|
render_asset::RenderAssetUsages,
|
||||||
texture::{Image, TextureFormatPixelInfo},
|
texture::{Image, TextureFormatPixelInfo},
|
||||||
};
|
};
|
||||||
use bevy_asset::{
|
use bevy_asset::{io::Reader, AssetLoader, LoadContext};
|
||||||
io::{AsyncReadExt, Reader},
|
|
||||||
AssetLoader, LoadContext,
|
|
||||||
};
|
|
||||||
use image::ImageDecoder;
|
use image::ImageDecoder;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
@ -37,7 +34,7 @@ impl AssetLoader for ExrTextureLoader {
|
|||||||
|
|
||||||
async fn load<'a>(
|
async fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
reader: &'a mut Reader<'_>,
|
reader: &'a mut dyn Reader,
|
||||||
settings: &'a Self::Settings,
|
settings: &'a Self::Settings,
|
||||||
_load_context: &'a mut LoadContext<'_>,
|
_load_context: &'a mut LoadContext<'_>,
|
||||||
) -> Result<Image, Self::Error> {
|
) -> Result<Image, Self::Error> {
|
||||||
|
@ -2,7 +2,7 @@ use crate::{
|
|||||||
render_asset::RenderAssetUsages,
|
render_asset::RenderAssetUsages,
|
||||||
texture::{Image, TextureFormatPixelInfo},
|
texture::{Image, TextureFormatPixelInfo},
|
||||||
};
|
};
|
||||||
use bevy_asset::{io::Reader, AssetLoader, AsyncReadExt, LoadContext};
|
use bevy_asset::{io::Reader, AssetLoader, LoadContext};
|
||||||
use image::DynamicImage;
|
use image::DynamicImage;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
@ -32,7 +32,7 @@ impl AssetLoader for HdrTextureLoader {
|
|||||||
type Error = HdrTextureLoaderError;
|
type Error = HdrTextureLoaderError;
|
||||||
async fn load<'a>(
|
async fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
reader: &'a mut Reader<'_>,
|
reader: &'a mut dyn Reader,
|
||||||
settings: &'a Self::Settings,
|
settings: &'a Self::Settings,
|
||||||
_load_context: &'a mut LoadContext<'_>,
|
_load_context: &'a mut LoadContext<'_>,
|
||||||
) -> Result<Image, Self::Error> {
|
) -> Result<Image, Self::Error> {
|
||||||
|
@ -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 bevy_ecs::prelude::{FromWorld, World};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ impl AssetLoader for ImageLoader {
|
|||||||
type Error = ImageLoaderError;
|
type Error = ImageLoaderError;
|
||||||
async fn load<'a>(
|
async fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
reader: &'a mut Reader<'_>,
|
reader: &'a mut dyn Reader,
|
||||||
settings: &'a ImageLoaderSettings,
|
settings: &'a ImageLoaderSettings,
|
||||||
load_context: &'a mut LoadContext<'_>,
|
load_context: &'a mut LoadContext<'_>,
|
||||||
) -> Result<Image, Self::Error> {
|
) -> Result<Image, Self::Error> {
|
||||||
|
@ -2,7 +2,7 @@ use crate::ron;
|
|||||||
#[cfg(feature = "serialize")]
|
#[cfg(feature = "serialize")]
|
||||||
use crate::serde::SceneDeserializer;
|
use crate::serde::SceneDeserializer;
|
||||||
use crate::DynamicScene;
|
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::reflect::AppTypeRegistry;
|
||||||
use bevy_ecs::world::{FromWorld, World};
|
use bevy_ecs::world::{FromWorld, World};
|
||||||
use bevy_reflect::TypeRegistryArc;
|
use bevy_reflect::TypeRegistryArc;
|
||||||
@ -47,7 +47,7 @@ impl AssetLoader for SceneLoader {
|
|||||||
|
|
||||||
async fn load<'a>(
|
async fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
reader: &'a mut Reader<'_>,
|
reader: &'a mut dyn Reader,
|
||||||
_settings: &'a (),
|
_settings: &'a (),
|
||||||
_load_context: &'a mut LoadContext<'_>,
|
_load_context: &'a mut LoadContext<'_>,
|
||||||
) -> Result<Self::Asset, Self::Error> {
|
) -> Result<Self::Asset, Self::Error> {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::Font;
|
use crate::Font;
|
||||||
use bevy_asset::{io::Reader, AssetLoader, AsyncReadExt, LoadContext};
|
use bevy_asset::{io::Reader, AssetLoader, LoadContext};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@ -23,7 +23,7 @@ impl AssetLoader for FontLoader {
|
|||||||
type Error = FontLoaderError;
|
type Error = FontLoaderError;
|
||||||
async fn load<'a>(
|
async fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
reader: &'a mut Reader<'_>,
|
reader: &'a mut dyn Reader,
|
||||||
_settings: &'a (),
|
_settings: &'a (),
|
||||||
_load_context: &'a mut LoadContext<'_>,
|
_load_context: &'a mut LoadContext<'_>,
|
||||||
) -> Result<Font, Self::Error> {
|
) -> Result<Font, Self::Error> {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
use bevy::{
|
use bevy::{
|
||||||
asset::{
|
asset::{
|
||||||
io::{Reader, VecReader},
|
io::{Reader, VecReader},
|
||||||
AssetLoader, AsyncReadExt, ErasedLoadedAsset, LoadContext, LoadDirectError,
|
AssetLoader, ErasedLoadedAsset, LoadContext, LoadDirectError,
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
reflect::TypePath,
|
reflect::TypePath,
|
||||||
@ -42,7 +42,7 @@ impl AssetLoader for GzAssetLoader {
|
|||||||
type Error = GzAssetLoaderError;
|
type Error = GzAssetLoaderError;
|
||||||
async fn load<'a>(
|
async fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
reader: &'a mut Reader<'_>,
|
reader: &'a mut dyn Reader,
|
||||||
_settings: &'a (),
|
_settings: &'a (),
|
||||||
load_context: &'a mut LoadContext<'_>,
|
load_context: &'a mut LoadContext<'_>,
|
||||||
) -> Result<Self::Asset, Self::Error> {
|
) -> Result<Self::Asset, Self::Error> {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Implements loader for a custom asset type.
|
//! Implements loader for a custom asset type.
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
asset::{io::Reader, AssetLoader, AsyncReadExt, LoadContext},
|
asset::{io::Reader, AssetLoader, LoadContext},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
reflect::TypePath,
|
reflect::TypePath,
|
||||||
};
|
};
|
||||||
@ -35,7 +35,7 @@ impl AssetLoader for CustomAssetLoader {
|
|||||||
type Error = CustomAssetLoaderError;
|
type Error = CustomAssetLoaderError;
|
||||||
async fn load<'a>(
|
async fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
reader: &'a mut Reader<'_>,
|
reader: &'a mut dyn Reader,
|
||||||
_settings: &'a (),
|
_settings: &'a (),
|
||||||
_load_context: &'a mut LoadContext<'_>,
|
_load_context: &'a mut LoadContext<'_>,
|
||||||
) -> Result<Self::Asset, Self::Error> {
|
) -> Result<Self::Asset, Self::Error> {
|
||||||
@ -74,7 +74,7 @@ impl AssetLoader for BlobAssetLoader {
|
|||||||
|
|
||||||
async fn load<'a>(
|
async fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
reader: &'a mut Reader<'_>,
|
reader: &'a mut dyn Reader,
|
||||||
_settings: &'a (),
|
_settings: &'a (),
|
||||||
_load_context: &'a mut LoadContext<'_>,
|
_load_context: &'a mut LoadContext<'_>,
|
||||||
) -> Result<Self::Asset, Self::Error> {
|
) -> Result<Self::Asset, Self::Error> {
|
||||||
|
@ -15,11 +15,11 @@ use std::path::Path;
|
|||||||
struct CustomAssetReader(Box<dyn ErasedAssetReader>);
|
struct CustomAssetReader(Box<dyn ErasedAssetReader>);
|
||||||
|
|
||||||
impl AssetReader for CustomAssetReader {
|
impl AssetReader for CustomAssetReader {
|
||||||
async fn read<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> {
|
async fn read<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
|
||||||
info!("Reading {:?}", path);
|
info!("Reading {:?}", path);
|
||||||
self.0.read(path).await
|
self.0.read(path).await
|
||||||
}
|
}
|
||||||
async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> {
|
async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
|
||||||
self.0.read_meta(path).await
|
self.0.read_meta(path).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ use bevy::{
|
|||||||
processor::LoadTransformAndSave,
|
processor::LoadTransformAndSave,
|
||||||
saver::{AssetSaver, SavedAsset},
|
saver::{AssetSaver, SavedAsset},
|
||||||
transformer::{AssetTransformer, TransformedAsset},
|
transformer::{AssetTransformer, TransformedAsset},
|
||||||
AssetLoader, AsyncReadExt, AsyncWriteExt, LoadContext,
|
AssetLoader, AsyncWriteExt, LoadContext,
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
reflect::TypePath,
|
reflect::TypePath,
|
||||||
@ -83,7 +83,7 @@ impl AssetLoader for TextLoader {
|
|||||||
type Error = std::io::Error;
|
type Error = std::io::Error;
|
||||||
async fn load<'a>(
|
async fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
reader: &'a mut Reader<'_>,
|
reader: &'a mut dyn Reader,
|
||||||
settings: &'a TextSettings,
|
settings: &'a TextSettings,
|
||||||
_load_context: &'a mut LoadContext<'_>,
|
_load_context: &'a mut LoadContext<'_>,
|
||||||
) -> Result<Text, Self::Error> {
|
) -> Result<Text, Self::Error> {
|
||||||
@ -137,7 +137,7 @@ impl AssetLoader for CoolTextLoader {
|
|||||||
|
|
||||||
async fn load<'a>(
|
async fn load<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
reader: &'a mut Reader<'_>,
|
reader: &'a mut dyn Reader,
|
||||||
_settings: &'a Self::Settings,
|
_settings: &'a Self::Settings,
|
||||||
load_context: &'a mut LoadContext<'_>,
|
load_context: &'a mut LoadContext<'_>,
|
||||||
) -> Result<CoolText, Self::Error> {
|
) -> Result<CoolText, Self::Error> {
|
||||||
|
Loading…
Reference in New Issue
Block a user