Add AsyncSeekForwardExt trait to allows a similar API to the previous Bevy version (#16027)

# Objective

This PR introduces an `AsyncSeekForwardExt` trait, which I forgot in my
previous PR #14194.

This new trait is analogous to `AsyncSeekExt` and allows all
implementors of `AsyncSeekForward` to directly use the `seek_forward`
function in async contexts.

## Solution

- Implement a new `AsyncSeekForwardExt` trait
- Automatically implement this trait for all types that implement
`AsyncSeekForward`

## Showcase

This new trait allows a similar API to the previous Bevy version:

```rust
#[derive(Default)]
struct UniverseLoader;

#[derive(Asset, TypePath, Debug)]
struct JustALilAsteroid([u8; 128]);

impl AssetLoader for UniverseLoader {
    type Asset = JustALilAsteroid;
    type Settings = ();
    type Error = std::io::Error;

    async fn load<'a>(
        &'a self,
        reader: &'a mut Reader<'a>,
        _settings: &'a Self::Settings,
        _context: &'a mut LoadContext<'_>,
    ) -> Result<Self::Asset, Self::Error> {
        // read the asteroids entry table
        let entry_offset: u64 = /* ... */;
        let current_offset: u64 = reader.seek_forward(0).await?;

        // jump to the entry
        reader.seek_forward(entry_offset - current_offset).await?;

        let mut asteroid_buf = [0; 128];
        reader.read_exact(&mut asteroid_buf).await?;

        Ok(JustALilAsteroid(asteroid_buf))
    }
    
    fn extensions(&self) -> &[&str] {
        &["celestial"]
    }
}
```
This commit is contained in:
Ludwig DUBOS 2024-10-25 22:08:14 +02:00 committed by GitHub
parent c6a66a7e96
commit 611ba8b98e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -23,6 +23,7 @@ pub use source::*;
use alloc::sync::Arc;
use bevy_utils::{BoxedFuture, ConditionalSendFuture};
use core::future::Future;
use core::{
mem::size_of,
pin::Pin,
@ -120,6 +121,40 @@ impl<T: ?Sized + AsyncSeekForward + Unpin> AsyncSeekForward for Box<T> {
}
}
/// Extension trait for [`AsyncSeekForward`].
pub trait AsyncSeekForwardExt: AsyncSeekForward {
/// Seek by the provided `offset` in the forwards direction, using the [`AsyncSeekForward`] trait.
fn seek_forward(&mut self, offset: u64) -> SeekForwardFuture<'_, Self>
where
Self: Unpin,
{
SeekForwardFuture {
seeker: self,
offset,
}
}
}
impl<R: AsyncSeekForward + ?Sized> AsyncSeekForwardExt for R {}
#[derive(Debug)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct SeekForwardFuture<'a, S: Unpin + ?Sized> {
seeker: &'a mut S,
offset: u64,
}
impl<S: Unpin + ?Sized> Unpin for SeekForwardFuture<'_, S> {}
impl<S: AsyncSeekForward + Unpin + ?Sized> Future for SeekForwardFuture<'_, S> {
type Output = futures_lite::io::Result<u64>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let offset = self.offset;
Pin::new(&mut *self.seeker).poll_seek_forward(cx, offset)
}
}
/// A type returned from [`AssetReader::read`], which is used to read the contents of a file
/// (or virtual file) corresponding to an asset.
///