opendal/raw/
ops.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//! Ops provides the operation args struct like [`OpRead`] for user.
19//!
20//! By using ops, users can add more context for operation.
21
22use crate::{options, raw::*};
23use chrono::{DateTime, Utc};
24use std::collections::HashMap;
25use std::time::Duration;
26
27/// Args for `create` operation.
28///
29/// The path must be normalized.
30#[derive(Debug, Clone, Default)]
31pub struct OpCreateDir {}
32
33impl OpCreateDir {
34    /// Create a new `OpCreateDir`.
35    pub fn new() -> Self {
36        Self::default()
37    }
38}
39
40/// Args for `delete` operation.
41///
42/// The path must be normalized.
43#[derive(Debug, Clone, Default, Eq, Hash, PartialEq)]
44pub struct OpDelete {
45    version: Option<String>,
46}
47
48impl OpDelete {
49    /// Create a new `OpDelete`.
50    pub fn new() -> Self {
51        Self::default()
52    }
53}
54
55impl OpDelete {
56    /// Change the version of this delete operation.
57    pub fn with_version(mut self, version: &str) -> Self {
58        self.version = Some(version.into());
59        self
60    }
61
62    /// Get the version of this delete operation.
63    pub fn version(&self) -> Option<&str> {
64        self.version.as_deref()
65    }
66}
67
68impl From<options::DeleteOptions> for OpDelete {
69    fn from(value: options::DeleteOptions) -> Self {
70        Self {
71            version: value.version,
72        }
73    }
74}
75
76/// Args for `delete` operation.
77///
78/// The path must be normalized.
79#[derive(Debug, Clone, Default)]
80pub struct OpDeleter {}
81
82impl OpDeleter {
83    /// Create a new `OpDelete`.
84    pub fn new() -> Self {
85        Self::default()
86    }
87}
88
89/// Args for `list` operation.
90#[derive(Debug, Clone, Default)]
91pub struct OpList {
92    /// The limit passed to underlying service to specify the max results
93    /// that could return per-request.
94    ///
95    /// Users could use this to control the memory usage of list operation.
96    limit: Option<usize>,
97    /// The start_after passes to underlying service to specify the specified key
98    /// to start listing from.
99    start_after: Option<String>,
100    /// The recursive is used to control whether the list operation is recursive.
101    ///
102    /// - If `false`, list operation will only list the entries under the given path.
103    /// - If `true`, list operation will list all entries that starts with given path.
104    ///
105    /// Default to `false`.
106    recursive: bool,
107    /// The version is used to control whether the object versions should be returned.
108    ///
109    /// - If `false`, list operation will not return with object versions
110    /// - If `true`, list operation will return with object versions if object versioning is supported
111    ///   by the underlying service
112    ///
113    /// Default to `false`
114    versions: bool,
115    /// The deleted is used to control whether the deleted objects should be returned.
116    ///
117    /// - If `false`, list operation will not return with deleted objects
118    /// - If `true`, list operation will return with deleted objects if object versioning is supported
119    ///   by the underlying service
120    ///
121    /// Default to `false`
122    deleted: bool,
123}
124
125impl OpList {
126    /// Create a new `OpList`.
127    pub fn new() -> Self {
128        Self::default()
129    }
130
131    /// Change the limit of this list operation.
132    pub fn with_limit(mut self, limit: usize) -> Self {
133        self.limit = Some(limit);
134        self
135    }
136
137    /// Get the limit of list operation.
138    pub fn limit(&self) -> Option<usize> {
139        self.limit
140    }
141
142    /// Change the start_after of this list operation.
143    pub fn with_start_after(mut self, start_after: &str) -> Self {
144        self.start_after = Some(start_after.into());
145        self
146    }
147
148    /// Get the start_after of list operation.
149    pub fn start_after(&self) -> Option<&str> {
150        self.start_after.as_deref()
151    }
152
153    /// The recursive is used to control whether the list operation is recursive.
154    ///
155    /// - If `false`, list operation will only list the entries under the given path.
156    /// - If `true`, list operation will list all entries that starts with given path.
157    ///
158    /// Default to `false`.
159    pub fn with_recursive(mut self, recursive: bool) -> Self {
160        self.recursive = recursive;
161        self
162    }
163
164    /// Get the current recursive.
165    pub fn recursive(&self) -> bool {
166        self.recursive
167    }
168
169    /// Change the concurrent of this list operation.
170    ///
171    /// The default concurrent is 1.
172    #[deprecated(since = "0.53.2", note = "concurrent in list is no-op")]
173    pub fn with_concurrent(self, concurrent: usize) -> Self {
174        let _ = concurrent;
175        self
176    }
177
178    /// Get the concurrent of list operation.
179    #[deprecated(since = "0.53.2", note = "concurrent in list is no-op")]
180    pub fn concurrent(&self) -> usize {
181        0
182    }
183
184    /// Change the version of this list operation
185    #[deprecated(since = "0.51.1", note = "use with_versions instead")]
186    pub fn with_version(mut self, version: bool) -> Self {
187        self.versions = version;
188        self
189    }
190
191    /// Change the version of this list operation
192    pub fn with_versions(mut self, versions: bool) -> Self {
193        self.versions = versions;
194        self
195    }
196
197    /// Get the version of this list operation
198    #[deprecated(since = "0.51.1", note = "use versions instead")]
199    pub fn version(&self) -> bool {
200        self.versions
201    }
202
203    /// Get the version of this list operation
204    pub fn versions(&self) -> bool {
205        self.versions
206    }
207
208    /// Change the deleted of this list operation
209    pub fn with_deleted(mut self, deleted: bool) -> Self {
210        self.deleted = deleted;
211        self
212    }
213
214    /// Get the deleted of this list operation
215    pub fn deleted(&self) -> bool {
216        self.deleted
217    }
218}
219
220impl From<options::ListOptions> for OpList {
221    fn from(value: options::ListOptions) -> Self {
222        Self {
223            limit: value.limit,
224            start_after: value.start_after,
225            recursive: value.recursive,
226            versions: value.versions,
227            deleted: value.deleted,
228        }
229    }
230}
231
232/// Args for `presign` operation.
233///
234/// The path must be normalized.
235#[derive(Debug, Clone)]
236pub struct OpPresign {
237    expire: Duration,
238
239    op: PresignOperation,
240}
241
242impl OpPresign {
243    /// Create a new `OpPresign`.
244    pub fn new(op: impl Into<PresignOperation>, expire: Duration) -> Self {
245        Self {
246            op: op.into(),
247            expire,
248        }
249    }
250
251    /// Get operation from op.
252    pub fn operation(&self) -> &PresignOperation {
253        &self.op
254    }
255
256    /// Get expire from op.
257    pub fn expire(&self) -> Duration {
258        self.expire
259    }
260
261    /// Consume OpPresign into (Duration, PresignOperation)
262    pub fn into_parts(self) -> (Duration, PresignOperation) {
263        (self.expire, self.op)
264    }
265}
266
267/// Presign operation used for presign.
268#[derive(Debug, Clone)]
269#[non_exhaustive]
270pub enum PresignOperation {
271    /// Presign a stat(head) operation.
272    Stat(OpStat),
273    /// Presign a read operation.
274    Read(OpRead),
275    /// Presign a write operation.
276    Write(OpWrite),
277    /// Presign a delete operation.
278    Delete(OpDelete),
279}
280
281impl From<OpStat> for PresignOperation {
282    fn from(op: OpStat) -> Self {
283        Self::Stat(op)
284    }
285}
286
287impl From<OpRead> for PresignOperation {
288    fn from(v: OpRead) -> Self {
289        Self::Read(v)
290    }
291}
292
293impl From<OpWrite> for PresignOperation {
294    fn from(v: OpWrite) -> Self {
295        Self::Write(v)
296    }
297}
298
299impl From<OpDelete> for PresignOperation {
300    fn from(v: OpDelete) -> Self {
301        Self::Delete(v)
302    }
303}
304
305/// Args for `read` operation.
306#[derive(Debug, Clone, Default)]
307pub struct OpRead {
308    range: BytesRange,
309    if_match: Option<String>,
310    if_none_match: Option<String>,
311    if_modified_since: Option<DateTime<Utc>>,
312    if_unmodified_since: Option<DateTime<Utc>>,
313    override_content_type: Option<String>,
314    override_cache_control: Option<String>,
315    override_content_disposition: Option<String>,
316    version: Option<String>,
317}
318
319impl OpRead {
320    /// Create a default `OpRead` which will read whole content of path.
321    pub fn new() -> Self {
322        Self::default()
323    }
324
325    /// Set the range of the option
326    pub fn with_range(mut self, range: BytesRange) -> Self {
327        self.range = range;
328        self
329    }
330
331    /// Get range from option
332    pub fn range(&self) -> BytesRange {
333        self.range
334    }
335
336    /// Returns a mutable range to allow updating.
337    pub(crate) fn range_mut(&mut self) -> &mut BytesRange {
338        &mut self.range
339    }
340
341    /// Sets the content-disposition header that should be sent back by the remote read operation.
342    pub fn with_override_content_disposition(mut self, content_disposition: &str) -> Self {
343        self.override_content_disposition = Some(content_disposition.into());
344        self
345    }
346
347    /// Returns the content-disposition header that should be sent back by the remote read
348    /// operation.
349    pub fn override_content_disposition(&self) -> Option<&str> {
350        self.override_content_disposition.as_deref()
351    }
352
353    /// Sets the cache-control header that should be sent back by the remote read operation.
354    pub fn with_override_cache_control(mut self, cache_control: &str) -> Self {
355        self.override_cache_control = Some(cache_control.into());
356        self
357    }
358
359    /// Returns the cache-control header that should be sent back by the remote read operation.
360    pub fn override_cache_control(&self) -> Option<&str> {
361        self.override_cache_control.as_deref()
362    }
363
364    /// Sets the content-type header that should be sent back by the remote read operation.
365    pub fn with_override_content_type(mut self, content_type: &str) -> Self {
366        self.override_content_type = Some(content_type.into());
367        self
368    }
369
370    /// Returns the content-type header that should be sent back by the remote read operation.
371    pub fn override_content_type(&self) -> Option<&str> {
372        self.override_content_type.as_deref()
373    }
374
375    /// Set the If-Match of the option
376    pub fn with_if_match(mut self, if_match: &str) -> Self {
377        self.if_match = Some(if_match.to_string());
378        self
379    }
380
381    /// Get If-Match from option
382    pub fn if_match(&self) -> Option<&str> {
383        self.if_match.as_deref()
384    }
385
386    /// Set the If-None-Match of the option
387    pub fn with_if_none_match(mut self, if_none_match: &str) -> Self {
388        self.if_none_match = Some(if_none_match.to_string());
389        self
390    }
391
392    /// Get If-None-Match from option
393    pub fn if_none_match(&self) -> Option<&str> {
394        self.if_none_match.as_deref()
395    }
396
397    /// Set the If-Modified-Since of the option
398    pub fn with_if_modified_since(mut self, v: DateTime<Utc>) -> Self {
399        self.if_modified_since = Some(v);
400        self
401    }
402
403    /// Get If-Modified-Since from option
404    pub fn if_modified_since(&self) -> Option<DateTime<Utc>> {
405        self.if_modified_since
406    }
407
408    /// Set the If-Unmodified-Since of the option
409    pub fn with_if_unmodified_since(mut self, v: DateTime<Utc>) -> Self {
410        self.if_unmodified_since = Some(v);
411        self
412    }
413
414    /// Get If-Unmodified-Since from option
415    pub fn if_unmodified_since(&self) -> Option<DateTime<Utc>> {
416        self.if_unmodified_since
417    }
418
419    /// Set the version of the option
420    pub fn with_version(mut self, version: &str) -> Self {
421        self.version = Some(version.to_string());
422        self
423    }
424
425    /// Get version from option
426    pub fn version(&self) -> Option<&str> {
427        self.version.as_deref()
428    }
429}
430
431/// Args for reader operation.
432#[derive(Debug, Clone)]
433pub struct OpReader {
434    /// The concurrent requests that reader can send.
435    concurrent: usize,
436    /// The chunk size of each request.
437    chunk: Option<usize>,
438    /// The gap size of each request.
439    gap: Option<usize>,
440}
441
442impl Default for OpReader {
443    fn default() -> Self {
444        Self {
445            concurrent: 1,
446            chunk: None,
447            gap: None,
448        }
449    }
450}
451
452impl OpReader {
453    /// Create a new `OpReader`.
454    pub fn new() -> Self {
455        Self::default()
456    }
457
458    /// Set the concurrent of the option
459    pub fn with_concurrent(mut self, concurrent: usize) -> Self {
460        self.concurrent = concurrent.max(1);
461        self
462    }
463
464    /// Get concurrent from option
465    pub fn concurrent(&self) -> usize {
466        self.concurrent
467    }
468
469    /// Set the chunk of the option
470    pub fn with_chunk(mut self, chunk: usize) -> Self {
471        self.chunk = Some(chunk.max(1));
472        self
473    }
474
475    /// Get chunk from option
476    pub fn chunk(&self) -> Option<usize> {
477        self.chunk
478    }
479
480    /// Set the gap of the option
481    pub fn with_gap(mut self, gap: usize) -> Self {
482        self.gap = Some(gap.max(1));
483        self
484    }
485
486    /// Get gap from option
487    pub fn gap(&self) -> Option<usize> {
488        self.gap
489    }
490}
491
492impl From<options::ReadOptions> for (OpRead, OpReader) {
493    fn from(value: options::ReadOptions) -> Self {
494        (
495            OpRead {
496                range: value.range,
497                if_match: value.if_match,
498                if_none_match: value.if_none_match,
499                if_modified_since: value.if_modified_since,
500                if_unmodified_since: value.if_unmodified_since,
501                override_content_type: value.override_content_type,
502                override_cache_control: value.override_cache_control,
503                override_content_disposition: value.override_content_disposition,
504                version: value.version,
505            },
506            OpReader {
507                // Ensure concurrent is at least 1
508                concurrent: value.concurrent.max(1),
509                chunk: value.chunk,
510                gap: value.gap,
511            },
512        )
513    }
514}
515
516impl From<options::ReaderOptions> for (OpRead, OpReader) {
517    fn from(value: options::ReaderOptions) -> Self {
518        (
519            OpRead {
520                range: BytesRange::default(),
521                if_match: value.if_match,
522                if_none_match: value.if_none_match,
523                if_modified_since: value.if_modified_since,
524                if_unmodified_since: value.if_unmodified_since,
525                override_content_type: None,
526                override_cache_control: None,
527                override_content_disposition: None,
528                version: value.version,
529            },
530            OpReader {
531                // Ensure concurrent is at least 1
532                concurrent: value.concurrent.max(1),
533                chunk: value.chunk,
534                gap: value.gap,
535            },
536        )
537    }
538}
539
540/// Args for `stat` operation.
541#[derive(Debug, Clone, Default)]
542pub struct OpStat {
543    if_match: Option<String>,
544    if_none_match: Option<String>,
545    if_modified_since: Option<DateTime<Utc>>,
546    if_unmodified_since: Option<DateTime<Utc>>,
547    override_content_type: Option<String>,
548    override_cache_control: Option<String>,
549    override_content_disposition: Option<String>,
550    version: Option<String>,
551}
552
553impl OpStat {
554    /// Create a new `OpStat`.
555    pub fn new() -> Self {
556        Self::default()
557    }
558
559    /// Set the If-Match of the option
560    pub fn with_if_match(mut self, if_match: &str) -> Self {
561        self.if_match = Some(if_match.to_string());
562        self
563    }
564
565    /// Get If-Match from option
566    pub fn if_match(&self) -> Option<&str> {
567        self.if_match.as_deref()
568    }
569
570    /// Set the If-None-Match of the option
571    pub fn with_if_none_match(mut self, if_none_match: &str) -> Self {
572        self.if_none_match = Some(if_none_match.to_string());
573        self
574    }
575
576    /// Get If-None-Match from option
577    pub fn if_none_match(&self) -> Option<&str> {
578        self.if_none_match.as_deref()
579    }
580
581    /// Set the If-Modified-Since of the option
582    pub fn with_if_modified_since(mut self, v: DateTime<Utc>) -> Self {
583        self.if_modified_since = Some(v);
584        self
585    }
586
587    /// Get If-Modified-Since from option
588    pub fn if_modified_since(&self) -> Option<DateTime<Utc>> {
589        self.if_modified_since
590    }
591
592    /// Set the If-Unmodified-Since of the option
593    pub fn with_if_unmodified_since(mut self, v: DateTime<Utc>) -> Self {
594        self.if_unmodified_since = Some(v);
595        self
596    }
597
598    /// Get If-Unmodified-Since from option
599    pub fn if_unmodified_since(&self) -> Option<DateTime<Utc>> {
600        self.if_unmodified_since
601    }
602
603    /// Sets the content-disposition header that should be sent back by the remote read operation.
604    pub fn with_override_content_disposition(mut self, content_disposition: &str) -> Self {
605        self.override_content_disposition = Some(content_disposition.into());
606        self
607    }
608
609    /// Returns the content-disposition header that should be sent back by the remote read
610    /// operation.
611    pub fn override_content_disposition(&self) -> Option<&str> {
612        self.override_content_disposition.as_deref()
613    }
614
615    /// Sets the cache-control header that should be sent back by the remote read operation.
616    pub fn with_override_cache_control(mut self, cache_control: &str) -> Self {
617        self.override_cache_control = Some(cache_control.into());
618        self
619    }
620
621    /// Returns the cache-control header that should be sent back by the remote read operation.
622    pub fn override_cache_control(&self) -> Option<&str> {
623        self.override_cache_control.as_deref()
624    }
625
626    /// Sets the content-type header that should be sent back by the remote read operation.
627    pub fn with_override_content_type(mut self, content_type: &str) -> Self {
628        self.override_content_type = Some(content_type.into());
629        self
630    }
631
632    /// Returns the content-type header that should be sent back by the remote read operation.
633    pub fn override_content_type(&self) -> Option<&str> {
634        self.override_content_type.as_deref()
635    }
636
637    /// Set the version of the option
638    pub fn with_version(mut self, version: &str) -> Self {
639        self.version = Some(version.to_string());
640        self
641    }
642
643    /// Get version from option
644    pub fn version(&self) -> Option<&str> {
645        self.version.as_deref()
646    }
647}
648
649impl From<options::StatOptions> for OpStat {
650    fn from(value: options::StatOptions) -> Self {
651        Self {
652            if_match: value.if_match,
653            if_none_match: value.if_none_match,
654            if_modified_since: value.if_modified_since,
655            if_unmodified_since: value.if_unmodified_since,
656            override_content_type: value.override_content_type,
657            override_cache_control: value.override_cache_control,
658            override_content_disposition: value.override_content_disposition,
659            version: value.version,
660        }
661    }
662}
663
664/// Args for `write` operation.
665#[derive(Debug, Clone, Default)]
666pub struct OpWrite {
667    append: bool,
668    concurrent: usize,
669    content_type: Option<String>,
670    content_disposition: Option<String>,
671    content_encoding: Option<String>,
672    cache_control: Option<String>,
673    if_match: Option<String>,
674    if_none_match: Option<String>,
675    if_not_exists: bool,
676    user_metadata: Option<HashMap<String, String>>,
677}
678
679impl OpWrite {
680    /// Create a new `OpWrite`.
681    ///
682    /// If input path is not a file path, an error will be returned.
683    pub fn new() -> Self {
684        Self::default()
685    }
686
687    /// Get the append from op.
688    ///
689    /// The append is the flag to indicate that this write operation is an append operation.
690    pub fn append(&self) -> bool {
691        self.append
692    }
693
694    /// Set the append mode of op.
695    ///
696    /// If the append mode is set, the data will be appended to the end of the file.
697    ///
698    /// # Notes
699    ///
700    /// Service could return `Unsupported` if the underlying storage does not support append.
701    pub fn with_append(mut self, append: bool) -> Self {
702        self.append = append;
703        self
704    }
705
706    /// Get the content type from option
707    pub fn content_type(&self) -> Option<&str> {
708        self.content_type.as_deref()
709    }
710
711    /// Set the content type of option
712    pub fn with_content_type(mut self, content_type: &str) -> Self {
713        self.content_type = Some(content_type.to_string());
714        self
715    }
716
717    /// Get the content disposition from option
718    pub fn content_disposition(&self) -> Option<&str> {
719        self.content_disposition.as_deref()
720    }
721
722    /// Set the content disposition of option
723    pub fn with_content_disposition(mut self, content_disposition: &str) -> Self {
724        self.content_disposition = Some(content_disposition.to_string());
725        self
726    }
727
728    /// Get the content encoding from option
729    pub fn content_encoding(&self) -> Option<&str> {
730        self.content_encoding.as_deref()
731    }
732
733    /// Set the content encoding of option
734    pub fn with_content_encoding(mut self, content_encoding: &str) -> Self {
735        self.content_encoding = Some(content_encoding.to_string());
736        self
737    }
738
739    /// Get the cache control from option
740    pub fn cache_control(&self) -> Option<&str> {
741        self.cache_control.as_deref()
742    }
743
744    /// Set the content type of option
745    pub fn with_cache_control(mut self, cache_control: &str) -> Self {
746        self.cache_control = Some(cache_control.to_string());
747        self
748    }
749
750    /// Get the concurrent.
751    pub fn concurrent(&self) -> usize {
752        self.concurrent
753    }
754
755    /// Set the maximum concurrent write task amount.
756    pub fn with_concurrent(mut self, concurrent: usize) -> Self {
757        self.concurrent = concurrent;
758        self
759    }
760
761    /// Set the If-Match of the option
762    pub fn with_if_match(mut self, s: &str) -> Self {
763        self.if_match = Some(s.to_string());
764        self
765    }
766
767    /// Get If-Match from option
768    pub fn if_match(&self) -> Option<&str> {
769        self.if_match.as_deref()
770    }
771
772    /// Set the If-None-Match of the option
773    pub fn with_if_none_match(mut self, s: &str) -> Self {
774        self.if_none_match = Some(s.to_string());
775        self
776    }
777
778    /// Get If-None-Match from option
779    pub fn if_none_match(&self) -> Option<&str> {
780        self.if_none_match.as_deref()
781    }
782
783    /// Set the If-Not-Exist of the option
784    pub fn with_if_not_exists(mut self, b: bool) -> Self {
785        self.if_not_exists = b;
786        self
787    }
788
789    /// Get If-Not-Exist from option
790    pub fn if_not_exists(&self) -> bool {
791        self.if_not_exists
792    }
793
794    /// Set the user defined metadata of the op
795    pub fn with_user_metadata(mut self, metadata: HashMap<String, String>) -> Self {
796        self.user_metadata = Some(metadata);
797        self
798    }
799
800    /// Get the user defined metadata from the op
801    pub fn user_metadata(&self) -> Option<&HashMap<String, String>> {
802        self.user_metadata.as_ref()
803    }
804}
805
806/// Args for `writer` operation.
807#[derive(Debug, Clone, Default)]
808pub struct OpWriter {
809    chunk: Option<usize>,
810}
811
812impl OpWriter {
813    /// Create a new `OpWriter`.
814    pub fn new() -> Self {
815        Self::default()
816    }
817
818    /// Get the chunk from op.
819    ///
820    /// The chunk is used by service to decide the chunk size of the underlying writer.
821    pub fn chunk(&self) -> Option<usize> {
822        self.chunk
823    }
824
825    /// Set the chunk of op.
826    ///
827    /// If chunk is set, the data will be chunked by the underlying writer.
828    ///
829    /// ## NOTE
830    ///
831    /// Service could have their own minimum chunk size while perform write
832    /// operations like multipart uploads. So the chunk size may be larger than
833    /// the given buffer size.
834    pub fn with_chunk(mut self, chunk: usize) -> Self {
835        self.chunk = Some(chunk);
836        self
837    }
838}
839
840impl From<options::WriteOptions> for (OpWrite, OpWriter) {
841    fn from(value: options::WriteOptions) -> Self {
842        (
843            OpWrite {
844                append: value.append,
845                // Ensure concurrent is at least 1
846                concurrent: value.concurrent.max(1),
847                content_type: value.content_type,
848                content_disposition: value.content_disposition,
849                content_encoding: value.content_encoding,
850                cache_control: value.cache_control,
851                if_match: value.if_match,
852                if_none_match: value.if_none_match,
853                if_not_exists: value.if_not_exists,
854                user_metadata: value.user_metadata,
855            },
856            OpWriter { chunk: value.chunk },
857        )
858    }
859}
860
861/// Args for `copy` operation.
862#[derive(Debug, Clone, Default)]
863pub struct OpCopy {}
864
865impl OpCopy {
866    /// Create a new `OpCopy`.
867    pub fn new() -> Self {
868        Self::default()
869    }
870}
871
872/// Args for `rename` operation.
873#[derive(Debug, Clone, Default)]
874pub struct OpRename {}
875
876impl OpRename {
877    /// Create a new `OpMove`.
878    pub fn new() -> Self {
879        Self::default()
880    }
881}