Skip to content

Commit 117f6a1

Browse files
committed
update assets Reader to use AsyncSeekForward rather than AsyncSeek
1 parent df23b93 commit 117f6a1

File tree

5 files changed

+113
-96
lines changed

5 files changed

+113
-96
lines changed

crates/bevy_asset/src/io/file/file_asset.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,35 @@
11
use crate::io::{
2-
get_meta_path, AssetReader, AssetReaderError, AssetWriter, AssetWriterError, PathStream,
3-
Reader, Writer,
2+
get_meta_path, AssetReader, AssetReaderError, AssetWriter, AssetWriterError, AsyncSeekForward,
3+
PathStream, Reader, Writer,
44
};
55
use async_fs::{read_dir, File};
6+
use futures_io::AsyncSeek;
67
use futures_lite::StreamExt;
78

9+
use core::{pin::Pin, task, task::Poll};
810
use std::path::Path;
911

1012
use super::{FileAssetReader, FileAssetWriter};
1113

14+
impl AsyncSeekForward for File {
15+
fn poll_seek_forward(
16+
mut self: Pin<&mut Self>,
17+
cx: &mut task::Context<'_>,
18+
offset: u64,
19+
) -> Poll<futures_io::Result<u64>> {
20+
let offset: Result<i64, _> = offset.try_into();
21+
22+
if let Ok(offset) = offset {
23+
Pin::new(&mut self).poll_seek(cx, futures_io::SeekFrom::Current(offset))
24+
} else {
25+
Poll::Ready(Err(std::io::Error::new(
26+
std::io::ErrorKind::InvalidInput,
27+
"seek position is out of range",
28+
)))
29+
}
30+
}
31+
}
32+
1233
impl Reader for File {}
1334

1435
impl AssetReader for FileAssetReader {

crates/bevy_asset/src/io/file/sync_file_asset.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use futures_io::{AsyncRead, AsyncSeek, AsyncWrite};
1+
use futures_io::{AsyncRead, AsyncWrite};
22
use futures_lite::Stream;
33

44
use crate::io::{
5-
get_meta_path, AssetReader, AssetReaderError, AssetWriter, AssetWriterError, PathStream,
6-
Reader, Writer,
5+
get_meta_path, AssetReader, AssetReaderError, AssetWriter, AssetWriterError, AsyncSeekForward,
6+
PathStream, Reader, Writer,
77
};
88

99
use core::{pin::Pin, task::Poll};
@@ -29,14 +29,16 @@ impl AsyncRead for FileReader {
2929
}
3030
}
3131

32-
impl AsyncSeek for FileReader {
33-
fn poll_seek(
32+
impl AsyncSeekForward for FileReader {
33+
fn poll_seek_forward(
3434
self: Pin<&mut Self>,
3535
_cx: &mut core::task::Context<'_>,
36-
pos: std::io::SeekFrom,
36+
offset: u64,
3737
) -> Poll<std::io::Result<u64>> {
3838
let this = self.get_mut();
39-
let seek = this.0.seek(pos);
39+
let current = this.0.stream_position()?;
40+
let seek = this.0.seek(std::io::SeekFrom::Start(current + offset));
41+
4042
Poll::Ready(seek)
4143
}
4244
}

crates/bevy_asset/src/io/memory.rs

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@ use crate::io::{AssetReader, AssetReaderError, PathStream, Reader};
22
use alloc::sync::Arc;
33
use bevy_utils::HashMap;
44
use core::{pin::Pin, task::Poll};
5-
use futures_io::{AsyncRead, AsyncSeek};
5+
use futures_io::AsyncRead;
66
use futures_lite::{ready, Stream};
77
use parking_lot::RwLock;
8-
use std::{
9-
io::SeekFrom,
10-
path::{Path, PathBuf},
11-
};
8+
use std::path::{Path, PathBuf};
9+
10+
use super::AsyncSeekForward;
1211

1312
#[derive(Default, Debug)]
1413
struct DirInternal {
@@ -247,37 +246,20 @@ impl AsyncRead for DataReader {
247246
}
248247
}
249248

250-
impl AsyncSeek for DataReader {
251-
fn poll_seek(
249+
impl AsyncSeekForward for DataReader {
250+
fn poll_seek_forward(
252251
mut self: Pin<&mut Self>,
253252
_cx: &mut core::task::Context<'_>,
254-
pos: SeekFrom,
253+
offset: u64,
255254
) -> Poll<std::io::Result<u64>> {
256-
let result = match pos {
257-
SeekFrom::Start(offset) => offset.try_into(),
258-
SeekFrom::End(offset) => self
259-
.data
260-
.value()
261-
.len()
262-
.try_into()
263-
.map(|len: i64| len - offset),
264-
SeekFrom::Current(offset) => self
265-
.bytes_read
266-
.try_into()
267-
.map(|bytes_read: i64| bytes_read + offset),
268-
};
255+
let result = self
256+
.bytes_read
257+
.try_into()
258+
.map(|bytes_read: u64| bytes_read + offset);
269259

270260
if let Ok(new_pos) = result {
271-
if new_pos < 0 {
272-
Poll::Ready(Err(std::io::Error::new(
273-
std::io::ErrorKind::InvalidInput,
274-
"seek position is out of range",
275-
)))
276-
} else {
277-
self.bytes_read = new_pos as _;
278-
279-
Poll::Ready(Ok(new_pos as _))
280-
}
261+
self.bytes_read = new_pos as _;
262+
Poll::Ready(Ok(new_pos as _))
281263
} else {
282264
Poll::Ready(Err(std::io::Error::new(
283265
std::io::ErrorKind::InvalidInput,

crates/bevy_asset/src/io/mod.rs

Lines changed: 60 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,9 @@ use core::{
2828
pin::Pin,
2929
task::{Context, Poll},
3030
};
31-
use futures_io::{AsyncRead, AsyncSeek, AsyncWrite};
31+
use futures_io::{AsyncRead, AsyncWrite};
3232
use futures_lite::{ready, Stream};
33-
use std::{
34-
io::SeekFrom,
35-
path::{Path, PathBuf},
36-
};
33+
use std::path::{Path, PathBuf};
3734
use thiserror::Error;
3835

3936
/// Errors that occur while loading assets.
@@ -83,13 +80,51 @@ pub const STACK_FUTURE_SIZE: usize = 10 * size_of::<&()>();
8380

8481
pub use stackfuture::StackFuture;
8582

83+
/// Asynchronously advances the cursor position by a specified number of bytes.
84+
///
85+
/// This trait is a simplified version of the [`futures_io::AsyncSeek`] trait, providing
86+
/// support exclusively for the [`futures_io::SeekFrom::Current`] variant. It allows for relative
87+
/// seeking from the current cursor position.
88+
pub trait AsyncSeekForward {
89+
/// Attempts to asynchronously seek forward by a specified number of bytes from the current cursor position.
90+
///
91+
/// Seeking beyond the end of the stream is allowed and the behavior for this case is defined by the implementation.
92+
/// The new position, relative to the beginning of the stream, should be returned upon successful completion
93+
/// of the seek operation.
94+
///
95+
/// If the seek operation completes successfully,
96+
/// the new position relative to the beginning of the stream should be returned.
97+
///
98+
/// # Implementation
99+
///
100+
/// Implementations of this trait should handle [`Poll::Pending`] correctly, converting
101+
/// [`std::io::ErrorKind::WouldBlock`] errors into [`Poll::Pending`] to indicate that the operation is not
102+
/// yet complete and should be retried, and either internally retry or convert
103+
/// [`std::io::ErrorKind::Interrupted`] into another error kind.
104+
fn poll_seek_forward(
105+
self: Pin<&mut Self>,
106+
cx: &mut Context<'_>,
107+
offset: u64,
108+
) -> Poll<futures_io::Result<u64>>;
109+
}
110+
111+
impl<T: ?Sized + AsyncSeekForward + Unpin> AsyncSeekForward for Box<T> {
112+
fn poll_seek_forward(
113+
mut self: Pin<&mut Self>,
114+
cx: &mut Context<'_>,
115+
offset: u64,
116+
) -> Poll<futures_io::Result<u64>> {
117+
Pin::new(&mut **self).poll_seek_forward(cx, offset)
118+
}
119+
}
120+
86121
/// A type returned from [`AssetReader::read`], which is used to read the contents of a file
87122
/// (or virtual file) corresponding to an asset.
88123
///
89-
/// This is essentially a trait alias for types implementing [`AsyncRead`] and [`AsyncSeek`].
124+
/// This is essentially a trait alias for types implementing [`AsyncRead`] and [`AsyncSeekForward`].
90125
/// The only reason a blanket implementation is not provided for applicable types is to allow
91126
/// implementors to override the provided implementation of [`Reader::read_to_end`].
92-
pub trait Reader: AsyncRead + AsyncSeek + Unpin + Send + Sync {
127+
pub trait Reader: AsyncRead + AsyncSeekForward + Unpin + Send + Sync {
93128
/// Reads the entire contents of this reader and appends them to a vec.
94129
///
95130
/// # Note for implementors
@@ -559,32 +594,20 @@ impl AsyncRead for VecReader {
559594
}
560595
}
561596

562-
impl AsyncSeek for VecReader {
563-
fn poll_seek(
597+
impl AsyncSeekForward for VecReader {
598+
fn poll_seek_forward(
564599
mut self: Pin<&mut Self>,
565600
_cx: &mut Context<'_>,
566-
pos: SeekFrom,
601+
offset: u64,
567602
) -> Poll<std::io::Result<u64>> {
568-
let result = match pos {
569-
SeekFrom::Start(offset) => offset.try_into(),
570-
SeekFrom::End(offset) => self.bytes.len().try_into().map(|len: i64| len - offset),
571-
SeekFrom::Current(offset) => self
572-
.bytes_read
573-
.try_into()
574-
.map(|bytes_read: i64| bytes_read + offset),
575-
};
603+
let result = self
604+
.bytes_read
605+
.try_into()
606+
.map(|bytes_read: u64| bytes_read + offset);
576607

577608
if let Ok(new_pos) = result {
578-
if new_pos < 0 {
579-
Poll::Ready(Err(std::io::Error::new(
580-
std::io::ErrorKind::InvalidInput,
581-
"seek position is out of range",
582-
)))
583-
} else {
584-
self.bytes_read = new_pos as _;
585-
586-
Poll::Ready(Ok(new_pos as _))
587-
}
609+
self.bytes_read = new_pos as _;
610+
Poll::Ready(Ok(new_pos as _))
588611
} else {
589612
Poll::Ready(Err(std::io::Error::new(
590613
std::io::ErrorKind::InvalidInput,
@@ -644,32 +667,21 @@ impl<'a> AsyncRead for SliceReader<'a> {
644667
}
645668
}
646669

647-
impl<'a> AsyncSeek for SliceReader<'a> {
648-
fn poll_seek(
670+
impl<'a> AsyncSeekForward for SliceReader<'a> {
671+
fn poll_seek_forward(
649672
mut self: Pin<&mut Self>,
650673
_cx: &mut Context<'_>,
651-
pos: SeekFrom,
674+
offset: u64,
652675
) -> Poll<std::io::Result<u64>> {
653-
let result = match pos {
654-
SeekFrom::Start(offset) => offset.try_into(),
655-
SeekFrom::End(offset) => self.bytes.len().try_into().map(|len: i64| len - offset),
656-
SeekFrom::Current(offset) => self
657-
.bytes_read
658-
.try_into()
659-
.map(|bytes_read: i64| bytes_read + offset),
660-
};
676+
let result = self
677+
.bytes_read
678+
.try_into()
679+
.map(|bytes_read: u64| bytes_read + offset);
661680

662681
if let Ok(new_pos) = result {
663-
if new_pos < 0 {
664-
Poll::Ready(Err(std::io::Error::new(
665-
std::io::ErrorKind::InvalidInput,
666-
"seek position is out of range",
667-
)))
668-
} else {
669-
self.bytes_read = new_pos as _;
682+
self.bytes_read = new_pos as _;
670683

671-
Poll::Ready(Ok(new_pos as _))
672-
}
684+
Poll::Ready(Ok(new_pos as _))
673685
} else {
674686
Poll::Ready(Err(std::io::Error::new(
675687
std::io::ErrorKind::InvalidInput,

crates/bevy_asset/src/io/processor_gated.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ use alloc::sync::Arc;
77
use async_lock::RwLockReadGuardArc;
88
use bevy_utils::tracing::trace;
99
use core::{pin::Pin, task::Poll};
10-
use futures_io::{AsyncRead, AsyncSeek};
11-
use std::{io::SeekFrom, path::Path};
10+
use futures_io::AsyncRead;
11+
use std::path::Path;
1212

13-
use super::ErasedAssetReader;
13+
use super::{AsyncSeekForward, ErasedAssetReader};
1414

1515
/// An [`AssetReader`] that will prevent asset (and asset metadata) read futures from returning for a
1616
/// given path until that path has been processed by [`AssetProcessor`].
1717
///
18-
/// [`AssetProcessor`]: crate::processor::AssetProcessor
18+
/// [`AssetProcessor`]: crate::processor::AssetProcessor
1919
pub struct ProcessorGatedReader {
2020
reader: Box<dyn ErasedAssetReader>,
2121
source: AssetSourceId<'static>,
@@ -142,13 +142,13 @@ impl AsyncRead for TransactionLockedReader<'_> {
142142
}
143143
}
144144

145-
impl AsyncSeek for TransactionLockedReader<'_> {
146-
fn poll_seek(
145+
impl AsyncSeekForward for TransactionLockedReader<'_> {
146+
fn poll_seek_forward(
147147
mut self: Pin<&mut Self>,
148148
cx: &mut core::task::Context<'_>,
149-
pos: SeekFrom,
149+
offset: u64,
150150
) -> Poll<std::io::Result<u64>> {
151-
Pin::new(&mut self.reader).poll_seek(cx, pos)
151+
Pin::new(&mut self.reader).poll_seek_forward(cx, offset)
152152
}
153153
}
154154

0 commit comments

Comments
 (0)