@@ -20,30 +20,38 @@ use crate::error::{AsyncTiffError, AsyncTiffResult};
20
20
///
21
21
/// Notes:
22
22
///
23
- /// 1. There is a default implementation for types that implement [`tokio::io::AsyncRead`]
24
- /// and [`tokio::io::AsyncSeek`], for example [`tokio::fs::File`].
23
+ /// 1. There are distinct traits for accessing "metadata bytes" and "image bytes". The requests for
24
+ /// "metadata bytes" from `get_metadata_bytes` will be called from `TIFF.open`, while parsing
25
+ /// IFDs. Requests for "image bytes" from `get_image_bytes` and `get_image_byte_ranges` will be
26
+ /// called while fetching data from TIFF tiles or strips.
25
27
///
26
28
/// 2. [`ObjectReader`], available when the `object_store` crate feature
27
29
/// is enabled, implements this interface for [`ObjectStore`].
28
30
///
31
+ /// 3. You can use [`TokioReader`] to implement [`AsyncFileReader`] for types that implement
32
+ /// [`tokio::io::AsyncRead`] and [`tokio::io::AsyncSeek`], for example [`tokio::fs::File`].
33
+ ///
29
34
/// [`ObjectStore`]: object_store::ObjectStore
30
35
///
31
36
/// [`tokio::fs::File`]: https://docs.rs/tokio/latest/tokio/fs/struct.File.html
32
37
pub trait AsyncFileReader : Debug + Send + Sync {
33
- /// Retrieve the bytes in `range`
34
- fn get_bytes ( & self , range : Range < u64 > ) -> BoxFuture < ' _ , AsyncTiffResult < Bytes > > ;
38
+ /// Retrieve the bytes in `range` as part of a request for header metadata.
39
+ fn get_metadata_bytes ( & self , range : Range < u64 > ) -> BoxFuture < ' _ , AsyncTiffResult < Bytes > > ;
40
+
41
+ /// Retrieve the bytes in `range` as part of a request for image data, not header metadata.
42
+ fn get_image_bytes ( & self , range : Range < u64 > ) -> BoxFuture < ' _ , AsyncTiffResult < Bytes > > ;
35
43
36
- /// Retrieve multiple byte ranges. The default implementation will call `get_bytes`
37
- /// sequentially
38
- fn get_byte_ranges (
44
+ /// Retrieve multiple byte ranges as part of a request for image data, not header metadata. The
45
+ /// default implementation will call `get_image_bytes` sequentially
46
+ fn get_image_byte_ranges (
39
47
& self ,
40
48
ranges : Vec < Range < u64 > > ,
41
49
) -> BoxFuture < ' _ , AsyncTiffResult < Vec < Bytes > > > {
42
50
async move {
43
51
let mut result = Vec :: with_capacity ( ranges. len ( ) ) ;
44
52
45
53
for range in ranges. into_iter ( ) {
46
- let data = self . get_bytes ( range) . await ?;
54
+ let data = self . get_image_bytes ( range) . await ?;
47
55
result. push ( data) ;
48
56
}
49
57
@@ -55,15 +63,19 @@ pub trait AsyncFileReader: Debug + Send + Sync {
55
63
56
64
/// This allows Box<dyn AsyncFileReader + '_> to be used as an AsyncFileReader,
57
65
impl AsyncFileReader for Box < dyn AsyncFileReader + ' _ > {
58
- fn get_bytes ( & self , range : Range < u64 > ) -> BoxFuture < ' _ , AsyncTiffResult < Bytes > > {
59
- self . as_ref ( ) . get_bytes ( range)
66
+ fn get_metadata_bytes ( & self , range : Range < u64 > ) -> BoxFuture < ' _ , AsyncTiffResult < Bytes > > {
67
+ self . as_ref ( ) . get_metadata_bytes ( range)
68
+ }
69
+
70
+ fn get_image_bytes ( & self , range : Range < u64 > ) -> BoxFuture < ' _ , AsyncTiffResult < Bytes > > {
71
+ self . as_ref ( ) . get_image_bytes ( range)
60
72
}
61
73
62
- fn get_byte_ranges (
74
+ fn get_image_byte_ranges (
63
75
& self ,
64
76
ranges : Vec < Range < u64 > > ,
65
77
) -> BoxFuture < ' _ , AsyncTiffResult < Vec < Bytes > > > {
66
- self . as_ref ( ) . get_byte_ranges ( ranges)
78
+ self . as_ref ( ) . get_image_byte_ranges ( ranges)
67
79
}
68
80
}
69
81
@@ -89,31 +101,36 @@ impl<T: tokio::io::AsyncRead + tokio::io::AsyncSeek + Unpin + Send + Debug> Toki
89
101
pub fn new ( inner : T ) -> Self {
90
102
Self ( tokio:: sync:: Mutex :: new ( inner) )
91
103
}
92
- }
93
104
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 > > {
105
+ async fn make_range_request ( & self , range : Range < u64 > ) -> AsyncTiffResult < Bytes > {
99
106
use std:: io:: SeekFrom ;
100
107
use tokio:: io:: { AsyncReadExt , AsyncSeekExt } ;
101
108
102
- async move {
103
- let mut file = self . 0 . lock ( ) . await ;
104
-
105
- file. seek ( SeekFrom :: Start ( range. start ) ) . await ?;
109
+ let mut file = self . 0 . lock ( ) . await ;
106
110
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
- }
111
+ file. seek ( SeekFrom :: Start ( range. start ) ) . await ?;
113
112
114
- Ok ( buffer. into ( ) )
113
+ let to_read = range. end - range. start ;
114
+ let mut buffer = Vec :: with_capacity ( to_read as usize ) ;
115
+ let read = file. read ( & mut buffer) . await ? as u64 ;
116
+ if read != to_read {
117
+ return Err ( AsyncTiffError :: EndOfFile ( to_read, read) ) ;
115
118
}
116
- . boxed ( )
119
+
120
+ Ok ( buffer. into ( ) )
121
+ }
122
+ }
123
+
124
+ #[ cfg( feature = "tokio" ) ]
125
+ impl < T : tokio:: io:: AsyncRead + tokio:: io:: AsyncSeek + Unpin + Send + Debug > AsyncFileReader
126
+ for TokioReader < T >
127
+ {
128
+ fn get_metadata_bytes ( & self , range : Range < u64 > ) -> BoxFuture < ' _ , AsyncTiffResult < Bytes > > {
129
+ self . make_range_request ( range) . boxed ( )
130
+ }
131
+
132
+ fn get_image_bytes ( & self , range : Range < u64 > ) -> BoxFuture < ' _ , AsyncTiffResult < Bytes > > {
133
+ self . make_range_request ( range) . boxed ( )
117
134
}
118
135
}
119
136
@@ -133,19 +150,30 @@ impl ObjectReader {
133
150
pub fn new ( store : Arc < dyn object_store:: ObjectStore > , path : object_store:: path:: Path ) -> Self {
134
151
Self { store, path }
135
152
}
136
- }
137
153
138
- #[ cfg( feature = "object_store" ) ]
139
- impl AsyncFileReader for ObjectReader {
140
- fn get_bytes ( & self , range : Range < u64 > ) -> BoxFuture < ' _ , AsyncTiffResult < Bytes > > {
154
+ async fn make_range_request ( & self , range : Range < u64 > ) -> AsyncTiffResult < Bytes > {
141
155
let range = range. start as _ ..range. end as _ ;
142
156
self . store
143
157
. get_range ( & self . path , range)
144
158
. map_err ( |e| e. into ( ) )
145
- . boxed ( )
159
+ . await
160
+ }
161
+ }
162
+
163
+ #[ cfg( feature = "object_store" ) ]
164
+ impl AsyncFileReader for ObjectReader {
165
+ fn get_metadata_bytes ( & self , range : Range < u64 > ) -> BoxFuture < ' _ , AsyncTiffResult < Bytes > > {
166
+ self . make_range_request ( range) . boxed ( )
146
167
}
147
168
148
- fn get_byte_ranges ( & self , ranges : Vec < Range < u64 > > ) -> BoxFuture < ' _ , AsyncTiffResult < Vec < Bytes > > >
169
+ fn get_image_bytes ( & self , range : Range < u64 > ) -> BoxFuture < ' _ , AsyncTiffResult < Bytes > > {
170
+ self . make_range_request ( range) . boxed ( )
171
+ }
172
+
173
+ fn get_image_byte_ranges (
174
+ & self ,
175
+ ranges : Vec < Range < u64 > > ,
176
+ ) -> BoxFuture < ' _ , AsyncTiffResult < Vec < Bytes > > >
149
177
where
150
178
Self : Send ,
151
179
{
@@ -177,11 +205,8 @@ impl ReqwestReader {
177
205
pub fn new ( client : reqwest:: Client , url : reqwest:: Url ) -> Self {
178
206
Self { client, url }
179
207
}
180
- }
181
208
182
- #[ cfg( feature = "reqwest" ) ]
183
- impl AsyncFileReader for ReqwestReader {
184
- fn get_bytes ( & self , range : Range < u64 > ) -> BoxFuture < ' _ , AsyncTiffResult < Bytes > > {
209
+ fn make_range_request ( & self , range : Range < u64 > ) -> BoxFuture < ' _ , AsyncTiffResult < Bytes > > {
185
210
let url = self . url . clone ( ) ;
186
211
let client = self . client . clone ( ) ;
187
212
// HTTP range is inclusive, so we need to subtract 1 from the end
@@ -200,6 +225,17 @@ impl AsyncFileReader for ReqwestReader {
200
225
}
201
226
}
202
227
228
+ #[ cfg( feature = "reqwest" ) ]
229
+ impl AsyncFileReader for ReqwestReader {
230
+ fn get_metadata_bytes ( & self , range : Range < u64 > ) -> BoxFuture < ' _ , AsyncTiffResult < Bytes > > {
231
+ self . make_range_request ( range)
232
+ }
233
+
234
+ fn get_image_bytes ( & self , range : Range < u64 > ) -> BoxFuture < ' _ , AsyncTiffResult < Bytes > > {
235
+ self . make_range_request ( range)
236
+ }
237
+ }
238
+
203
239
/// An AsyncFileReader that caches the first `prefetch` bytes of a file.
204
240
#[ derive( Debug ) ]
205
241
pub struct PrefetchReader {
@@ -210,34 +246,43 @@ pub struct PrefetchReader {
210
246
impl PrefetchReader {
211
247
/// Construct a new PrefetchReader, catching the first `prefetch` bytes of the file.
212
248
pub async fn new ( reader : Arc < dyn AsyncFileReader > , prefetch : u64 ) -> AsyncTiffResult < Self > {
213
- let buffer = reader. get_bytes ( 0 ..prefetch) . await ?;
249
+ let buffer = reader. get_metadata_bytes ( 0 ..prefetch) . await ?;
214
250
Ok ( Self { reader, buffer } )
215
251
}
216
252
}
217
253
218
254
impl AsyncFileReader for PrefetchReader {
219
- fn get_bytes ( & self , range : Range < u64 > ) -> BoxFuture < ' _ , AsyncTiffResult < Bytes > > {
255
+ fn get_metadata_bytes ( & self , range : Range < u64 > ) -> BoxFuture < ' _ , AsyncTiffResult < Bytes > > {
220
256
if range. start < self . buffer . len ( ) as _ {
221
257
if range. end < self . buffer . len ( ) as _ {
222
258
let usize_range = range. start as usize ..range. end as usize ;
223
259
let result = self . buffer . slice ( usize_range) ;
224
260
async { Ok ( result) } . boxed ( )
225
261
} else {
226
262
// TODO: reuse partial internal buffer
227
- self . reader . get_bytes ( range)
263
+ self . reader . get_metadata_bytes ( range)
228
264
}
229
265
} else {
230
- self . reader . get_bytes ( range)
266
+ self . reader . get_metadata_bytes ( range)
231
267
}
232
268
}
233
269
234
- fn get_byte_ranges ( & self , ranges : Vec < Range < u64 > > ) -> BoxFuture < ' _ , AsyncTiffResult < Vec < Bytes > > >
270
+ fn get_image_bytes ( & self , range : Range < u64 > ) -> BoxFuture < ' _ , AsyncTiffResult < Bytes > > {
271
+ // In practice, get_image_bytes is only used for fetching tiles, which are unlikely
272
+ // to overlap a metadata prefetch.
273
+ self . reader . get_image_bytes ( range)
274
+ }
275
+
276
+ fn get_image_byte_ranges (
277
+ & self ,
278
+ ranges : Vec < Range < u64 > > ,
279
+ ) -> BoxFuture < ' _ , AsyncTiffResult < Vec < Bytes > > >
235
280
where
236
281
Self : Send ,
237
282
{
238
- // In practice, get_byte_ranges is only used for fetching tiles, which are unlikely to
239
- // overlap a metadata prefetch.
240
- self . reader . get_byte_ranges ( ranges)
283
+ // In practice, get_image_byte_ranges is only used for fetching tiles, which are unlikely
284
+ // to overlap a metadata prefetch.
285
+ self . reader . get_image_byte_ranges ( ranges)
241
286
}
242
287
}
243
288
@@ -298,7 +343,7 @@ impl AsyncCursor {
298
343
pub ( crate ) async fn read ( & mut self , length : u64 ) -> AsyncTiffResult < EndianAwareReader > {
299
344
let range = self . offset as _ ..( self . offset + length) as _ ;
300
345
self . offset += length;
301
- let bytes = self . reader . get_bytes ( range) . await ?;
346
+ let bytes = self . reader . get_metadata_bytes ( range) . await ?;
302
347
Ok ( EndianAwareReader {
303
348
reader : bytes. reader ( ) ,
304
349
endianness : self . endianness ,
0 commit comments