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}