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