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