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