Skip to content

Commit e4960f5

Browse files
committed
update assets Reader to use AsyncSeekForward rather than AsyncSeek
1 parent 1caa64d commit e4960f5

File tree

5 files changed

+113
-92
lines changed

5 files changed

+113
-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;
6-
use std::io::SeekFrom;
76
use std::{
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>,
@@ -237,37 +238,20 @@ impl AsyncRead for DataReader {
237238
}
238239
}
239240

240-
impl AsyncSeek for DataReader {
241-
fn poll_seek(
241+
impl AsyncSeekForward for DataReader {
242+
fn poll_seek_forward(
242243
mut self: Pin<&mut Self>,
243244
_cx: &mut std::task::Context<'_>,
244-
pos: SeekFrom,
245+
offset: u64,
245246
) -> Poll<std::io::Result<u64>> {
246-
let result = match pos {
247-
SeekFrom::Start(offset) => offset.try_into(),
248-
SeekFrom::End(offset) => self
249-
.data
250-
.value()
251-
.len()
252-
.try_into()
253-
.map(|len: i64| len - offset),
254-
SeekFrom::Current(offset) => self
255-
.bytes_read
256-
.try_into()
257-
.map(|bytes_read: i64| bytes_read + offset),
258-
};
247+
let result = self
248+
.bytes_read
249+
.try_into()
250+
.map(|bytes_read: u64| bytes_read + offset);
259251

260252
if let Ok(new_pos) = result {
261-
if new_pos < 0 {
262-
Poll::Ready(Err(std::io::Error::new(
263-
std::io::ErrorKind::InvalidInput,
264-
"seek position is out of range",
265-
)))
266-
} else {
267-
self.bytes_read = new_pos as _;
268-
269-
Poll::Ready(Ok(new_pos as _))
270-
}
253+
self.bytes_read = new_pos as _;
254+
Poll::Ready(Ok(new_pos as _))
271255
} else {
272256
Poll::Ready(Err(std::io::Error::new(
273257
std::io::ErrorKind::InvalidInput,

crates/bevy_asset/src/io/mod.rs

Lines changed: 61 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +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,
2929
mem::size_of,
3030
path::{Path, PathBuf},
3131
pin::Pin,
3232
sync::Arc,
33-
task::{Context, Poll},
33+
task::Poll,
3434
};
3535
use thiserror::Error;
3636

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

8282
pub use stackfuture::StackFuture;
8383

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+
84122
/// A type returned from [`AssetReader::read`], which is used to read the contents of a file
85123
/// (or virtual file) corresponding to an asset.
86124
///
87-
/// 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`].
88126
/// The only reason a blanket implementation is not provided for applicable types is to allow
89127
/// implementors to override the provided implementation of [`Reader::read_to_end`].
90-
pub trait Reader: AsyncRead + AsyncSeek + Unpin + Send + Sync {
128+
pub trait Reader: AsyncRead + AsyncSeekForward + Unpin + Send + Sync {
91129
/// Reads the entire contents of this reader and appends them to a vec.
92130
///
93131
/// # Note for implementors
@@ -533,32 +571,20 @@ impl AsyncRead for VecReader {
533571
}
534572
}
535573

536-
impl AsyncSeek for VecReader {
537-
fn poll_seek(
574+
impl AsyncSeekForward for VecReader {
575+
fn poll_seek_forward(
538576
mut self: Pin<&mut Self>,
539577
_cx: &mut Context<'_>,
540-
pos: SeekFrom,
578+
offset: u64,
541579
) -> Poll<std::io::Result<u64>> {
542-
let result = match pos {
543-
SeekFrom::Start(offset) => offset.try_into(),
544-
SeekFrom::End(offset) => self.bytes.len().try_into().map(|len: i64| len - offset),
545-
SeekFrom::Current(offset) => self
546-
.bytes_read
547-
.try_into()
548-
.map(|bytes_read: i64| bytes_read + offset),
549-
};
580+
let result = self
581+
.bytes_read
582+
.try_into()
583+
.map(|bytes_read: u64| bytes_read + offset);
550584

551585
if let Ok(new_pos) = result {
552-
if new_pos < 0 {
553-
Poll::Ready(Err(std::io::Error::new(
554-
std::io::ErrorKind::InvalidInput,
555-
"seek position is out of range",
556-
)))
557-
} else {
558-
self.bytes_read = new_pos as _;
559-
560-
Poll::Ready(Ok(new_pos as _))
561-
}
586+
self.bytes_read = new_pos as _;
587+
Poll::Ready(Ok(new_pos as _))
562588
} else {
563589
Poll::Ready(Err(std::io::Error::new(
564590
std::io::ErrorKind::InvalidInput,
@@ -618,32 +644,21 @@ impl<'a> AsyncRead for SliceReader<'a> {
618644
}
619645
}
620646

621-
impl<'a> AsyncSeek for SliceReader<'a> {
622-
fn poll_seek(
647+
impl<'a> AsyncSeekForward for SliceReader<'a> {
648+
fn poll_seek_forward(
623649
mut self: Pin<&mut Self>,
624650
_cx: &mut Context<'_>,
625-
pos: SeekFrom,
651+
offset: u64,
626652
) -> Poll<std::io::Result<u64>> {
627-
let result = match pos {
628-
SeekFrom::Start(offset) => offset.try_into(),
629-
SeekFrom::End(offset) => self.bytes.len().try_into().map(|len: i64| len - offset),
630-
SeekFrom::Current(offset) => self
631-
.bytes_read
632-
.try_into()
633-
.map(|bytes_read: i64| bytes_read + offset),
634-
};
653+
let result = self
654+
.bytes_read
655+
.try_into()
656+
.map(|bytes_read: u64| bytes_read + offset);
635657

636658
if let Ok(new_pos) = result {
637-
if new_pos < 0 {
638-
Poll::Ready(Err(std::io::Error::new(
639-
std::io::ErrorKind::InvalidInput,
640-
"seek position is out of range",
641-
)))
642-
} else {
643-
self.bytes_read = new_pos as _;
659+
self.bytes_read = new_pos as _;
644660

645-
Poll::Ready(Ok(new_pos as _))
646-
}
661+
Poll::Ready(Ok(new_pos as _))
647662
} else {
648663
Poll::Ready(Err(std::io::Error::new(
649664
std::io::ErrorKind::InvalidInput,

crates/bevy_asset/src/io/processor_gated.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,16 @@ 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;
8+
use futures_io::AsyncRead;
109
use std::task::Poll;
1110
use std::{path::Path, pin::Pin, sync::Arc};
1211

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

1514
/// An [`AssetReader`] that will prevent asset (and asset metadata) read futures from returning for a
1615
/// given path until that path has been processed by [`AssetProcessor`].
1716
///
18-
/// [`AssetProcessor`]: crate::processor::AssetProcessor
17+
/// [`AssetProcessor`]: crate::processor::AssetProcessor
1918
pub struct ProcessorGatedReader {
2019
reader: Box<dyn ErasedAssetReader>,
2120
source: AssetSourceId<'static>,
@@ -142,13 +141,13 @@ impl AsyncRead for TransactionLockedReader<'_> {
142141
}
143142
}
144143

145-
impl AsyncSeek for TransactionLockedReader<'_> {
146-
fn poll_seek(
144+
impl AsyncSeekForward for TransactionLockedReader<'_> {
145+
fn poll_seek_forward(
147146
mut self: Pin<&mut Self>,
148147
cx: &mut std::task::Context<'_>,
149-
pos: SeekFrom,
148+
offset: u64,
150149
) -> Poll<std::io::Result<u64>> {
151-
Pin::new(&mut self.reader).poll_seek(cx, pos)
150+
Pin::new(&mut self.reader).poll_seek_forward(cx, offset)
152151
}
153152
}
154153

0 commit comments

Comments
 (0)