Skip to content

Commit 2ea920e

Browse files
committed
update assets Reader to use AsyncSeekForward rather than AsyncSeek
1 parent fcddb54 commit 2ea920e

File tree

5 files changed

+115
-92
lines changed

5 files changed

+115
-92
lines changed

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

Lines changed: 24 additions & 3 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

8-
use std::path::Path;
9+
use std::task;
10+
use std::{path::Path, pin::Pin, task::Poll};
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 std::{
@@ -30,14 +30,16 @@ impl AsyncRead for FileReader {
3030
}
3131
}
3232

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

crates/bevy_asset/src/io/memory.rs

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
use crate::io::{AssetReader, AssetReaderError, PathStream, Reader};
22
use bevy_utils::HashMap;
3-
use futures_io::{AsyncRead, AsyncSeek};
3+
use futures_io::AsyncRead;
44
use futures_lite::{ready, Stream};
55
use parking_lot::RwLock;
66
use std::{
7-
io::SeekFrom,
87
path::{Path, PathBuf},
98
pin::Pin,
109
sync::Arc,
1110
task::Poll,
1211
};
1312

13+
use super::AsyncSeekForward;
14+
1415
#[derive(Default, Debug)]
1516
struct DirInternal {
1617
assets: HashMap<Box<str>, Data>,
@@ -248,37 +249,20 @@ impl AsyncRead for DataReader {
248249
}
249250
}
250251

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

271263
if let Ok(new_pos) = result {
272-
if new_pos < 0 {
273-
Poll::Ready(Err(std::io::Error::new(
274-
std::io::ErrorKind::InvalidInput,
275-
"seek position is out of range",
276-
)))
277-
} else {
278-
self.bytes_read = new_pos as _;
279-
280-
Poll::Ready(Ok(new_pos as _))
281-
}
264+
self.bytes_read = new_pos as _;
265+
Poll::Ready(Ok(new_pos as _))
282266
} else {
283267
Poll::Ready(Err(std::io::Error::new(
284268
std::io::ErrorKind::InvalidInput,

crates/bevy_asset/src/io/mod.rs

Lines changed: 62 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@ pub use futures_lite::AsyncWriteExt;
2222
pub use source::*;
2323

2424
use bevy_utils::{BoxedFuture, ConditionalSendFuture};
25-
use futures_io::{AsyncRead, AsyncSeek, AsyncWrite};
25+
use futures_io::{AsyncRead, AsyncWrite};
2626
use futures_lite::{ready, Stream};
27+
use std::task::Context;
2728
use std::{
28-
io::SeekFrom,
29+
mem::size_of,
2930
path::{Path, PathBuf},
3031
pin::Pin,
3132
sync::Arc,
32-
task::{Context, Poll},
33+
task::Poll,
3334
};
3435
use thiserror::Error;
3536

@@ -80,13 +81,51 @@ pub const STACK_FUTURE_SIZE: usize = 10 * size_of::<&()>();
8081

8182
pub use stackfuture::StackFuture;
8283

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

559-
impl AsyncSeek for VecReader {
560-
fn poll_seek(
598+
impl AsyncSeekForward for VecReader {
599+
fn poll_seek_forward(
561600
mut self: Pin<&mut Self>,
562601
_cx: &mut Context<'_>,
563-
pos: SeekFrom,
602+
offset: u64,
564603
) -> Poll<std::io::Result<u64>> {
565-
let result = match pos {
566-
SeekFrom::Start(offset) => offset.try_into(),
567-
SeekFrom::End(offset) => self.bytes.len().try_into().map(|len: i64| len - offset),
568-
SeekFrom::Current(offset) => self
569-
.bytes_read
570-
.try_into()
571-
.map(|bytes_read: i64| bytes_read + offset),
572-
};
604+
let result = self
605+
.bytes_read
606+
.try_into()
607+
.map(|bytes_read: u64| bytes_read + offset);
573608

574609
if let Ok(new_pos) = result {
575-
if new_pos < 0 {
576-
Poll::Ready(Err(std::io::Error::new(
577-
std::io::ErrorKind::InvalidInput,
578-
"seek position is out of range",
579-
)))
580-
} else {
581-
self.bytes_read = new_pos as _;
582-
583-
Poll::Ready(Ok(new_pos as _))
584-
}
610+
self.bytes_read = new_pos as _;
611+
Poll::Ready(Ok(new_pos as _))
585612
} else {
586613
Poll::Ready(Err(std::io::Error::new(
587614
std::io::ErrorKind::InvalidInput,
@@ -641,32 +668,21 @@ impl<'a> AsyncRead for SliceReader<'a> {
641668
}
642669
}
643670

644-
impl<'a> AsyncSeek for SliceReader<'a> {
645-
fn poll_seek(
671+
impl<'a> AsyncSeekForward for SliceReader<'a> {
672+
fn poll_seek_forward(
646673
mut self: Pin<&mut Self>,
647674
_cx: &mut Context<'_>,
648-
pos: SeekFrom,
675+
offset: u64,
649676
) -> Poll<std::io::Result<u64>> {
650-
let result = match pos {
651-
SeekFrom::Start(offset) => offset.try_into(),
652-
SeekFrom::End(offset) => self.bytes.len().try_into().map(|len: i64| len - offset),
653-
SeekFrom::Current(offset) => self
654-
.bytes_read
655-
.try_into()
656-
.map(|bytes_read: i64| bytes_read + offset),
657-
};
677+
let result = self
678+
.bytes_read
679+
.try_into()
680+
.map(|bytes_read: u64| bytes_read + offset);
658681

659682
if let Ok(new_pos) = result {
660-
if new_pos < 0 {
661-
Poll::Ready(Err(std::io::Error::new(
662-
std::io::ErrorKind::InvalidInput,
663-
"seek position is out of range",
664-
)))
665-
} else {
666-
self.bytes_read = new_pos as _;
683+
self.bytes_read = new_pos as _;
667684

668-
Poll::Ready(Ok(new_pos as _))
669-
}
685+
Poll::Ready(Ok(new_pos as _))
670686
} else {
671687
Poll::Ready(Err(std::io::Error::new(
672688
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
@@ -5,15 +5,15 @@ use crate::{
55
};
66
use async_lock::RwLockReadGuardArc;
77
use bevy_utils::tracing::trace;
8-
use futures_io::{AsyncRead, AsyncSeek};
9-
use std::{io::SeekFrom, path::Path, pin::Pin, sync::Arc, task::Poll};
8+
use futures_io::AsyncRead;
9+
use std::{path::Path, pin::Pin, sync::Arc, task::Poll};
1010

11-
use super::ErasedAssetReader;
11+
use super::{AsyncSeekForward, ErasedAssetReader};
1212

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

143-
impl AsyncSeek for TransactionLockedReader<'_> {
144-
fn poll_seek(
143+
impl AsyncSeekForward for TransactionLockedReader<'_> {
144+
fn poll_seek_forward(
145145
mut self: Pin<&mut Self>,
146146
cx: &mut std::task::Context<'_>,
147-
pos: SeekFrom,
147+
offset: u64,
148148
) -> Poll<std::io::Result<u64>> {
149-
Pin::new(&mut self.reader).poll_seek(cx, pos)
149+
Pin::new(&mut self.reader).poll_seek_forward(cx, offset)
150150
}
151151
}
152152

0 commit comments

Comments
 (0)