From 96f8208ab279af99b4b7fba380a7118ed208039f Mon Sep 17 00:00:00 2001 From: Ludwig DUBOS Date: Fri, 25 Oct 2024 22:08:14 +0200 Subject: [PATCH] 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 { // 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"] } } ``` --- crates/bevy_asset/src/io/mod.rs | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/crates/bevy_asset/src/io/mod.rs b/crates/bevy_asset/src/io/mod.rs index 948382ca311cc..eceefb2e7aba6 100644 --- a/crates/bevy_asset/src/io/mod.rs +++ b/crates/bevy_asset/src/io/mod.rs @@ -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 AsyncSeekForward for Box { } } +/// 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 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 Unpin for SeekForwardFuture<'_, S> {} + +impl Future for SeekForwardFuture<'_, S> { + type Output = futures_lite::io::Result; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + 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. ///