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