qiniu_objects_manager/
bucket.rs

1use super::{
2    batch_operations::BatchOperations,
3    callbacks::Callbacks,
4    list::{ListIter, ListVersion},
5    mime::Mime,
6    operation::{
7        CopyObject, CopyObjectBuilder, DeleteObject, DeleteObjectBuilder, Entry, ModifyObjectLifeCycle,
8        ModifyObjectLifeCycleBuilder, ModifyObjectMetadata, ModifyObjectMetadataBuilder, ModifyObjectStatus,
9        ModifyObjectStatusBuilder, MoveObject, MoveObjectBuilder, SetObjectType, SetObjectTypeBuilder, StatObject,
10        StatObjectBuilder, UnfreezeObject, UnfreezeObjectBuilder,
11    },
12    ObjectsManager,
13};
14use anyhow::Result as AnyResult;
15use assert_impl::assert_impl;
16use once_cell::sync::OnceCell;
17use qiniu_apis::{
18    http::ResponseParts,
19    http_client::{BucketName, BucketRegionsProvider, RegionsProvider, RequestBuilderParts, ResponseError},
20    upload_token::FileType,
21};
22use std::{borrow::Cow, io::Result as IOResult, mem::take, sync::Arc};
23
24#[cfg(feature = "async")]
25use {super::list::ListStream, async_once_cell::OnceCell as AsyncOnceCell};
26
27/// 七牛存储空间管理器
28#[derive(Debug, Clone)]
29pub struct Bucket(Arc<BucketInner>);
30
31#[derive(Debug)]
32struct BucketInner {
33    name: BucketName,
34    objects_manager: ObjectsManager,
35    region_provider: Option<Box<dyn RegionsProvider>>,
36    bucket_regions_provider: OnceCell<BucketRegionsProvider>,
37
38    #[cfg(feature = "async")]
39    async_bucket_regions_provider: AsyncOnceCell<BucketRegionsProvider>,
40}
41
42impl Bucket {
43    pub(super) fn new(
44        name: BucketName,
45        objects_manager: ObjectsManager,
46        region_provider: Option<Box<dyn RegionsProvider>>,
47    ) -> Self {
48        Self(Arc::new(BucketInner {
49            name,
50            objects_manager,
51            region_provider,
52            bucket_regions_provider: Default::default(),
53
54            #[cfg(feature = "async")]
55            async_bucket_regions_provider: AsyncOnceCell::new(),
56        }))
57    }
58
59    /// 获取存储空间名称
60    #[inline]
61    pub fn name(&self) -> &BucketName {
62        &self.0.name
63    }
64
65    /// 获取对象管理器
66    #[inline]
67    pub fn objects_manager(&self) -> &ObjectsManager {
68        &self.0.objects_manager
69    }
70
71    /// 创建列举操作构建器
72    ///
73    /// ##### 阻塞代码示例
74    ///
75    /// ```
76    /// use qiniu_objects_manager::{apis::credential::Credential, ObjectsManager};
77    /// use futures::stream::TryStreamExt;
78    ///
79    /// # fn example() -> anyhow::Result<()> {
80    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
81    /// let object_manager = ObjectsManager::new(credential);
82    /// let bucket = object_manager.bucket("test-bucket");
83    /// let mut iter = bucket.list().iter();
84    /// while let Some(object) = iter.next() {
85    ///     let object = object?;
86    ///     println!("fsize: {:?}", object.get_size_as_u64());
87    ///     println!("hash: {:?}", object.get_hash_as_str());
88    ///     println!("mime_type: {:?}", object.get_mime_type_as_str());
89    /// }
90    /// # Ok(())
91    /// # }
92    /// ```
93    ///
94    /// ##### 异步代码示例
95    ///
96    /// ```
97    /// use qiniu_objects_manager::{apis::credential::Credential, ObjectsManager};
98    /// use futures::stream::TryStreamExt;
99    ///
100    /// # async fn example() -> anyhow::Result<()> {
101    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
102    /// let object_manager = ObjectsManager::new(credential);
103    /// let bucket = object_manager.bucket("test-bucket");
104    /// let mut stream = bucket.list().stream();
105    /// while let Some(object) = stream.try_next().await? {
106    ///     println!("fsize: {:?}", object.get_size_as_u64());
107    ///     println!("hash: {:?}", object.get_hash_as_str());
108    ///     println!("mime_type: {:?}", object.get_mime_type_as_str());
109    /// }
110    /// # Ok(())
111    /// # }
112    /// ```
113    #[inline]
114    pub fn list(&self) -> ListBuilder<'_> {
115        ListBuilder::new(self)
116    }
117
118    /// 创建对象元信息获取操作构建器
119    ///
120    /// ##### 阻塞代码示例
121    ///
122    /// ```
123    /// use qiniu_objects_manager::{apis::credential::Credential, ObjectsManager};
124    ///
125    /// # fn example() -> anyhow::Result<()> {
126    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
127    /// let object_manager = ObjectsManager::new(credential);
128    /// let bucket = object_manager.bucket("test-bucket");
129    ///
130    /// let response = bucket.stat_object("test-key").call()?;
131    /// let object = response.into_body();
132    /// println!("fsize: {}", object.get_size_as_u64());
133    /// println!("hash: {}", object.get_hash_as_str());
134    /// println!("mime_type: {}", object.get_mime_type_as_str());
135    /// # Ok(())
136    /// # }
137    /// ```
138    ///
139    /// ##### 异步代码示例
140    ///
141    /// ```
142    /// use qiniu_objects_manager::{apis::credential::Credential, ObjectsManager};
143    ///
144    /// # async fn example() -> anyhow::Result<()> {
145    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
146    /// let object_manager = ObjectsManager::new(credential);
147    /// let bucket = object_manager.bucket("test-bucket");
148    ///
149    /// let response = bucket.stat_object("test-key").async_call().await?;
150    /// let object = response.into_body();
151    /// println!("fsize: {}", object.get_size_as_u64());
152    /// println!("hash: {}", object.get_hash_as_str());
153    /// println!("mime_type: {}", object.get_mime_type_as_str());
154    /// # Ok(())
155    /// # }
156    /// ```
157    #[inline]
158    pub fn stat_object<'a>(&'a self, object_name: &'a str) -> StatObjectBuilder<'a> {
159        StatObject::builder(Entry::new(self, object_name))
160    }
161
162    /// 创建对象复制操作构建器
163    ///
164    /// ##### 阻塞代码示例
165    ///
166    /// ```
167    /// use qiniu_objects_manager::{apis::credential::Credential, ObjectsManager};
168    ///
169    /// # fn example() -> anyhow::Result<()> {
170    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
171    /// let object_manager = ObjectsManager::new(credential);
172    /// let bucket = object_manager.bucket("test-bucket");
173    ///
174    /// bucket.copy_object_to("test-key", "test-bucket-2", "test-key").call()?;
175    /// # Ok(())
176    /// # }
177    /// ```
178    ///
179    /// ##### 异步代码示例
180    ///
181    /// ```
182    /// use qiniu_objects_manager::{apis::credential::Credential, ObjectsManager};
183    ///
184    /// # async fn example() -> anyhow::Result<()> {
185    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
186    /// let object_manager = ObjectsManager::new(credential);
187    /// let bucket = object_manager.bucket("test-bucket");
188    ///
189    /// bucket.copy_object_to("test-key", "test-bucket-2", "test-key").async_call().await?;
190    /// # Ok(())
191    /// # }
192    /// ```
193    #[inline]
194    pub fn copy_object_to<'a>(
195        &'a self,
196        from_object_name: &'a str,
197        to_bucket_name: &'a str,
198        to_object_name: &'a str,
199    ) -> CopyObjectBuilder<'a> {
200        CopyObject::builder(Entry::new(self, from_object_name), to_bucket_name, to_object_name)
201    }
202
203    /// 创建对象移动操作构建器
204    ///
205    /// ##### 阻塞代码示例
206    ///
207    /// ```
208    /// use qiniu_objects_manager::{apis::credential::Credential, ObjectsManager};
209    ///
210    /// # fn example() -> anyhow::Result<()> {
211    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
212    /// let object_manager = ObjectsManager::new(credential);
213    /// let bucket = object_manager.bucket("test-bucket");
214    ///
215    /// bucket.move_object_to("test-key", "test-bucket-2", "test-key").call()?;
216    /// # Ok(())
217    /// # }
218    /// ```
219    ///
220    /// ##### 异步代码示例
221    ///
222    /// ```
223    /// use qiniu_objects_manager::{apis::credential::Credential, ObjectsManager};
224    ///
225    /// # async fn example() -> anyhow::Result<()> {
226    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
227    /// let object_manager = ObjectsManager::new(credential);
228    /// let bucket = object_manager.bucket("test-bucket");
229    ///
230    /// bucket.move_object_to("test-key", "test-bucket-2", "test-key").async_call().await?;
231    /// # Ok(())
232    /// # }
233    /// ```
234    #[inline]
235    pub fn move_object_to<'a>(
236        &'a self,
237        from_object_name: &'a str,
238        to_bucket_name: &'a str,
239        to_object_name: &'a str,
240    ) -> MoveObjectBuilder<'a> {
241        MoveObject::builder(Entry::new(self, from_object_name), to_bucket_name, to_object_name)
242    }
243
244    /// 创建对象删除操作构建器
245    ///
246    /// ##### 阻塞代码示例
247    ///
248    /// ```
249    /// use qiniu_objects_manager::{apis::credential::Credential, ObjectsManager};
250    ///
251    /// # fn example() -> anyhow::Result<()> {
252    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
253    /// let object_manager = ObjectsManager::new(credential);
254    /// let bucket = object_manager.bucket("test-bucket");
255    ///
256    /// bucket.delete_object("test-key").call()?;
257    /// # Ok(())
258    /// # }
259    /// ```
260    ///
261    /// ##### 异步代码示例
262    ///
263    /// ```
264    /// use qiniu_objects_manager::{apis::credential::Credential, ObjectsManager};
265    ///
266    /// # async fn example() -> anyhow::Result<()> {
267    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
268    /// let object_manager = ObjectsManager::new(credential);
269    /// let bucket = object_manager.bucket("test-bucket");
270    ///
271    /// bucket.delete_object("test-key").async_call().await?;
272    /// # Ok(())
273    /// # }
274    /// ```
275    #[inline]
276    pub fn delete_object<'a>(&'a self, object_name: &'a str) -> DeleteObjectBuilder<'a> {
277        DeleteObject::builder(Entry::new(self, object_name))
278    }
279
280    /// 创建对象解冻操作构建器
281    ///
282    /// ##### 阻塞代码示例
283    ///
284    /// ```
285    /// use qiniu_objects_manager::{apis::credential::Credential, ObjectsManager};
286    ///
287    /// # fn example() -> anyhow::Result<()> {
288    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
289    /// let object_manager = ObjectsManager::new(credential);
290    /// let bucket = object_manager.bucket("test-bucket");
291    ///
292    /// bucket.restore_archived_object("test-key", 1).call()?;
293    /// # Ok(())
294    /// # }
295    /// ```
296    ///
297    /// ##### 异步代码示例
298    ///
299    /// ```
300    /// use qiniu_objects_manager::{apis::credential::Credential, ObjectsManager};
301    ///
302    /// # async fn example() -> anyhow::Result<()> {
303    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
304    /// let object_manager = ObjectsManager::new(credential);
305    /// let bucket = object_manager.bucket("test-bucket");
306    ///
307    /// bucket.restore_archived_object("test-key", 1).async_call().await?;
308    /// # Ok(())
309    /// # }
310    /// ```
311    #[inline]
312    pub fn restore_archived_object<'a>(
313        &'a self,
314        object_name: &'a str,
315        freeze_after_days: usize,
316    ) -> UnfreezeObjectBuilder<'a> {
317        UnfreezeObject::builder(Entry::new(self, object_name), freeze_after_days)
318    }
319
320    /// 创建对象类型设置操作构建器
321    ///
322    /// ##### 阻塞代码示例
323    ///
324    /// ```
325    /// use qiniu_objects_manager::{apis::{credential::Credential, upload_token::FileType}, ObjectsManager};
326    ///
327    /// # fn example() -> anyhow::Result<()> {
328    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
329    /// let object_manager = ObjectsManager::new(credential);
330    /// let bucket = object_manager.bucket("test-bucket");
331    ///
332    /// bucket.set_object_type("test-key", FileType::Archive).call()?;
333    /// # Ok(())
334    /// # }
335    /// ```
336    ///
337    /// ##### 异步代码示例
338    ///
339    /// ```
340    /// use qiniu_objects_manager::{apis::{credential::Credential, upload_token::FileType}, ObjectsManager};
341    ///
342    /// # async fn example() -> anyhow::Result<()> {
343    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
344    /// let object_manager = ObjectsManager::new(credential);
345    /// let bucket = object_manager.bucket("test-bucket");
346    ///
347    /// bucket.set_object_type("test-key", FileType::Archive).async_call().await?;
348    /// # Ok(())
349    /// # }
350    /// ```
351    #[inline]
352    pub fn set_object_type<'a>(&'a self, object_name: &'a str, object_type: FileType) -> SetObjectTypeBuilder<'a> {
353        SetObjectType::builder(Entry::new(self, object_name), object_type)
354    }
355
356    /// 创建对象状态设置操作构建器
357    ///
358    /// ##### 阻塞代码示例
359    ///
360    /// ```
361    /// use qiniu_objects_manager::{apis::credential::Credential, ObjectsManager};
362    ///
363    /// # async fn example() -> anyhow::Result<()> {
364    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
365    /// let object_manager = ObjectsManager::new(credential);
366    /// let bucket = object_manager.bucket("test-bucket");
367    ///
368    /// bucket.modify_object_status("test-key", true).call()?;
369    /// # Ok(())
370    /// # }
371    /// ```
372    ///
373    /// ##### 异步代码示例
374    ///
375    /// ```
376    /// use qiniu_objects_manager::{apis::credential::Credential, ObjectsManager};
377    ///
378    /// # async fn example() -> anyhow::Result<()> {
379    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
380    /// let object_manager = ObjectsManager::new(credential);
381    /// let bucket = object_manager.bucket("test-bucket");
382    ///
383    /// bucket.modify_object_status("test-key", true).async_call().await?;
384    /// # Ok(())
385    /// # }
386    /// ```
387    #[inline]
388    pub fn modify_object_status<'a>(&'a self, object_name: &'a str, disable: bool) -> ModifyObjectStatusBuilder<'a> {
389        ModifyObjectStatus::builder(Entry::new(self, object_name), disable)
390    }
391
392    /// 创建对象元信息设置操作构建器
393    ///
394    /// ```
395    /// use qiniu_objects_manager::{apis::credential::Credential, ObjectsManager, mime::APPLICATION_JSON};
396    ///
397    /// # async fn example() -> anyhow::Result<()> {
398    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
399    /// let object_manager = ObjectsManager::new(credential);
400    /// let bucket = object_manager.bucket("test-bucket");
401    ///
402    /// bucket.modify_object_metadata("test-key", APPLICATION_JSON).async_call().await?;
403    /// # Ok(())
404    /// # }
405    /// ```
406    #[inline]
407    pub fn modify_object_metadata<'a>(
408        &'a self,
409        object_name: &'a str,
410        mime_type: Mime,
411    ) -> ModifyObjectMetadataBuilder<'a> {
412        ModifyObjectMetadata::builder(Entry::new(self, object_name), mime_type)
413    }
414
415    /// 创建对象生命周期设置操作构建器
416    ///
417    /// ##### 阻塞代码示例
418    ///
419    /// ```
420    /// use qiniu_objects_manager::{AfterDays, apis::credential::Credential, ObjectsManager};
421    ///
422    /// # async fn example() -> anyhow::Result<()> {
423    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
424    /// let object_manager = ObjectsManager::new(credential);
425    /// let bucket = object_manager.bucket("test-bucket");
426    ///
427    /// bucket.modify_object_life_cycle("test-key").delete_after_days(AfterDays::new(5)).call()?;
428    /// # Ok(())
429    /// # }
430    /// ```
431    ///
432    /// ##### 异步代码示例
433    ///
434    /// ```
435    /// use qiniu_objects_manager::{AfterDays, apis::credential::Credential, ObjectsManager};
436    ///
437    /// # async fn example() -> anyhow::Result<()> {
438    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
439    /// let object_manager = ObjectsManager::new(credential);
440    /// let bucket = object_manager.bucket("test-bucket");
441    ///
442    /// bucket.modify_object_life_cycle("test-key").delete_after_days(AfterDays::new(5)).async_call().await?;
443    /// # Ok(())
444    /// # }
445    /// ```
446    #[inline]
447    pub fn modify_object_life_cycle<'a>(&'a self, object_name: &'a str) -> ModifyObjectLifeCycleBuilder<'a> {
448        ModifyObjectLifeCycle::builder(Entry::new(self, object_name))
449    }
450
451    /// 创建批量操作
452    ///
453    /// ##### 阻塞代码示例
454    ///
455    /// ```
456    /// use qiniu_objects_manager::{apis::credential::Credential, ObjectsManager, OperationProvider};
457    ///
458    /// # fn example() -> anyhow::Result<()> {
459    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
460    /// let object_manager = ObjectsManager::new(credential);
461    /// let bucket = object_manager.bucket("test-bucket");
462    /// let mut ops = bucket.batch_ops();
463    /// ops.add_operation(bucket.stat_object("test-file-1"));
464    /// ops.add_operation(bucket.stat_object("test-file-2"));
465    /// ops.add_operation(bucket.stat_object("test-file-3"));
466    /// ops.add_operation(bucket.stat_object("test-file-4"));
467    /// ops.add_operation(bucket.stat_object("test-file-5"));
468    /// let mut iter = ops.call();
469    /// while let Some(object) = iter.next() {
470    ///     let object = object?;
471    ///     println!("fsize: {:?}", object.get_size_as_u64());
472    ///     println!("hash: {:?}", object.get_hash_as_str());
473    ///     println!("mime_type: {:?}", object.get_mime_type_as_str());
474    /// }
475    /// # Ok(())
476    /// # }
477    /// ```
478    ///
479    /// ##### 异步代码示例
480    ///
481    /// ```
482    /// use qiniu_objects_manager::{apis::credential::Credential, ObjectsManager, OperationProvider};
483    /// use futures::stream::TryStreamExt;
484    ///
485    /// # async fn example() -> anyhow::Result<()> {
486    /// let credential = Credential::new("abcdefghklmnopq", "1234567890");
487    /// let object_manager = ObjectsManager::new(credential);
488    /// let bucket = object_manager.bucket("test-bucket");
489    /// let mut ops = bucket.batch_ops();
490    /// ops.add_operation(bucket.stat_object("test-file-1"));
491    /// ops.add_operation(bucket.stat_object("test-file-2"));
492    /// ops.add_operation(bucket.stat_object("test-file-3"));
493    /// ops.add_operation(bucket.stat_object("test-file-4"));
494    /// ops.add_operation(bucket.stat_object("test-file-5"));
495    /// let mut stream = ops.async_call();
496    /// while let Some(object) = stream.try_next().await? {
497    ///     println!("fsize: {:?}", object.get_size_as_u64());
498    ///     println!("hash: {:?}", object.get_hash_as_str());
499    ///     println!("mime_type: {:?}", object.get_mime_type_as_str());
500    /// }
501    /// # Ok(())
502    /// # }
503    /// ```
504    #[inline]
505    pub fn batch_ops(&self) -> BatchOperations<'_> {
506        BatchOperations::new(self)
507    }
508
509    pub(super) fn region_provider(&self) -> IOResult<&dyn RegionsProvider> {
510        self.0
511            .region_provider
512            .as_ref()
513            .map(|r| Ok(r as &dyn RegionsProvider))
514            .unwrap_or_else(|| {
515                self.0
516                    .bucket_regions_provider
517                    .get_or_try_init(|| {
518                        Ok(self.0.objects_manager.queryer().query(
519                            self.0
520                                .objects_manager
521                                .credential()
522                                .get(Default::default())?
523                                .access_key()
524                                .to_owned(),
525                            self.name().to_owned(),
526                        ))
527                    })
528                    .map(|r| r as &dyn RegionsProvider)
529            })
530    }
531
532    #[cfg(feature = "async")]
533    pub(super) async fn async_region_provider(&self) -> IOResult<&dyn RegionsProvider> {
534        return if let Some(region_provider) = self.0.region_provider.as_ref() {
535            Ok(region_provider)
536        } else {
537            self.0
538                .async_bucket_regions_provider
539                .get_or_try_init(create_region_provider(&self.0.objects_manager, self.name()))
540                .await
541                .map(|r| r as &dyn RegionsProvider)
542        };
543
544        async fn create_region_provider(
545            objects_manager: &ObjectsManager,
546            bucket_name: &BucketName,
547        ) -> IOResult<BucketRegionsProvider> {
548            Ok(objects_manager.queryer().query(
549                objects_manager
550                    .credential()
551                    .async_get(Default::default())
552                    .await?
553                    .access_key()
554                    .to_owned(),
555                bucket_name.to_owned(),
556            ))
557        }
558    }
559
560    #[allow(dead_code)]
561    fn assert() {
562        assert_impl!(Send: Self);
563        assert_impl!(Sync: Self);
564    }
565}
566
567/// 列举操作构建器
568///
569/// 可以通过 [`Bucket::list`] 方法获取该构建器。
570#[must_use]
571#[derive(Debug)]
572pub struct ListBuilder<'a> {
573    bucket: &'a Bucket,
574    limit: Option<usize>,
575    prefix: Option<Cow<'a, str>>,
576    marker: Option<Cow<'a, str>>,
577    version: ListVersion,
578    need_parts: bool,
579    callbacks: Callbacks<'a>,
580}
581
582impl<'a> ListBuilder<'a> {
583    fn new(bucket: &'a Bucket) -> Self {
584        Self {
585            bucket,
586            limit: Default::default(),
587            prefix: Default::default(),
588            marker: Default::default(),
589            version: Default::default(),
590            need_parts: Default::default(),
591            callbacks: Default::default(),
592        }
593    }
594
595    #[inline]
596    /// 设置列举限制
597    pub fn limit(&mut self, limit: usize) -> &mut Self {
598        self.limit = Some(limit);
599        self
600    }
601
602    #[inline]
603    /// 设置对象名称前缀匹配字符串
604    pub fn prefix(&mut self, prefix: impl Into<Cow<'a, str>>) -> &mut Self {
605        self.prefix = Some(prefix.into());
606        self
607    }
608
609    #[inline]
610    /// 设置上一次列举返回的位置标记
611    pub fn marker(&mut self, marker: impl Into<Cow<'a, str>>) -> &mut Self {
612        self.marker = Some(marker.into());
613        self
614    }
615
616    #[inline]
617    /// 设置列举 API 版本
618    pub fn version(&mut self, version: ListVersion) -> &mut Self {
619        self.version = version;
620        self
621    }
622
623    /// 设置是否需要返回分片信息
624    #[inline]
625    pub fn need_parts(&mut self) -> &mut Self {
626        self.need_parts = true;
627        self
628    }
629
630    /// 设置请求前回调函数
631    #[inline]
632    pub fn before_request_callback(
633        &mut self,
634        callback: impl FnMut(&mut RequestBuilderParts<'_>) -> AnyResult<()> + Send + Sync + 'a,
635    ) -> &mut Self {
636        self.callbacks.insert_before_request_callback(callback);
637        self
638    }
639
640    /// 设置响应成功回调函数
641    #[inline]
642    pub fn after_response_ok_callback(
643        &mut self,
644        callback: impl FnMut(&mut ResponseParts) -> AnyResult<()> + Send + Sync + 'a,
645    ) -> &mut Self {
646        self.callbacks.insert_after_response_ok_callback(callback);
647        self
648    }
649
650    /// 设置响应失败回调函数
651    #[inline]
652    pub fn after_response_error_callback(
653        &mut self,
654        callback: impl FnMut(&mut ResponseError) -> AnyResult<()> + Send + Sync + 'a,
655    ) -> &mut Self {
656        self.callbacks.insert_after_response_error_callback(callback);
657        self
658    }
659
660    /// 创建对象列举迭代器
661    ///
662    /// 对象列举迭代器采用阻塞 API 列举对象信息
663    ///
664    /// 该方法的的异步版本为 [`Self::stream`]。
665    #[inline]
666    pub fn iter(&mut self) -> ListIter<'a> {
667        let owned = self.take_self();
668        ListIter::new(
669            owned.bucket,
670            owned.limit,
671            owned.prefix,
672            owned.marker,
673            owned.need_parts,
674            owned.version,
675            owned.callbacks,
676        )
677    }
678
679    /// 创建对象列举流
680    ///
681    /// 对象列举流采用异步 API 列举对象信息
682    #[inline]
683    #[cfg(feature = "async")]
684    #[cfg_attr(feature = "docs", doc(cfg(feature = "async")))]
685    pub fn stream(&mut self) -> ListStream<'a> {
686        let owned = self.take_self();
687        ListStream::new(
688            owned.bucket,
689            owned.limit,
690            owned.prefix,
691            owned.marker,
692            owned.need_parts,
693            owned.version,
694            owned.callbacks,
695        )
696    }
697
698    fn take_self(&mut self) -> Self {
699        Self {
700            bucket: self.bucket,
701            limit: take(&mut self.limit),
702            prefix: take(&mut self.prefix),
703            marker: take(&mut self.marker),
704            need_parts: take(&mut self.need_parts),
705            version: take(&mut self.version),
706            callbacks: take(&mut self.callbacks),
707        }
708    }
709
710    #[allow(dead_code)]
711    fn assert() {
712        assert_impl!(Send: Self);
713        assert_impl!(Sync: Self);
714    }
715}