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