Skip to content

Commit 3e4b0ba

Browse files
committed
Split traits to get image bytes and metadata bytes
1 parent 960e4e1 commit 3e4b0ba

File tree

2 files changed

+89
-49
lines changed

2 files changed

+89
-49
lines changed

src/ifd.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -779,7 +779,7 @@ impl ImageFileDirectory {
779779
let range = self
780780
.get_tile_byte_range(x, y)
781781
.ok_or(AsyncTiffError::General("Not a tiled TIFF".to_string()))?;
782-
let compressed_bytes = reader.get_bytes(range).await?;
782+
let compressed_bytes = reader.get_image_bytes(range).await?;
783783
Ok(Tile {
784784
x,
785785
y,
@@ -810,7 +810,7 @@ impl ImageFileDirectory {
810810
.collect::<AsyncTiffResult<Vec<_>>>()?;
811811

812812
// 2: Fetch using `get_ranges
813-
let buffers = reader.get_byte_ranges(byte_ranges).await?;
813+
let buffers = reader.get_image_byte_ranges(byte_ranges).await?;
814814

815815
// 3: Create tile objects
816816
let mut tiles = vec![];

src/reader.rs

Lines changed: 87 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,23 @@ use crate::error::{AsyncTiffError, AsyncTiffResult};
3030
///
3131
/// [`tokio::fs::File`]: https://docs.rs/tokio/latest/tokio/fs/struct.File.html
3232
pub trait AsyncFileReader: Debug + Send + Sync {
33-
/// Retrieve the bytes in `range`
34-
fn get_bytes(&self, range: Range<u64>) -> BoxFuture<'_, AsyncTiffResult<Bytes>>;
33+
/// Retrieve the bytes in `range` as part of a request for header metadata.
34+
fn get_metadata_bytes(&self, range: Range<u64>) -> BoxFuture<'_, AsyncTiffResult<Bytes>>;
3535

36-
/// Retrieve multiple byte ranges. The default implementation will call `get_bytes`
37-
/// sequentially
38-
fn get_byte_ranges(
36+
/// Retrieve the bytes in `range` as part of a request for image data, not header metadata.
37+
fn get_image_bytes(&self, range: Range<u64>) -> BoxFuture<'_, AsyncTiffResult<Bytes>>;
38+
39+
/// Retrieve multiple byte ranges as part of a request for image data, not header metadata. The
40+
/// default implementation will call `get_image_bytes` sequentially
41+
fn get_image_byte_ranges(
3942
&self,
4043
ranges: Vec<Range<u64>>,
4144
) -> BoxFuture<'_, AsyncTiffResult<Vec<Bytes>>> {
4245
async move {
4346
let mut result = Vec::with_capacity(ranges.len());
4447

4548
for range in ranges.into_iter() {
46-
let data = self.get_bytes(range).await?;
49+
let data = self.get_image_bytes(range).await?;
4750
result.push(data);
4851
}
4952

@@ -55,15 +58,19 @@ pub trait AsyncFileReader: Debug + Send + Sync {
5558

5659
/// This allows Box<dyn AsyncFileReader + '_> to be used as an AsyncFileReader,
5760
impl AsyncFileReader for Box<dyn AsyncFileReader + '_> {
58-
fn get_bytes(&self, range: Range<u64>) -> BoxFuture<'_, AsyncTiffResult<Bytes>> {
59-
self.as_ref().get_bytes(range)
61+
fn get_metadata_bytes(&self, range: Range<u64>) -> BoxFuture<'_, AsyncTiffResult<Bytes>> {
62+
self.as_ref().get_metadata_bytes(range)
63+
}
64+
65+
fn get_image_bytes(&self, range: Range<u64>) -> BoxFuture<'_, AsyncTiffResult<Bytes>> {
66+
self.as_ref().get_image_bytes(range)
6067
}
6168

62-
fn get_byte_ranges(
69+
fn get_image_byte_ranges(
6370
&self,
6471
ranges: Vec<Range<u64>>,
6572
) -> BoxFuture<'_, AsyncTiffResult<Vec<Bytes>>> {
66-
self.as_ref().get_byte_ranges(ranges)
73+
self.as_ref().get_image_byte_ranges(ranges)
6774
}
6875
}
6976

@@ -89,31 +96,36 @@ impl<T: tokio::io::AsyncRead + tokio::io::AsyncSeek + Unpin + Send + Debug> Toki
8996
pub fn new(inner: T) -> Self {
9097
Self(tokio::sync::Mutex::new(inner))
9198
}
92-
}
9399

94-
#[cfg(feature = "tokio")]
95-
impl<T: tokio::io::AsyncRead + tokio::io::AsyncSeek + Unpin + Send + Debug> AsyncFileReader
96-
for TokioReader<T>
97-
{
98-
fn get_bytes(&self, range: Range<u64>) -> BoxFuture<'_, AsyncTiffResult<Bytes>> {
100+
async fn make_range_request(&self, range: Range<u64>) -> AsyncTiffResult<Bytes> {
99101
use std::io::SeekFrom;
100102
use tokio::io::{AsyncReadExt, AsyncSeekExt};
101103

102-
async move {
103-
let mut file = self.0.lock().await;
104-
105-
file.seek(SeekFrom::Start(range.start)).await?;
104+
let mut file = self.0.lock().await;
106105

107-
let to_read = range.end - range.start;
108-
let mut buffer = Vec::with_capacity(to_read as usize);
109-
let read = file.read(&mut buffer).await? as u64;
110-
if read != to_read {
111-
return Err(AsyncTiffError::EndOfFile(to_read, read));
112-
}
106+
file.seek(SeekFrom::Start(range.start)).await?;
113107

114-
Ok(buffer.into())
108+
let to_read = range.end - range.start;
109+
let mut buffer = Vec::with_capacity(to_read as usize);
110+
let read = file.read(&mut buffer).await? as u64;
111+
if read != to_read {
112+
return Err(AsyncTiffError::EndOfFile(to_read, read));
115113
}
116-
.boxed()
114+
115+
Ok(buffer.into())
116+
}
117+
}
118+
119+
#[cfg(feature = "tokio")]
120+
impl<T: tokio::io::AsyncRead + tokio::io::AsyncSeek + Unpin + Send + Debug> AsyncFileReader
121+
for TokioReader<T>
122+
{
123+
fn get_metadata_bytes(&self, range: Range<u64>) -> BoxFuture<'_, AsyncTiffResult<Bytes>> {
124+
self.make_range_request(range).boxed()
125+
}
126+
127+
fn get_image_bytes(&self, range: Range<u64>) -> BoxFuture<'_, AsyncTiffResult<Bytes>> {
128+
self.make_range_request(range).boxed()
117129
}
118130
}
119131

@@ -133,19 +145,30 @@ impl ObjectReader {
133145
pub fn new(store: Arc<dyn object_store::ObjectStore>, path: object_store::path::Path) -> Self {
134146
Self { store, path }
135147
}
136-
}
137148

138-
#[cfg(feature = "object_store")]
139-
impl AsyncFileReader for ObjectReader {
140-
fn get_bytes(&self, range: Range<u64>) -> BoxFuture<'_, AsyncTiffResult<Bytes>> {
149+
async fn make_range_request(&self, range: Range<u64>) -> AsyncTiffResult<Bytes> {
141150
let range = range.start as _..range.end as _;
142151
self.store
143152
.get_range(&self.path, range)
144153
.map_err(|e| e.into())
145-
.boxed()
154+
.await
155+
}
156+
}
157+
158+
#[cfg(feature = "object_store")]
159+
impl AsyncFileReader for ObjectReader {
160+
fn get_metadata_bytes(&self, range: Range<u64>) -> BoxFuture<'_, AsyncTiffResult<Bytes>> {
161+
self.make_range_request(range).boxed()
146162
}
147163

148-
fn get_byte_ranges(&self, ranges: Vec<Range<u64>>) -> BoxFuture<'_, AsyncTiffResult<Vec<Bytes>>>
164+
fn get_image_bytes(&self, range: Range<u64>) -> BoxFuture<'_, AsyncTiffResult<Bytes>> {
165+
self.make_range_request(range).boxed()
166+
}
167+
168+
fn get_image_byte_ranges(
169+
&self,
170+
ranges: Vec<Range<u64>>,
171+
) -> BoxFuture<'_, AsyncTiffResult<Vec<Bytes>>>
149172
where
150173
Self: Send,
151174
{
@@ -177,11 +200,8 @@ impl ReqwestReader {
177200
pub fn new(client: reqwest::Client, url: reqwest::Url) -> Self {
178201
Self { client, url }
179202
}
180-
}
181203

182-
#[cfg(feature = "reqwest")]
183-
impl AsyncFileReader for ReqwestReader {
184-
fn get_bytes(&self, range: Range<u64>) -> BoxFuture<'_, AsyncTiffResult<Bytes>> {
204+
fn make_range_request(&self, range: Range<u64>) -> BoxFuture<'_, AsyncTiffResult<Bytes>> {
185205
let url = self.url.clone();
186206
let client = self.client.clone();
187207
// HTTP range is inclusive, so we need to subtract 1 from the end
@@ -195,6 +215,17 @@ impl AsyncFileReader for ReqwestReader {
195215
}
196216
}
197217

218+
#[cfg(feature = "reqwest")]
219+
impl AsyncFileReader for ReqwestReader {
220+
fn get_metadata_bytes(&self, range: Range<u64>) -> BoxFuture<'_, AsyncTiffResult<Bytes>> {
221+
self.make_range_request(range)
222+
}
223+
224+
fn get_image_bytes(&self, range: Range<u64>) -> BoxFuture<'_, AsyncTiffResult<Bytes>> {
225+
self.make_range_request(range)
226+
}
227+
}
228+
198229
/// An AsyncFileReader that caches the first `prefetch` bytes of a file.
199230
#[derive(Debug)]
200231
pub struct PrefetchReader {
@@ -205,34 +236,43 @@ pub struct PrefetchReader {
205236
impl PrefetchReader {
206237
/// Construct a new PrefetchReader, catching the first `prefetch` bytes of the file.
207238
pub async fn new(reader: Arc<dyn AsyncFileReader>, prefetch: u64) -> AsyncTiffResult<Self> {
208-
let buffer = reader.get_bytes(0..prefetch).await?;
239+
let buffer = reader.get_metadata_bytes(0..prefetch).await?;
209240
Ok(Self { reader, buffer })
210241
}
211242
}
212243

213244
impl AsyncFileReader for PrefetchReader {
214-
fn get_bytes(&self, range: Range<u64>) -> BoxFuture<'_, AsyncTiffResult<Bytes>> {
245+
fn get_metadata_bytes(&self, range: Range<u64>) -> BoxFuture<'_, AsyncTiffResult<Bytes>> {
215246
if range.start < self.buffer.len() as _ {
216247
if range.end < self.buffer.len() as _ {
217248
let usize_range = range.start as usize..range.end as usize;
218249
let result = self.buffer.slice(usize_range);
219250
async { Ok(result) }.boxed()
220251
} else {
221252
// TODO: reuse partial internal buffer
222-
self.reader.get_bytes(range)
253+
self.reader.get_metadata_bytes(range)
223254
}
224255
} else {
225-
self.reader.get_bytes(range)
256+
self.reader.get_metadata_bytes(range)
226257
}
227258
}
228259

229-
fn get_byte_ranges(&self, ranges: Vec<Range<u64>>) -> BoxFuture<'_, AsyncTiffResult<Vec<Bytes>>>
260+
fn get_image_bytes(&self, range: Range<u64>) -> BoxFuture<'_, AsyncTiffResult<Bytes>> {
261+
// In practice, get_image_bytes is only used for fetching tiles, which are unlikely
262+
// to overlap a metadata prefetch.
263+
self.reader.get_image_bytes(range)
264+
}
265+
266+
fn get_image_byte_ranges(
267+
&self,
268+
ranges: Vec<Range<u64>>,
269+
) -> BoxFuture<'_, AsyncTiffResult<Vec<Bytes>>>
230270
where
231271
Self: Send,
232272
{
233-
// In practice, get_byte_ranges is only used for fetching tiles, which are unlikely to
234-
// overlap a metadata prefetch.
235-
self.reader.get_byte_ranges(ranges)
273+
// In practice, get_image_byte_ranges is only used for fetching tiles, which are unlikely
274+
// to overlap a metadata prefetch.
275+
self.reader.get_image_byte_ranges(ranges)
236276
}
237277
}
238278

@@ -293,7 +333,7 @@ impl AsyncCursor {
293333
pub(crate) async fn read(&mut self, length: u64) -> AsyncTiffResult<EndianAwareReader> {
294334
let range = self.offset as _..(self.offset + length) as _;
295335
self.offset += length;
296-
let bytes = self.reader.get_bytes(range).await?;
336+
let bytes = self.reader.get_metadata_bytes(range).await?;
297337
Ok(EndianAwareReader {
298338
reader: bytes.reader(),
299339
endianness: self.endianness,

0 commit comments

Comments
 (0)