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;
23use crate::raw::*;
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    pub fn with_versions(mut self, versions: bool) -> Self {
186        self.versions = versions;
187        self
188    }
189
190    /// Get the version of this list operation
191    pub fn versions(&self) -> bool {
192        self.versions
193    }
194
195    /// Change the deleted of this list operation
196    pub fn with_deleted(mut self, deleted: bool) -> Self {
197        self.deleted = deleted;
198        self
199    }
200
201    /// Get the deleted of this list operation
202    pub fn deleted(&self) -> bool {
203        self.deleted
204    }
205}
206
207impl From<options::ListOptions> for OpList {
208    fn from(value: options::ListOptions) -> Self {
209        Self {
210            limit: value.limit,
211            start_after: value.start_after,
212            recursive: value.recursive,
213            versions: value.versions,
214            deleted: value.deleted,
215        }
216    }
217}
218
219/// Args for `presign` operation.
220///
221/// The path must be normalized.
222#[derive(Debug, Clone)]
223pub struct OpPresign {
224    expire: Duration,
225
226    op: PresignOperation,
227}
228
229impl OpPresign {
230    /// Create a new `OpPresign`.
231    pub fn new(op: impl Into<PresignOperation>, expire: Duration) -> Self {
232        Self {
233            op: op.into(),
234            expire,
235        }
236    }
237
238    /// Get operation from op.
239    pub fn operation(&self) -> &PresignOperation {
240        &self.op
241    }
242
243    /// Get expire from op.
244    pub fn expire(&self) -> Duration {
245        self.expire
246    }
247
248    /// Consume OpPresign into (Duration, PresignOperation)
249    pub fn into_parts(self) -> (Duration, PresignOperation) {
250        (self.expire, self.op)
251    }
252}
253
254/// Presign operation used for presign.
255#[derive(Debug, Clone)]
256#[non_exhaustive]
257pub enum PresignOperation {
258    /// Presign a stat(head) operation.
259    Stat(OpStat),
260    /// Presign a read operation.
261    Read(OpRead),
262    /// Presign a write operation.
263    Write(OpWrite),
264    /// Presign a delete operation.
265    Delete(OpDelete),
266}
267
268impl From<OpStat> for PresignOperation {
269    fn from(op: OpStat) -> Self {
270        Self::Stat(op)
271    }
272}
273
274impl From<OpRead> for PresignOperation {
275    fn from(v: OpRead) -> Self {
276        Self::Read(v)
277    }
278}
279
280impl From<OpWrite> for PresignOperation {
281    fn from(v: OpWrite) -> Self {
282        Self::Write(v)
283    }
284}
285
286impl From<OpDelete> for PresignOperation {
287    fn from(v: OpDelete) -> Self {
288        Self::Delete(v)
289    }
290}
291
292/// Args for `read` operation.
293#[derive(Debug, Clone, Default)]
294pub struct OpRead {
295    range: BytesRange,
296    if_match: Option<String>,
297    if_none_match: Option<String>,
298    if_modified_since: Option<Timestamp>,
299    if_unmodified_since: Option<Timestamp>,
300    override_content_type: Option<String>,
301    override_cache_control: Option<String>,
302    override_content_disposition: Option<String>,
303    version: Option<String>,
304}
305
306impl OpRead {
307    /// Create a default `OpRead` which will read whole content of path.
308    pub fn new() -> Self {
309        Self::default()
310    }
311
312    /// Set the range of the option
313    pub fn with_range(mut self, range: BytesRange) -> Self {
314        self.range = range;
315        self
316    }
317
318    /// Get range from option
319    pub fn range(&self) -> BytesRange {
320        self.range
321    }
322
323    /// Returns a mutable range to allow updating.
324    pub(crate) fn range_mut(&mut self) -> &mut BytesRange {
325        &mut self.range
326    }
327
328    /// Sets the content-disposition header that should be sent back by the remote read operation.
329    pub fn with_override_content_disposition(mut self, content_disposition: &str) -> Self {
330        self.override_content_disposition = Some(content_disposition.into());
331        self
332    }
333
334    /// Returns the content-disposition header that should be sent back by the remote read
335    /// operation.
336    pub fn override_content_disposition(&self) -> Option<&str> {
337        self.override_content_disposition.as_deref()
338    }
339
340    /// Sets the cache-control header that should be sent back by the remote read operation.
341    pub fn with_override_cache_control(mut self, cache_control: &str) -> Self {
342        self.override_cache_control = Some(cache_control.into());
343        self
344    }
345
346    /// Returns the cache-control header that should be sent back by the remote read operation.
347    pub fn override_cache_control(&self) -> Option<&str> {
348        self.override_cache_control.as_deref()
349    }
350
351    /// Sets the content-type header that should be sent back by the remote read operation.
352    pub fn with_override_content_type(mut self, content_type: &str) -> Self {
353        self.override_content_type = Some(content_type.into());
354        self
355    }
356
357    /// Returns the content-type header that should be sent back by the remote read operation.
358    pub fn override_content_type(&self) -> Option<&str> {
359        self.override_content_type.as_deref()
360    }
361
362    /// Set the If-Match of the option
363    pub fn with_if_match(mut self, if_match: &str) -> Self {
364        self.if_match = Some(if_match.to_string());
365        self
366    }
367
368    /// Get If-Match from option
369    pub fn if_match(&self) -> Option<&str> {
370        self.if_match.as_deref()
371    }
372
373    /// Set the If-None-Match of the option
374    pub fn with_if_none_match(mut self, if_none_match: &str) -> Self {
375        self.if_none_match = Some(if_none_match.to_string());
376        self
377    }
378
379    /// Get If-None-Match from option
380    pub fn if_none_match(&self) -> Option<&str> {
381        self.if_none_match.as_deref()
382    }
383
384    /// Set the If-Modified-Since of the option
385    pub fn with_if_modified_since(mut self, v: Timestamp) -> Self {
386        self.if_modified_since = Some(v);
387        self
388    }
389
390    /// Get If-Modified-Since from option
391    pub fn if_modified_since(&self) -> Option<Timestamp> {
392        self.if_modified_since
393    }
394
395    /// Set the If-Unmodified-Since of the option
396    pub fn with_if_unmodified_since(mut self, v: Timestamp) -> Self {
397        self.if_unmodified_since = Some(v);
398        self
399    }
400
401    /// Get If-Unmodified-Since from option
402    pub fn if_unmodified_since(&self) -> Option<Timestamp> {
403        self.if_unmodified_since
404    }
405
406    /// Set the version of the option
407    pub fn with_version(mut self, version: &str) -> Self {
408        self.version = Some(version.to_string());
409        self
410    }
411
412    /// Get version from option
413    pub fn version(&self) -> Option<&str> {
414        self.version.as_deref()
415    }
416}
417
418/// Args for reader operation.
419#[derive(Debug, Clone)]
420pub struct OpReader {
421    /// The concurrent requests that reader can send.
422    concurrent: usize,
423    /// The chunk size of each request.
424    chunk: Option<usize>,
425    /// The gap size of each request.
426    gap: Option<usize>,
427    /// The maximum number of buffers that can be prefetched.
428    prefetch: usize,
429}
430
431impl Default for OpReader {
432    fn default() -> Self {
433        Self {
434            concurrent: 1,
435            chunk: None,
436            gap: None,
437            prefetch: 0,
438        }
439    }
440}
441
442impl OpReader {
443    /// Create a new `OpReader`.
444    pub fn new() -> Self {
445        Self::default()
446    }
447
448    /// Set the concurrent of the option
449    pub fn with_concurrent(mut self, concurrent: usize) -> Self {
450        self.concurrent = concurrent.max(1);
451        self
452    }
453
454    /// Get concurrent from option
455    pub fn concurrent(&self) -> usize {
456        self.concurrent
457    }
458
459    /// Set the chunk of the option
460    pub fn with_chunk(mut self, chunk: usize) -> Self {
461        self.chunk = Some(chunk.max(1));
462        self
463    }
464
465    /// Get chunk from option
466    pub fn chunk(&self) -> Option<usize> {
467        self.chunk
468    }
469
470    /// Set the gap of the option
471    pub fn with_gap(mut self, gap: usize) -> Self {
472        self.gap = Some(gap.max(1));
473        self
474    }
475
476    /// Get gap from option
477    pub fn gap(&self) -> Option<usize> {
478        self.gap
479    }
480
481    /// Set the prefetch of the option
482    pub fn with_prefetch(mut self, prefetch: usize) -> Self {
483        self.prefetch = prefetch;
484        self
485    }
486
487    /// Get prefetch from option
488    pub fn prefetch(&self) -> usize {
489        self.prefetch
490    }
491}
492
493impl From<options::ReadOptions> for (OpRead, OpReader) {
494    fn from(value: options::ReadOptions) -> Self {
495        (
496            OpRead {
497                range: value.range,
498                if_match: value.if_match,
499                if_none_match: value.if_none_match,
500                if_modified_since: value.if_modified_since,
501                if_unmodified_since: value.if_unmodified_since,
502                override_content_type: value.override_content_type,
503                override_cache_control: value.override_cache_control,
504                override_content_disposition: value.override_content_disposition,
505                version: value.version,
506            },
507            OpReader {
508                // Ensure concurrent is at least 1
509                concurrent: value.concurrent.max(1),
510                chunk: value.chunk,
511                gap: value.gap,
512                prefetch: 0,
513            },
514        )
515    }
516}
517
518impl From<options::ReaderOptions> for (OpRead, OpReader) {
519    fn from(value: options::ReaderOptions) -> Self {
520        (
521            OpRead {
522                range: BytesRange::default(),
523                if_match: value.if_match,
524                if_none_match: value.if_none_match,
525                if_modified_since: value.if_modified_since,
526                if_unmodified_since: value.if_unmodified_since,
527                override_content_type: None,
528                override_cache_control: None,
529                override_content_disposition: None,
530                version: value.version,
531            },
532            OpReader {
533                // Ensure concurrent is at least 1
534                concurrent: value.concurrent.max(1),
535                chunk: value.chunk,
536                gap: value.gap,
537                prefetch: value.prefetch,
538            },
539        )
540    }
541}
542
543/// Args for `stat` operation.
544#[derive(Debug, Clone, Default)]
545pub struct OpStat {
546    if_match: Option<String>,
547    if_none_match: Option<String>,
548    if_modified_since: Option<Timestamp>,
549    if_unmodified_since: Option<Timestamp>,
550    override_content_type: Option<String>,
551    override_cache_control: Option<String>,
552    override_content_disposition: Option<String>,
553    version: Option<String>,
554}
555
556impl OpStat {
557    /// Create a new `OpStat`.
558    pub fn new() -> Self {
559        Self::default()
560    }
561
562    /// Set the If-Match of the option
563    pub fn with_if_match(mut self, if_match: &str) -> Self {
564        self.if_match = Some(if_match.to_string());
565        self
566    }
567
568    /// Get If-Match from option
569    pub fn if_match(&self) -> Option<&str> {
570        self.if_match.as_deref()
571    }
572
573    /// Set the If-None-Match of the option
574    pub fn with_if_none_match(mut self, if_none_match: &str) -> Self {
575        self.if_none_match = Some(if_none_match.to_string());
576        self
577    }
578
579    /// Get If-None-Match from option
580    pub fn if_none_match(&self) -> Option<&str> {
581        self.if_none_match.as_deref()
582    }
583
584    /// Set the If-Modified-Since of the option
585    pub fn with_if_modified_since(mut self, v: Timestamp) -> Self {
586        self.if_modified_since = Some(v);
587        self
588    }
589
590    /// Get If-Modified-Since from option
591    pub fn if_modified_since(&self) -> Option<Timestamp> {
592        self.if_modified_since
593    }
594
595    /// Set the If-Unmodified-Since of the option
596    pub fn with_if_unmodified_since(mut self, v: Timestamp) -> Self {
597        self.if_unmodified_since = Some(v);
598        self
599    }
600
601    /// Get If-Unmodified-Since from option
602    pub fn if_unmodified_since(&self) -> Option<Timestamp> {
603        self.if_unmodified_since
604    }
605
606    /// Sets the content-disposition header that should be sent back by the remote read operation.
607    pub fn with_override_content_disposition(mut self, content_disposition: &str) -> Self {
608        self.override_content_disposition = Some(content_disposition.into());
609        self
610    }
611
612    /// Returns the content-disposition header that should be sent back by the remote read
613    /// operation.
614    pub fn override_content_disposition(&self) -> Option<&str> {
615        self.override_content_disposition.as_deref()
616    }
617
618    /// Sets the cache-control header that should be sent back by the remote read operation.
619    pub fn with_override_cache_control(mut self, cache_control: &str) -> Self {
620        self.override_cache_control = Some(cache_control.into());
621        self
622    }
623
624    /// Returns the cache-control header that should be sent back by the remote read operation.
625    pub fn override_cache_control(&self) -> Option<&str> {
626        self.override_cache_control.as_deref()
627    }
628
629    /// Sets the content-type header that should be sent back by the remote read operation.
630    pub fn with_override_content_type(mut self, content_type: &str) -> Self {
631        self.override_content_type = Some(content_type.into());
632        self
633    }
634
635    /// Returns the content-type header that should be sent back by the remote read operation.
636    pub fn override_content_type(&self) -> Option<&str> {
637        self.override_content_type.as_deref()
638    }
639
640    /// Set the version of the option
641    pub fn with_version(mut self, version: &str) -> Self {
642        self.version = Some(version.to_string());
643        self
644    }
645
646    /// Get version from option
647    pub fn version(&self) -> Option<&str> {
648        self.version.as_deref()
649    }
650}
651
652impl From<options::StatOptions> for OpStat {
653    fn from(value: options::StatOptions) -> Self {
654        Self {
655            if_match: value.if_match,
656            if_none_match: value.if_none_match,
657            if_modified_since: value.if_modified_since,
658            if_unmodified_since: value.if_unmodified_since,
659            override_content_type: value.override_content_type,
660            override_cache_control: value.override_cache_control,
661            override_content_disposition: value.override_content_disposition,
662            version: value.version,
663        }
664    }
665}
666
667/// Args for `write` operation.
668#[derive(Debug, Clone, Default)]
669pub struct OpWrite {
670    append: bool,
671    concurrent: usize,
672    content_type: Option<String>,
673    content_disposition: Option<String>,
674    content_encoding: Option<String>,
675    cache_control: Option<String>,
676    if_match: Option<String>,
677    if_none_match: Option<String>,
678    if_not_exists: bool,
679    user_metadata: Option<HashMap<String, String>>,
680}
681
682impl OpWrite {
683    /// Create a new `OpWrite`.
684    ///
685    /// If input path is not a file path, an error will be returned.
686    pub fn new() -> Self {
687        Self::default()
688    }
689
690    /// Get the append from op.
691    ///
692    /// The append is the flag to indicate that this write operation is an append operation.
693    pub fn append(&self) -> bool {
694        self.append
695    }
696
697    /// Set the append mode of op.
698    ///
699    /// If the append mode is set, the data will be appended to the end of the file.
700    ///
701    /// # Notes
702    ///
703    /// Service could return `Unsupported` if the underlying storage does not support append.
704    pub fn with_append(mut self, append: bool) -> Self {
705        self.append = append;
706        self
707    }
708
709    /// Get the content type from option
710    pub fn content_type(&self) -> Option<&str> {
711        self.content_type.as_deref()
712    }
713
714    /// Set the content type of option
715    pub fn with_content_type(mut self, content_type: &str) -> Self {
716        self.content_type = Some(content_type.to_string());
717        self
718    }
719
720    /// Get the content disposition from option
721    pub fn content_disposition(&self) -> Option<&str> {
722        self.content_disposition.as_deref()
723    }
724
725    /// Set the content disposition of option
726    pub fn with_content_disposition(mut self, content_disposition: &str) -> Self {
727        self.content_disposition = Some(content_disposition.to_string());
728        self
729    }
730
731    /// Get the content encoding from option
732    pub fn content_encoding(&self) -> Option<&str> {
733        self.content_encoding.as_deref()
734    }
735
736    /// Set the content encoding of option
737    pub fn with_content_encoding(mut self, content_encoding: &str) -> Self {
738        self.content_encoding = Some(content_encoding.to_string());
739        self
740    }
741
742    /// Get the cache control from option
743    pub fn cache_control(&self) -> Option<&str> {
744        self.cache_control.as_deref()
745    }
746
747    /// Set the content type of option
748    pub fn with_cache_control(mut self, cache_control: &str) -> Self {
749        self.cache_control = Some(cache_control.to_string());
750        self
751    }
752
753    /// Get the concurrent.
754    pub fn concurrent(&self) -> usize {
755        self.concurrent
756    }
757
758    /// Set the maximum concurrent write task amount.
759    pub fn with_concurrent(mut self, concurrent: usize) -> Self {
760        self.concurrent = concurrent;
761        self
762    }
763
764    /// Set the If-Match of the option
765    pub fn with_if_match(mut self, s: &str) -> Self {
766        self.if_match = Some(s.to_string());
767        self
768    }
769
770    /// Get If-Match from option
771    pub fn if_match(&self) -> Option<&str> {
772        self.if_match.as_deref()
773    }
774
775    /// Set the If-None-Match of the option
776    pub fn with_if_none_match(mut self, s: &str) -> Self {
777        self.if_none_match = Some(s.to_string());
778        self
779    }
780
781    /// Get If-None-Match from option
782    pub fn if_none_match(&self) -> Option<&str> {
783        self.if_none_match.as_deref()
784    }
785
786    /// Set the If-Not-Exist of the option
787    pub fn with_if_not_exists(mut self, b: bool) -> Self {
788        self.if_not_exists = b;
789        self
790    }
791
792    /// Get If-Not-Exist from option
793    pub fn if_not_exists(&self) -> bool {
794        self.if_not_exists
795    }
796
797    /// Set the user defined metadata of the op
798    pub fn with_user_metadata(mut self, metadata: HashMap<String, String>) -> Self {
799        self.user_metadata = Some(metadata);
800        self
801    }
802
803    /// Get the user defined metadata from the op
804    pub fn user_metadata(&self) -> Option<&HashMap<String, String>> {
805        self.user_metadata.as_ref()
806    }
807}
808
809/// Args for `writer` operation.
810#[derive(Debug, Clone, Default)]
811pub struct OpWriter {
812    chunk: Option<usize>,
813}
814
815impl OpWriter {
816    /// Create a new `OpWriter`.
817    pub fn new() -> Self {
818        Self::default()
819    }
820
821    /// Get the chunk from op.
822    ///
823    /// The chunk is used by service to decide the chunk size of the underlying writer.
824    pub fn chunk(&self) -> Option<usize> {
825        self.chunk
826    }
827
828    /// Set the chunk of op.
829    ///
830    /// If chunk is set, the data will be chunked by the underlying writer.
831    ///
832    /// ## NOTE
833    ///
834    /// Service could have their own minimum chunk size while perform write
835    /// operations like multipart uploads. So the chunk size may be larger than
836    /// the given buffer size.
837    pub fn with_chunk(mut self, chunk: usize) -> Self {
838        self.chunk = Some(chunk);
839        self
840    }
841}
842
843impl From<options::WriteOptions> for (OpWrite, OpWriter) {
844    fn from(value: options::WriteOptions) -> Self {
845        (
846            OpWrite {
847                append: value.append,
848                // Ensure concurrent is at least 1
849                concurrent: value.concurrent.max(1),
850                content_type: value.content_type,
851                content_disposition: value.content_disposition,
852                content_encoding: value.content_encoding,
853                cache_control: value.cache_control,
854                if_match: value.if_match,
855                if_none_match: value.if_none_match,
856                if_not_exists: value.if_not_exists,
857                user_metadata: value.user_metadata,
858            },
859            OpWriter { chunk: value.chunk },
860        )
861    }
862}
863
864/// Args for `copy` operation.
865#[derive(Debug, Clone, Default)]
866pub struct OpCopy {
867    if_not_exists: bool,
868}
869
870impl OpCopy {
871    /// Create a new `OpCopy`.
872    pub fn new() -> Self {
873        Self::default()
874    }
875
876    /// Set the if_not_exists flag for the operation.
877    ///
878    /// When set to true, the copy operation will only proceed if the destination
879    /// doesn't already exist.
880    pub fn with_if_not_exists(mut self, if_not_exists: bool) -> Self {
881        self.if_not_exists = if_not_exists;
882        self
883    }
884
885    /// Get if_not_exists flag.
886    pub fn if_not_exists(&self) -> bool {
887        self.if_not_exists
888    }
889}
890
891/// Args for `rename` operation.
892#[derive(Debug, Clone, Default)]
893pub struct OpRename {}
894
895impl OpRename {
896    /// Create a new `OpMove`.
897    pub fn new() -> Self {
898        Self::default()
899    }
900}