opendal/types/options.rs
1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Options module provides options definitions for operations.
19
20use std::collections::HashMap;
21
22use chrono::DateTime;
23use chrono::Utc;
24
25use crate::raw::BytesRange;
26
27/// Options for delete operations.
28#[derive(Debug, Clone, Default, Eq, PartialEq)]
29pub struct DeleteOptions {
30 /// The version of the file to delete.
31 pub version: Option<String>,
32}
33
34/// Options for list operations.
35
36#[derive(Debug, Clone, Default, Eq, PartialEq)]
37pub struct ListOptions {
38 /// The limit passed to underlying service to specify the max results
39 /// that could return per-request.
40 ///
41 /// Users could use this to control the memory usage of list operation.
42 pub limit: Option<usize>,
43 /// The start_after passes to underlying service to specify the specified key
44 /// to start listing from.
45 pub start_after: Option<String>,
46 /// The recursive is used to control whether the list operation is recursive.
47 ///
48 /// - If `false`, list operation will only list the entries under the given path.
49 /// - If `true`, list operation will list all entries that starts with given path.
50 ///
51 /// Default to `false`.
52 pub recursive: bool,
53 /// The version is used to control whether the object versions should be returned.
54 ///
55 /// - If `false`, list operation will not return with object versions
56 /// - If `true`, list operation will return with object versions if object versioning is supported
57 /// by the underlying service
58 ///
59 /// Default to `false`
60 pub versions: bool,
61 /// The deleted is used to control whether the deleted objects should be returned.
62 ///
63 /// - If `false`, list operation will not return with deleted objects
64 /// - If `true`, list operation will return with deleted objects if object versioning is supported
65 /// by the underlying service
66 ///
67 /// Default to `false`
68 pub deleted: bool,
69}
70
71/// Options for read operations.
72#[derive(Debug, Clone, Default, Eq, PartialEq)]
73pub struct ReadOptions {
74 /// Set `range` for this operation.
75 ///
76 /// If we have a file with size `n`.
77 ///
78 /// - `..` means read bytes in range `[0, n)` of file.
79 /// - `0..1024` and `..1024` means read bytes in range `[0, 1024)` of file
80 /// - `1024..` means read bytes in range `[1024, n)` of file
81 ///
82 /// The type implements `From<RangeBounds<u64>>`, so users can use `(1024..).into()` instead.
83 pub range: BytesRange,
84 /// Set `version` for this operation.
85 ///
86 /// This option can be used to retrieve the data of a specified version of the given path.
87 ///
88 /// If the version doesn't exist, an error with kind [`ErrorKind::NotFound`] will be returned.
89 pub version: Option<String>,
90
91 /// Set `if_match` for this operation.
92 ///
93 /// This option can be used to check if the file's `ETag` matches the given `ETag`.
94 ///
95 /// If file exists and it's etag doesn't match, an error with kind [`ErrorKind::ConditionNotMatch`]
96 /// will be returned.
97 pub if_match: Option<String>,
98 /// Set `if_none_match` for this operation.
99 ///
100 /// This option can be used to check if the file's `ETag` doesn't match the given `ETag`.
101 ///
102 /// If file exists and it's etag match, an error with kind [`ErrorKind::ConditionNotMatch`]
103 /// will be returned.
104 pub if_none_match: Option<String>,
105 /// Set `if_modified_since` for this operation.
106 ///
107 /// This option can be used to check if the file has been modified since the given timestamp.
108 ///
109 /// If file exists and it hasn't been modified since the specified time, an error with kind
110 /// [`ErrorKind::ConditionNotMatch`] will be returned.
111 pub if_modified_since: Option<DateTime<Utc>>,
112 /// Set `if_unmodified_since` for this operation.
113 ///
114 /// This feature can be used to check if the file hasn't been modified since the given timestamp.
115 ///
116 /// If file exists and it has been modified since the specified time, an error with kind
117 /// [`ErrorKind::ConditionNotMatch`] will be returned.
118 pub if_unmodified_since: Option<DateTime<Utc>>,
119
120 /// Set `concurrent` for the operation.
121 ///
122 /// OpenDAL by default to read file without concurrent. This is not efficient for cases when users
123 /// read large chunks of data. By setting `concurrent`, opendal will reading files concurrently
124 /// on support storage services.
125 ///
126 /// By setting `concurrent`, opendal will fetch chunks concurrently with
127 /// the give chunk size.
128 ///
129 /// Refer to [`crate::docs::performance`] for more details.
130 pub concurrent: usize,
131 /// Set `chunk` for the operation.
132 ///
133 /// OpenDAL will use services' preferred chunk size by default. Users can set chunk based on their own needs.
134 ///
135 /// Refer to [`crate::docs::performance`] for more details.
136 pub chunk: Option<usize>,
137 /// Controls the optimization strategy for range reads in [`Reader::fetch`].
138 ///
139 /// When performing range reads, if the gap between two requested ranges is smaller than
140 /// the configured `gap` size, OpenDAL will merge these ranges into a single read request
141 /// and discard the unrequested data in between. This helps reduce the number of API calls
142 /// to remote storage services.
143 ///
144 /// This optimization is particularly useful when performing multiple small range reads
145 /// that are close to each other, as it reduces the overhead of multiple network requests
146 /// at the cost of transferring some additional data.
147 ///
148 /// Refer to [`crate::docs::performance`] for more details.
149 pub gap: Option<usize>,
150
151 /// Specify the content-type header that should be sent back by the operation.
152 ///
153 /// This option is only meaningful when used along with presign.
154 pub override_content_type: Option<String>,
155 /// Specify the `cache-control` header that should be sent back by the operation.
156 ///
157 /// This option is only meaningful when used along with presign.
158 pub override_cache_control: Option<String>,
159 /// Specify the `content-disposition` header that should be sent back by the operation.
160 ///
161 /// This option is only meaningful when used along with presign.
162 pub override_content_disposition: Option<String>,
163}
164
165/// Options for reader operations.
166#[derive(Debug, Clone, Default, Eq, PartialEq)]
167pub struct ReaderOptions {
168 /// Set `version` for this operation.
169 ///
170 /// This option can be used to retrieve the data of a specified version of the given path.
171 ///
172 /// If the version doesn't exist, an error with kind [`ErrorKind::NotFound`] will be returned.
173 pub version: Option<String>,
174
175 /// Set `if_match` for this operation.
176 ///
177 /// This option can be used to check if the file's `ETag` matches the given `ETag`.
178 ///
179 /// If file exists and it's etag doesn't match, an error with kind [`ErrorKind::ConditionNotMatch`]
180 /// will be returned.
181 pub if_match: Option<String>,
182 /// Set `if_none_match` for this operation.
183 ///
184 /// This option can be used to check if the file's `ETag` doesn't match the given `ETag`.
185 ///
186 /// If file exists and it's etag match, an error with kind [`ErrorKind::ConditionNotMatch`]
187 /// will be returned.
188 pub if_none_match: Option<String>,
189 /// Set `if_modified_since` for this operation.
190 ///
191 /// This option can be used to check if the file has been modified since the given timestamp.
192 ///
193 /// If file exists and it hasn't been modified since the specified time, an error with kind
194 /// [`ErrorKind::ConditionNotMatch`] will be returned.
195 pub if_modified_since: Option<DateTime<Utc>>,
196 /// Set `if_unmodified_since` for this operation.
197 ///
198 /// This feature can be used to check if the file hasn't been modified since the given timestamp.
199 ///
200 /// If file exists and it has been modified since the specified time, an error with kind
201 /// [`ErrorKind::ConditionNotMatch`] will be returned.
202 pub if_unmodified_since: Option<DateTime<Utc>>,
203
204 /// Set `concurrent` for the operation.
205 ///
206 /// OpenDAL by default to read file without concurrent. This is not efficient for cases when users
207 /// read large chunks of data. By setting `concurrent`, opendal will reading files concurrently
208 /// on support storage services.
209 ///
210 /// By setting `concurrent`, opendal will fetch chunks concurrently with
211 /// the give chunk size.
212 ///
213 /// Refer to [`crate::docs::performance`] for more details.
214 pub concurrent: usize,
215 /// Set `chunk` for the operation.
216 ///
217 /// OpenDAL will use services' preferred chunk size by default. Users can set chunk based on their own needs.
218 ///
219 /// Refer to [`crate::docs::performance`] for more details.
220 pub chunk: Option<usize>,
221 /// Controls the optimization strategy for range reads in [`Reader::fetch`].
222 ///
223 /// When performing range reads, if the gap between two requested ranges is smaller than
224 /// the configured `gap` size, OpenDAL will merge these ranges into a single read request
225 /// and discard the unrequested data in between. This helps reduce the number of API calls
226 /// to remote storage services.
227 ///
228 /// This optimization is particularly useful when performing multiple small range reads
229 /// that are close to each other, as it reduces the overhead of multiple network requests
230 /// at the cost of transferring some additional data.
231 ///
232 /// Refer to [`crate::docs::performance`] for more details.
233 pub gap: Option<usize>,
234 /// Controls the number of prefetched bytes ranges that can be buffered in memory
235 /// during concurrent reading.
236 ///
237 /// When performing concurrent reads with `Reader`, this option limits how many
238 /// completed-but-not-yet-read chunks can be buffered. Once the number of buffered
239 /// chunks reaches this limit, no new read tasks will be spawned until some of the
240 /// buffered chunks are consumed.
241 ///
242 /// - Default value: 0 (no prefetching, strict back-pressure control)
243 /// - Set to a higher value to allow more aggressive prefetching at the cost of memory
244 ///
245 /// This option helps prevent memory exhaustion when reading large files with high
246 /// concurrency settings.
247 pub prefetch: usize,
248}
249
250/// Options for stat operations.
251#[derive(Debug, Clone, Default, Eq, PartialEq)]
252pub struct StatOptions {
253 /// Set `version` for this operation.
254 ///
255 /// This options can be used to retrieve the data of a specified version of the given path.
256 ///
257 /// If the version doesn't exist, an error with kind [`ErrorKind::NotFound`] will be returned.
258 pub version: Option<String>,
259
260 /// Set `if_match` for this operation.
261 ///
262 /// This option can be used to check if the file's `ETag` matches the given `ETag`.
263 ///
264 /// If file exists and it's etag doesn't match, an error with kind [`ErrorKind::ConditionNotMatch`]
265 /// will be returned.
266 pub if_match: Option<String>,
267 /// Set `if_none_match` for this operation.
268 ///
269 /// This option can be used to check if the file's `ETag` doesn't match the given `ETag`.
270 ///
271 /// If file exists and it's etag match, an error with kind [`ErrorKind::ConditionNotMatch`]
272 /// will be returned.
273 pub if_none_match: Option<String>,
274 /// Set `if_modified_since` for this operation.
275 ///
276 /// This option can be used to check if the file has been modified since the given timestamp.
277 ///
278 /// If file exists and it hasn't been modified since the specified time, an error with kind
279 /// [`ErrorKind::ConditionNotMatch`] will be returned.
280 pub if_modified_since: Option<DateTime<Utc>>,
281 /// Set `if_unmodified_since` for this operation.
282 ///
283 /// This feature can be used to check if the file hasn't been modified since the given timestamp.
284 ///
285 /// If file exists and it has been modified since the specified time, an error with kind
286 /// [`ErrorKind::ConditionNotMatch`] will be returned.
287 pub if_unmodified_since: Option<DateTime<Utc>>,
288
289 /// Specify the content-type header that should be sent back by the operation.
290 ///
291 /// This option is only meaningful when used along with presign.
292 pub override_content_type: Option<String>,
293 /// Specify the `cache-control` header that should be sent back by the operation.
294 ///
295 /// This option is only meaningful when used along with presign.
296 pub override_cache_control: Option<String>,
297 /// Specify the `content-disposition` header that should be sent back by the operation.
298 ///
299 /// This option is only meaningful when used along with presign.
300 pub override_content_disposition: Option<String>,
301}
302
303/// Options for write operations.
304#[derive(Debug, Clone, Default, Eq, PartialEq)]
305pub struct WriteOptions {
306 /// Sets append mode for this operation.
307 ///
308 /// ### Capability
309 ///
310 /// Check [`Capability::write_can_append`] before using this option.
311 ///
312 /// ### Behavior
313 ///
314 /// - By default, write operations overwrite existing files
315 /// - When append is set to true:
316 /// - New data will be appended to the end of existing file
317 /// - If file doesn't exist, it will be created
318 /// - If not supported, will return an error
319 ///
320 /// This operation allows adding data to existing files instead of overwriting them.
321 pub append: bool,
322
323 /// Sets Cache-Control header for this write operation.
324 ///
325 /// ### Capability
326 ///
327 /// Check [`Capability::write_with_cache_control`] before using this feature.
328 ///
329 /// ### Behavior
330 ///
331 /// - If supported, sets Cache-Control as system metadata on the target file
332 /// - The value should follow HTTP Cache-Control header format
333 /// - If not supported, the value will be ignored
334 ///
335 /// This operation allows controlling caching behavior for the written content.
336 ///
337 /// ### Use Cases
338 ///
339 /// - Setting browser cache duration
340 /// - Configuring CDN behavior
341 /// - Optimizing content delivery
342 /// - Managing cache invalidation
343 ///
344 /// ### References
345 ///
346 /// - [MDN Cache-Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control)
347 /// - [RFC 7234 Section 5.2](https://tools.ietf.org/html/rfc7234#section-5.2)
348 pub cache_control: Option<String>,
349 /// Sets `Content-Type` header for this write operation.
350 ///
351 /// ## Capability
352 ///
353 /// Check [`Capability::write_with_content_type`] before using this feature.
354 ///
355 /// ### Behavior
356 ///
357 /// - If supported, sets Content-Type as system metadata on the target file
358 /// - The value should follow MIME type format (e.g. "text/plain", "image/jpeg")
359 /// - If not supported, the value will be ignored
360 ///
361 /// This operation allows specifying the media type of the content being written.
362 pub content_type: Option<String>,
363 /// Sets Content-Disposition header for this write request.
364 ///
365 /// ### Capability
366 ///
367 /// Check [`Capability::write_with_content_disposition`] before using this feature.
368 ///
369 /// ### Behavior
370 ///
371 /// - If supported, sets Content-Disposition as system metadata on the target file
372 /// - The value should follow HTTP Content-Disposition header format
373 /// - Common values include:
374 /// - `inline` - Content displayed within browser
375 /// - `attachment` - Content downloaded as file
376 /// - `attachment; filename="example.jpg"` - Downloaded with specified filename
377 /// - If not supported, the value will be ignored
378 ///
379 /// This operation allows controlling how the content should be displayed or downloaded.
380 pub content_disposition: Option<String>,
381 /// Sets Content-Encoding header for this write request.
382 ///
383 /// ### Capability
384 ///
385 /// Check [`Capability::write_with_content_encoding`] before using this feature.
386 ///
387 /// ### Behavior
388 ///
389 /// - If supported, sets Content-Encoding as system metadata on the target file
390 /// - The value should follow HTTP Content-Encoding header format
391 /// - Common values include:
392 /// - `gzip` - Content encoded using gzip compression
393 /// - `deflate` - Content encoded using deflate compression
394 /// - `br` - Content encoded using Brotli compression
395 /// - `identity` - No encoding applied (default value)
396 /// - If not supported, the value will be ignored
397 ///
398 /// This operation allows specifying the encoding applied to the content being written.
399 pub content_encoding: Option<String>,
400 /// Sets user metadata for this write request.
401 ///
402 /// ### Capability
403 ///
404 /// Check [`Capability::write_with_user_metadata`] before using this feature.
405 ///
406 /// ### Behavior
407 ///
408 /// - If supported, the user metadata will be attached to the object during write
409 /// - Accepts key-value pairs where both key and value are strings
410 /// - Keys are case-insensitive in most services
411 /// - Services may have limitations for user metadata, for example:
412 /// - Key length is typically limited (e.g., 1024 bytes)
413 /// - Value length is typically limited (e.g., 4096 bytes)
414 /// - Total metadata size might be limited
415 /// - Some characters might be forbidden in keys
416 /// - If not supported, the metadata will be ignored
417 ///
418 /// User metadata provides a way to attach custom metadata to objects during write operations.
419 /// This metadata can be retrieved later when reading the object.
420 pub user_metadata: Option<HashMap<String, String>>,
421
422 /// Sets If-Match header for this write request.
423 ///
424 /// ### Capability
425 ///
426 /// Check [`Capability::write_with_if_match`] before using this feature.
427 ///
428 /// ### Behavior
429 ///
430 /// - If supported, the write operation will only succeed if the target's ETag matches the specified value
431 /// - The value should be a valid ETag string
432 /// - Common values include:
433 /// - A specific ETag value like `"686897696a7c876b7e"`
434 /// - `*` - Matches any existing resource
435 /// - If not supported, the value will be ignored
436 ///
437 /// This operation provides conditional write functionality based on ETag matching,
438 /// helping prevent unintended overwrites in concurrent scenarios.
439 pub if_match: Option<String>,
440 /// Sets If-None-Match header for this write request.
441 ///
442 /// Note: Certain services, like `s3`, support `if_not_exists` but not `if_none_match`.
443 /// Use `if_not_exists` if you only want to check whether a file exists.
444 ///
445 /// ### Capability
446 ///
447 /// Check [`Capability::write_with_if_none_match`] before using this feature.
448 ///
449 /// ### Behavior
450 ///
451 /// - If supported, the write operation will only succeed if the target's ETag does not match the specified value
452 /// - The value should be a valid ETag string
453 /// - Common values include:
454 /// - A specific ETag value like `"686897696a7c876b7e"`
455 /// - `*` - Matches if the resource does not exist
456 /// - If not supported, the value will be ignored
457 ///
458 /// This operation provides conditional write functionality based on ETag non-matching,
459 /// useful for preventing overwriting existing resources or ensuring unique writes.
460 pub if_none_match: Option<String>,
461 /// Sets the condition that write operation will succeed only if target does not exist.
462 ///
463 /// ### Capability
464 ///
465 /// Check [`Capability::write_with_if_not_exists`] before using this feature.
466 ///
467 /// ### Behavior
468 ///
469 /// - If supported, the write operation will only succeed if the target path does not exist
470 /// - Will return error if target already exists
471 /// - If not supported, the value will be ignored
472 ///
473 /// This operation provides a way to ensure write operations only create new resources
474 /// without overwriting existing ones, useful for implementing "create if not exists" logic.
475 pub if_not_exists: bool,
476
477 /// Sets concurrent write operations for this writer.
478 ///
479 /// ## Behavior
480 ///
481 /// - By default, OpenDAL writes files sequentially
482 /// - When concurrent is set:
483 /// - Multiple write operations can execute in parallel
484 /// - Write operations return immediately without waiting if tasks space are available
485 /// - Close operation ensures all writes complete in order
486 /// - Memory usage increases with concurrency level
487 /// - If not supported, falls back to sequential writes
488 ///
489 /// This feature significantly improves performance when:
490 /// - Writing large files
491 /// - Network latency is high
492 /// - Storage service supports concurrent uploads like multipart uploads
493 ///
494 /// ## Performance Impact
495 ///
496 /// Setting appropriate concurrency can:
497 /// - Increase write throughput
498 /// - Reduce total write time
499 /// - Better utilize available bandwidth
500 /// - Trade memory for performance
501 pub concurrent: usize,
502 /// Sets chunk size for buffered writes.
503 ///
504 /// ### Capability
505 ///
506 /// Check [`Capability::write_multi_min_size`] and [`Capability::write_multi_max_size`] for size limits.
507 ///
508 /// ### Behavior
509 ///
510 /// - By default, OpenDAL sets optimal chunk size based on service capabilities
511 /// - When chunk size is set:
512 /// - Data will be buffered until reaching chunk size
513 /// - One API call will be made per chunk
514 /// - Last chunk may be smaller than chunk size
515 /// - Important considerations:
516 /// - Some services require minimum chunk sizes (e.g. S3's EntityTooSmall error)
517 /// - Smaller chunks increase API calls and costs
518 /// - Larger chunks increase memory usage, but improve performance and reduce costs
519 ///
520 /// ### Performance Impact
521 ///
522 /// Setting appropriate chunk size can:
523 /// - Reduce number of API calls
524 /// - Improve overall throughput
525 /// - Lower operation costs
526 /// - Better utilize network bandwidth
527 pub chunk: Option<usize>,
528}
529
530/// Options for copy operations.
531#[derive(Debug, Clone, Default, Eq, PartialEq)]
532pub struct CopyOptions {
533 /// Sets the condition that copy operation will succeed only if target does not exist.
534 ///
535 /// ### Capability
536 ///
537 /// Check [`Capability::copy_with_if_not_exists`] before using this feature.
538 ///
539 /// ### Behavior
540 ///
541 /// - If supported, the copy operation will only succeed if the target path does not exist
542 /// - Will return error if target already exists
543 /// - If not supported, the value will be ignored
544 ///
545 /// This operation provides a way to ensure copy operations only create new resources
546 /// without overwriting existing ones, useful for implementing "copy if not exists" logic.
547 pub if_not_exists: bool,
548}