aliyun_oss_client/
object.rs

1//! # Object 相关功能
2//! `ObjectList` 对应文件列表,`Object` 对应的是单个文件对象
3//!
4//! `ObjectList` 也可以支持自定义的类型存储单个文件对象,例如 [issue 12] 提到的,有些时候,
5//! Oss 接口不仅返回文件路径,还会返回目录路径,可以使用如下例子进行适配
6//!
7//! ```rust,no_run
8//! use aliyun_oss_client::{
9//!     decode::RefineObject,
10//!     object::{Objects, InitObject},
11//!     types::object::{InvalidObjectDir, ObjectDir, ObjectPath},
12//!     BucketName, Client,
13//! };
14//! use dotenv::dotenv;
15//!
16//! #[derive(Debug)]
17//! enum MyObject {
18//!     File(ObjectPath),
19//!     Dir(ObjectDir<'static>),
20//! }
21//!
22//! impl RefineObject<InvalidObjectDir> for MyObject {
23//!     fn set_key(&mut self, key: &str) -> Result<(), InvalidObjectDir> {
24//!         *self = match key.parse() {
25//!             Ok(file) => MyObject::File(file),
26//!             _ => MyObject::Dir(key.parse()?),
27//!         };
28//!
29//!         Ok(())
30//!     }
31//! }
32//!
33//! type MyList = Objects<MyObject>;
34//!
35//! // 可以根据传入的列表信息,为元素添加更多能力
36//! impl InitObject<MyObject> for MyList {
37//!     fn init_object(&mut self) -> Option<MyObject> {
38//!         Some(MyObject::File(ObjectPath::default()))
39//!     }
40//! }
41//!
42//! #[tokio::main]
43//! async fn main() {
44//!     dotenv().ok();
45//!
46//!     let client = Client::from_env().unwrap();
47//!
48//!     let mut list = MyList::default();
49//!
50//!     let _ = client.base_object_list([], &mut list).await;
51//!     // 第二页数据
52//!     let second = list.get_next_base().await;
53//!
54//!     println!("list: {:?}", list.to_vec());
55//! }
56//! ```
57//! [issue 12]: https://github.com/tu6ge/oss-rs/issues/12
58
59use crate::bucket::Bucket;
60#[cfg(feature = "blocking")]
61use crate::builder::RcPointer;
62use crate::builder::{ArcPointer, BuilderError, PointerFamily};
63use crate::client::ClientArc;
64#[cfg(feature = "blocking")]
65use crate::client::ClientRc;
66use crate::config::BucketBase;
67use crate::decode::{InnerListError, ListError, RefineObject, RefineObjectList};
68#[cfg(feature = "blocking")]
69use crate::file::blocking::AlignBuilder as BlockingAlignBuilder;
70use crate::file::AlignBuilder;
71use crate::types::object::ObjectPathInner;
72use crate::types::{
73    core::SetOssQuery,
74    object::{
75        CommonPrefixes, InvalidObjectDir, InvalidObjectPath, ObjectBase, ObjectDir, ObjectPath,
76    },
77    CanonicalizedResource, Query, QueryKey, QueryValue, CONTINUATION_TOKEN,
78};
79use crate::{BucketName, Client, EndPoint, KeyId, KeySecret};
80use async_stream::try_stream;
81use chrono::{DateTime, NaiveDateTime, Utc};
82use futures_core::stream::Stream;
83use http::Method;
84use oss_derive::oss_gen_rc;
85use url::Url;
86
87#[cfg(feature = "blocking")]
88use std::rc::Rc;
89use std::{
90    error::Error,
91    fmt::{self, Display},
92    num::ParseIntError,
93    sync::Arc,
94    vec::IntoIter,
95};
96
97pub mod content;
98pub use content::Content;
99
100#[cfg(test)]
101mod test;
102
103/// # 存放对象列表的结构体
104/// before name is `ObjectList`
105/// TODO impl core::ops::Index
106#[derive(Clone)]
107#[non_exhaustive]
108pub struct ObjectList<P: PointerFamily = ArcPointer, Item = Object<P>> {
109    pub(crate) bucket: BucketBase,
110    prefix: Option<ObjectDir<'static>>,
111    max_keys: u32,
112    key_count: u64,
113    /// 存放单个文件对象的 Vec 集合
114    object_list: Vec<Item>,
115    next_continuation_token: String,
116    common_prefixes: CommonPrefixes,
117    client: P::PointerType,
118    search_query: Query,
119}
120
121/// sync ObjectList alias
122pub type Objects<Item = Object<ArcPointer>> = ObjectList<ArcPointer, Item>;
123/// blocking ObjectList alias
124#[cfg(feature = "blocking")]
125pub type ObjectsBlocking<Item = Object<RcPointer>> = ObjectList<RcPointer, Item>;
126
127/// 存放单个对象的结构体
128#[derive(Clone, Debug)]
129#[non_exhaustive]
130pub struct Object<PointerSel: PointerFamily = ArcPointer> {
131    pub(crate) base: ObjectBase<PointerSel>,
132    last_modified: DateTime<Utc>,
133    etag: String,
134    _type: String,
135    size: u64,
136    storage_class: StorageClass,
137}
138
139/// 异步的 Object struct
140pub type ObjectArc = Object<ArcPointer>;
141
142impl<T: PointerFamily, Item> fmt::Debug for ObjectList<T, Item> {
143    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
144        f.debug_struct("ObjectList")
145            .field("bucket", &self.bucket)
146            .field("prefix", &self.prefix)
147            .field("max_keys", &self.max_keys)
148            .field("key_count", &self.key_count)
149            .field("next_continuation_token", &self.next_continuation_token)
150            .field("common_prefixes", &self.common_prefixes)
151            .field("search_query", &self.search_query)
152            .finish()
153    }
154}
155
156impl<P: PointerFamily, Item> Default for ObjectList<P, Item> {
157    fn default() -> Self {
158        Self {
159            bucket: BucketBase::default(),
160            prefix: Option::default(),
161            max_keys: u32::default(),
162            key_count: u64::default(),
163            object_list: Vec::new(),
164            next_continuation_token: String::default(),
165            common_prefixes: CommonPrefixes::default(),
166            client: P::PointerType::default(),
167            search_query: Query::default(),
168            //init_fn: Box::default(),
169        }
170    }
171}
172
173impl<T: PointerFamily, Item> AsMut<Query> for ObjectList<T, Item> {
174    fn as_mut(&mut self) -> &mut Query {
175        &mut self.search_query
176    }
177}
178
179impl<T: PointerFamily, Item> AsRef<BucketBase> for ObjectList<T, Item> {
180    fn as_ref(&self) -> &BucketBase {
181        &self.bucket
182    }
183}
184
185impl<T: PointerFamily, Item> AsRef<BucketName> for ObjectList<T, Item> {
186    fn as_ref(&self) -> &BucketName {
187        self.bucket.as_ref()
188    }
189}
190
191impl<T: PointerFamily, Item> AsRef<EndPoint> for ObjectList<T, Item> {
192    fn as_ref(&self) -> &EndPoint {
193        self.bucket.as_ref()
194    }
195}
196
197impl<T: PointerFamily, Item> ObjectList<T, Item> {
198    /// 文件列表的初始化方法
199    #[allow(clippy::too_many_arguments)]
200    pub fn new<Q: IntoIterator<Item = (QueryKey, QueryValue)>>(
201        bucket: BucketBase,
202        prefix: Option<ObjectDir<'static>>,
203        max_keys: u32,
204        key_count: u64,
205        object_list: Vec<Item>,
206        next_continuation_token: Option<String>,
207        client: T::PointerType,
208        search_query: Q,
209    ) -> Self {
210        Self {
211            bucket,
212            prefix,
213            max_keys,
214            key_count,
215            object_list,
216            next_continuation_token: next_continuation_token.unwrap_or_default(),
217            common_prefixes: CommonPrefixes::default(),
218            client,
219            search_query: Query::from_iter(search_query),
220            //init_fn: Box::default(),
221        }
222    }
223
224    /// 返回 bucket 元信息的引用
225    pub fn bucket(&self) -> &BucketBase {
226        &self.bucket
227    }
228
229    /// 返回 prefix 的引用
230    pub fn prefix(&self) -> &Option<ObjectDir<'static>> {
231        &self.prefix
232    }
233
234    /// 获取文件夹下的子文件夹名,子文件夹下递归的所有文件和文件夹不包含在这里。
235    pub fn common_prefixes(&self) -> &CommonPrefixes {
236        &self.common_prefixes
237    }
238
239    /// 设置 common_prefixes 信息
240    pub fn set_common_prefixes<P: IntoIterator<Item = ObjectDir<'static>>>(&mut self, prefixes: P) {
241        self.common_prefixes = CommonPrefixes::from_iter(prefixes);
242    }
243
244    /// 返回 max_keys
245    pub fn max_keys(&self) -> &u32 {
246        &self.max_keys
247    }
248
249    /// 返回 key_count
250    pub fn key_count(&self) -> &u64 {
251        &self.key_count
252    }
253
254    /// # 返回下一个 continuation_token
255    /// 用于翻页使用
256    pub fn next_continuation_token_str(&self) -> &String {
257        &self.next_continuation_token
258    }
259
260    /// 返回查询条件
261    pub fn search_query(&self) -> &Query {
262        &self.search_query
263    }
264
265    /// # 下一页的查询条件
266    ///
267    /// 如果有下一页,返回 Some(Query)
268    /// 如果没有下一页,则返回 None
269    pub fn next_query(&self) -> Option<Query> {
270        if !self.next_continuation_token.is_empty() {
271            let mut search_query = self.search_query.clone();
272            search_query.insert(CONTINUATION_TOKEN, self.next_continuation_token.to_owned());
273            Some(search_query)
274        } else {
275            None
276        }
277    }
278
279    /// 将 object 列表转化为迭代器
280    pub fn object_iter(self) -> IntoIter<Item> {
281        self.object_list.into_iter()
282    }
283}
284
285#[oss_gen_rc]
286impl<Item> ObjectList<ArcPointer, Item> {
287    /// 设置 Client
288    pub(crate) fn set_client(&mut self, client: Arc<ClientArc>) {
289        self.client = client;
290    }
291
292    pub(crate) fn from_bucket(
293        bucket: &Bucket<ArcPointer>,
294        capacity: usize,
295    ) -> ObjectList<ArcPointer> {
296        ObjectList::<ArcPointer> {
297            bucket: bucket.base.clone(),
298            client: Arc::clone(&bucket.client),
299            object_list: Vec::with_capacity(capacity),
300            ..Default::default()
301        }
302    }
303
304    /// 获取 Client 引用
305    pub(crate) fn client(&self) -> Arc<ClientArc> {
306        Arc::clone(&self.client)
307    }
308
309    fn clone_base(&self) -> Self {
310        Self {
311            client: Arc::clone(&self.client),
312            bucket: self.bucket.clone(),
313            search_query: self.search_query.clone(),
314            max_keys: self.max_keys,
315            object_list: Vec::with_capacity(self.max_keys as usize),
316            ..Default::default()
317        }
318    }
319}
320
321/// # 初始化 object 项目的接口
322///
323/// 根据 object 列表类型初始化一个 object 数据
324///
325/// 当对 OSS xml 数据进行解析时,每解析一个 object 时,
326/// 会先调用此 trait 中的 init_object 初始化 object 类型,再解析 xml 数据
327///
328/// Target 为 object 的具体类型
329pub trait InitObject<Target> {
330    /// 初始化 object 的类型
331    ///
332    /// 当返回 None 时,解析 OSS xml 数据时,会抛出 "init_object failed" 错误
333    fn init_object(&mut self) -> Option<Target>;
334}
335
336impl InitObject<Object<ArcPointer>> for ObjectList<ArcPointer, Object<ArcPointer>> {
337    fn init_object(&mut self) -> Option<Object<ArcPointer>> {
338        Some(Object::from_bucket(Arc::new(self.bucket.clone())))
339    }
340}
341
342#[cfg(feature = "blocking")]
343impl InitObject<Object<RcPointer>> for ObjectList<RcPointer, Object<RcPointer>> {
344    fn init_object(&mut self) -> Option<Object<RcPointer>> {
345        Some(Object::<RcPointer>::from_bucket(Rc::new(
346            self.bucket.clone(),
347        )))
348    }
349}
350
351impl ObjectList<ArcPointer> {
352    /// 异步获取下一页的数据
353    /// TODO 改为 unstable
354    pub async fn get_next_list(&self) -> Result<ObjectList<ArcPointer>, ExtractListError> {
355        match self.next_query() {
356            None => Err(ExtractListError {
357                kind: ExtractListErrorKind::NoMoreFile,
358            }),
359            Some(query) => {
360                let mut url = self.bucket.to_url();
361                url.set_oss_query(&query);
362
363                let canonicalized = CanonicalizedResource::from_bucket_query(&self.bucket, &query);
364
365                let response = self
366                    .builder(Method::GET, url, canonicalized)?
367                    .send_adjust_error()
368                    .await?;
369
370                let mut list = ObjectList::<ArcPointer> {
371                    client: self.client(),
372                    bucket: self.bucket.clone(),
373                    object_list: Vec::with_capacity(query.get_max_keys()),
374                    ..Default::default()
375                };
376
377                list.decode(&response.text().await?, Self::init_object)?;
378
379                list.set_search_query(query);
380                Ok(list)
381            }
382        }
383    }
384
385    /// # 将 object_list 转化为 stream, 返回第二页,第三页... 的内容
386    ///
387    /// *不够完善,最后一次迭代返回的是 `Some(Err(OssError::WithoutMore))`,而不是 `None`*
388    ///
389    /// ## 用法
390    ///
391    /// 1. 添加依赖
392    /// ```toml
393    /// [dependencies]
394    /// futures="0.3"
395    /// ```
396    /// 2. 将返回结果 pin 住
397    /// ```no_run
398    /// # use dotenv::dotenv;
399    /// # use aliyun_oss_client::Client;
400    /// # #[tokio::main]
401    /// # async fn main() {
402    /// # dotenv().ok();
403    /// use futures::{pin_mut, StreamExt};
404    /// # let client = Client::from_env().unwrap();
405    /// # let query = [("max-keys".into(), 100u8.into())];
406    /// # let object_list = client.get_object_list(query).await.unwrap();
407    /// let stream = object_list.into_stream();
408    /// pin_mut!(stream);
409    ///
410    /// let second_list = stream.next().await;
411    /// let third_list = stream.next().await;
412    /// println!("second_list: {:?}", second_list);
413    /// println!("third_list: {:?}", third_list);
414    /// # }
415    /// ```
416    pub fn into_stream(self) -> impl Stream<Item = Result<Self, ExtractListError>> {
417        try_stream! {
418            let result = self.get_next_list().await?;
419            yield result;
420        }
421    }
422}
423
424impl<Item> ObjectList<ArcPointer, Item>
425where
426    Self: InitObject<Item>,
427{
428    /// # 自定义 Item 时,获取下一页数据
429    /// 当没有下一页查询条件时 返回 `None`
430    /// 否则尝试获取下一页数据,成功返回 `Some(Ok(_))`, 失败返回 `Some(Err(_))`
431    pub async fn get_next_base<E>(&mut self) -> Option<Result<Self, ExtractListError>>
432    where
433        Item: RefineObject<E>,
434        E: Error + 'static,
435    {
436        match self.next_query() {
437            None => None,
438            Some(query) => {
439                let mut list = self.clone_base();
440                list.search_query = query.clone();
441                let res = self.client().base_object_list(query, &mut list).await;
442                Some(res.map(|_| list))
443            }
444        }
445    }
446}
447
448#[cfg(feature = "blocking")]
449impl ObjectList<RcPointer> {
450    /// 从 OSS 获取 object 列表信息
451    pub fn get_object_list(&self) -> Result<Self, ExtractListError> {
452        let mut list = ObjectList::<RcPointer>::clone_base(self);
453
454        let (bucket_url, resource) = self.bucket.get_url_resource(&self.search_query);
455
456        let response = self
457            .builder(Method::GET, bucket_url, resource)?
458            .send_adjust_error()?;
459
460        list.decode(&response.text()?, ObjectList::<RcPointer>::init_object)
461            .map_err(ExtractListError::from)?;
462
463        Ok(list)
464    }
465}
466
467impl<T: PointerFamily, Item> ObjectList<T, Item> {
468    /// 设置查询条件
469    #[inline]
470    pub fn set_search_query(&mut self, search_query: Query) {
471        self.search_query = search_query;
472    }
473
474    /// 设置 bucket 元信息
475    pub fn set_bucket(&mut self, bucket: BucketBase) {
476        self.bucket = bucket;
477    }
478
479    /// 获取 bucket 名称
480    pub fn bucket_name(&self) -> &str {
481        self.bucket.name()
482    }
483
484    /// 返回 object 的 Vec 集合
485    pub fn to_vec(self) -> Vec<Item> {
486        self.object_list
487    }
488
489    /// 返回文件数量
490    pub fn len(&self) -> usize {
491        self.object_list.len()
492    }
493
494    /// 返回是否存在文件
495    pub fn is_empty(&self) -> bool {
496        self.object_list.is_empty()
497    }
498}
499
500impl<T: PointerFamily> Default for Object<T> {
501    fn default() -> Self {
502        Object {
503            base: ObjectBase::<T>::default(),
504            last_modified: DateTime::<Utc>::from_utc(
505                #[allow(clippy::unwrap_used)]
506                NaiveDateTime::from_timestamp_opt(0, 0).unwrap(),
507                Utc,
508            ),
509            etag: String::default(),
510            _type: String::default(),
511            size: 0,
512            storage_class: StorageClass::default(),
513        }
514    }
515}
516
517impl<T: PointerFamily> AsRef<ObjectPath> for Object<T> {
518    fn as_ref(&self) -> &ObjectPath {
519        self.base.as_ref()
520    }
521}
522
523impl<T: PointerFamily> AsRef<DateTime<Utc>> for Object<T> {
524    fn as_ref(&self) -> &DateTime<Utc> {
525        &self.last_modified
526    }
527}
528
529impl<T: PointerFamily> AsRef<StorageClass> for Object<T> {
530    fn as_ref(&self) -> &StorageClass {
531        &self.storage_class
532    }
533}
534
535impl<T: PointerFamily> Object<T> {
536    /// 初始化 Object 结构体
537    pub fn new(
538        bucket: T::Bucket,
539        path: ObjectPath,
540        last_modified: DateTime<Utc>,
541        etag: String,
542        _type: String,
543        size: u64,
544        storage_class: StorageClass,
545    ) -> Self {
546        let base = ObjectBase::<T>::new2(bucket, path);
547        Self {
548            base,
549            last_modified,
550            etag,
551            _type,
552            size,
553            storage_class,
554        }
555    }
556
557    pub(crate) fn from_bucket(bucket: T::Bucket) -> Self {
558        Self {
559            base: ObjectBase::<T>::init_with_bucket(bucket),
560            ..Default::default()
561        }
562    }
563
564    /// 读取 Object 元信息
565    #[inline]
566    pub fn base(&self) -> &ObjectBase<T> {
567        &self.base
568    }
569
570    /// 设置 Object 元信息
571    #[inline]
572    pub fn set_base(&mut self, base: ObjectBase<T>) {
573        self.base = base;
574    }
575
576    /// 读取最后修改时间
577    #[inline]
578    pub fn last_modified(&self) -> &DateTime<Utc> {
579        &self.last_modified
580    }
581
582    /// 设置最后修改时间
583    #[inline]
584    pub fn set_last_modified(&mut self, last_modified: DateTime<Utc>) {
585        self.last_modified = last_modified;
586    }
587
588    /// 读取 etag 信息
589    #[inline]
590    pub fn etag(&self) -> &String {
591        &self.etag
592    }
593
594    /// 设置 etag
595    #[inline]
596    pub fn set_etag(&mut self, etag: String) {
597        self.etag = etag
598    }
599
600    /// 读取 type
601    #[inline]
602    pub fn get_type_string(&self) -> &String {
603        &self._type
604    }
605
606    /// 设置 type
607    #[inline]
608    pub fn set_type_string(&mut self, _type: String) {
609        self._type = _type;
610    }
611
612    /// 读取文件 size
613    #[inline]
614    pub fn size(&self) -> u64 {
615        self.size
616    }
617
618    /// 设置文件 size
619    #[inline]
620    pub fn set_size(&mut self, size: u64) {
621        self.size = size;
622    }
623
624    /// 读取 storage_class
625    #[inline]
626    pub fn storage_class(&self) -> &StorageClass {
627        &self.storage_class
628    }
629
630    /// 设置 storage_class
631    #[inline]
632    pub fn set_storage_class(&mut self, storage_class: StorageClass) {
633        self.storage_class = storage_class;
634    }
635
636    /// 获取一部分数据
637    pub fn pieces(
638        self,
639    ) -> (
640        ObjectBase<T>,
641        DateTime<Utc>,
642        String,
643        String,
644        u64,
645        StorageClass,
646    ) {
647        (
648            self.base,
649            self.last_modified,
650            self.etag,
651            self._type,
652            self.size,
653            self.storage_class,
654        )
655    }
656
657    /// 读取 文件路径
658    pub fn path(&self) -> ObjectPath {
659        self.base.path()
660    }
661
662    #[doc(hidden)]
663    pub fn path_string(&self) -> String {
664        self.base.path().to_string()
665    }
666}
667
668impl Object<ArcPointer> {
669    #[cfg(test)]
670    pub fn test_path(path: &'static str) -> Self {
671        let mut object = Self::default();
672        object.set_base(ObjectBase::<ArcPointer>::new2(
673            Arc::new(BucketBase::default()),
674            path.try_into().unwrap(),
675        ));
676        object
677    }
678}
679
680impl<T: PointerFamily> From<Object<T>> for ObjectPathInner<'static> {
681    #[inline]
682    fn from(obj: Object<T>) -> Self {
683        obj.base.path
684    }
685}
686
687#[oss_gen_rc]
688impl Object<ArcPointer> {
689    /// # Object 构建器
690    /// 用例
691    /// ```
692    /// # use aliyun_oss_client::{config::BucketBase, ObjectPath, object::{ObjectArc, StorageClass},EndPoint};
693    /// # use chrono::{DateTime, NaiveDateTime, Utc};
694    /// let bucket = BucketBase::new(
695    ///     "bucket-name".parse().unwrap(),
696    ///     EndPoint::CN_QINGDAO,
697    /// );
698    /// let mut builder = ObjectArc::builder("abc".parse::<ObjectPath>().unwrap());
699    ///
700    /// builder
701    ///     .bucket_base(bucket)
702    ///     .last_modified(DateTime::<Utc>::from_utc(
703    ///         NaiveDateTime::from_timestamp_opt(123000, 0).unwrap(),
704    ///         Utc,
705    ///     ))
706    ///     .etag("foo1".to_owned())
707    ///     .set_type("foo2".to_owned())
708    ///     .size(123)
709    ///     .storage_class(StorageClass::IA);
710    ///
711    /// let object = builder.build();
712    /// ```
713    pub fn builder(path: ObjectPath) -> ObjectBuilder<ArcPointer> {
714        ObjectBuilder::<ArcPointer>::new(Arc::default(), path)
715    }
716
717    /// 带签名的 Url 链接
718    pub fn to_sign_url(&self, key: &KeyId, secret: &KeySecret, expires: i64) -> Url {
719        self.base.to_sign_url(key, secret, expires)
720    }
721}
722
723/// Object 结构体的构建器
724pub struct ObjectBuilder<T: PointerFamily = ArcPointer> {
725    object: Object<T>,
726}
727
728impl<T: PointerFamily> ObjectBuilder<T> {
729    /// 初始化 Object 构建器
730    pub fn new(bucket: T::Bucket, path: ObjectPath) -> Self {
731        let base = ObjectBase::<T>::new2(bucket, path);
732        Self {
733            object: Object {
734                base,
735                last_modified: DateTime::<Utc>::from_utc(
736                    #[allow(clippy::unwrap_used)]
737                    NaiveDateTime::from_timestamp_opt(0, 0).unwrap(),
738                    Utc,
739                ),
740                ..Default::default()
741            },
742        }
743    }
744
745    /// 设置元信息
746    pub fn bucket(&mut self, bucket: T::Bucket) -> &mut Self {
747        self.object.base.set_bucket(bucket);
748        self
749    }
750
751    /// 设置 last_modified
752    pub fn last_modified(&mut self, date: DateTime<Utc>) -> &mut Self {
753        self.object.last_modified = date;
754        self
755    }
756
757    /// 设置 etag
758    pub fn etag(&mut self, etag: String) -> &mut Self {
759        self.object.etag = etag;
760        self
761    }
762
763    /// 设置 type
764    pub fn set_type(&mut self, _type: String) -> &mut Self {
765        self.object._type = _type;
766        self
767    }
768
769    /// 设置 size
770    pub fn size(&mut self, size: u64) -> &mut Self {
771        self.object.size = size;
772        self
773    }
774
775    /// 设置 storage_class
776    pub fn storage_class(&mut self, storage_class: StorageClass) -> &mut Self {
777        self.object.storage_class = storage_class;
778        self
779    }
780
781    /// 返回 object
782    pub fn build(self) -> Object<T> {
783        self.object
784    }
785}
786
787#[oss_gen_rc]
788impl ObjectBuilder<ArcPointer> {
789    /// 设置元信息
790    pub fn bucket_base(&mut self, base: BucketBase) -> &mut Self {
791        self.object.base.set_bucket(Arc::new(base));
792        self
793    }
794}
795
796impl<T: PointerFamily> RefineObject<BuildInItemError> for Object<T> {
797    #[inline]
798    fn set_key(&mut self, key: &str) -> Result<(), BuildInItemError> {
799        self.base
800            .set_path(key.to_owned())
801            .map_err(|e| BuildInItemError {
802                source: key.to_string(),
803                kind: BuildInItemErrorKind::BasePath(e),
804            })
805    }
806
807    #[inline]
808    fn set_last_modified(&mut self, value: &str) -> Result<(), BuildInItemError> {
809        self.last_modified = value.parse().map_err(|e| BuildInItemError {
810            source: value.to_string(),
811            kind: BuildInItemErrorKind::LastModified(e),
812        })?;
813        Ok(())
814    }
815
816    #[inline]
817    fn set_etag(&mut self, value: &str) -> Result<(), BuildInItemError> {
818        self.etag = value.to_string();
819        Ok(())
820    }
821
822    #[inline]
823    fn set_type(&mut self, value: &str) -> Result<(), BuildInItemError> {
824        self._type = value.to_string();
825        Ok(())
826    }
827
828    #[inline]
829    fn set_size(&mut self, size: &str) -> Result<(), BuildInItemError> {
830        self.size = size.parse().map_err(|e| BuildInItemError {
831            source: size.to_string(),
832            kind: BuildInItemErrorKind::Size(e),
833        })?;
834        Ok(())
835    }
836
837    #[inline]
838    fn set_storage_class(&mut self, storage_class: &str) -> Result<(), BuildInItemError> {
839        self.storage_class = StorageClass::new(storage_class).ok_or(BuildInItemError {
840            source: storage_class.to_string(),
841            kind: BuildInItemErrorKind::InvalidStorageClass,
842        })?;
843        Ok(())
844    }
845}
846
847/// Xml 转化为内置 Object 时的错误集合
848#[derive(Debug)]
849#[non_exhaustive]
850pub struct BuildInItemError {
851    source: String,
852    kind: BuildInItemErrorKind,
853}
854
855impl BuildInItemError {
856    #[cfg(test)]
857    pub(crate) fn test_new() -> Self {
858        Self {
859            source: "foo".to_string(),
860            kind: BuildInItemErrorKind::InvalidStorageClass,
861        }
862    }
863
864    pub(crate) fn new<K: Into<BuildInItemErrorKind>>(kind: K, source: &str) -> Self {
865        Self {
866            source: source.to_owned(),
867            kind: kind.into(),
868        }
869    }
870}
871
872impl Display for BuildInItemError {
873    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
874        use BuildInItemErrorKind::*;
875        let kind = match &self.kind {
876            Size(_) => "size",
877            BasePath(_) => "base-path",
878            LastModified(_) => "last-modified",
879            InvalidStorageClass => "storage-class",
880        };
881        write!(f, "parse {kind} failed, gived str: {}", self.source)
882    }
883}
884
885impl Error for BuildInItemError {
886    fn source(&self) -> Option<&(dyn Error + 'static)> {
887        use BuildInItemErrorKind::*;
888        match &self.kind {
889            Size(e) => Some(e),
890            BasePath(e) => Some(e),
891            LastModified(e) => Some(e),
892            InvalidStorageClass => None,
893        }
894    }
895}
896
897/// Xml 转化为内置 Object 时的错误集合
898#[derive(Debug)]
899#[non_exhaustive]
900pub(crate) enum BuildInItemErrorKind {
901    /// 转换数字类型的错误
902    Size(ParseIntError),
903
904    /// 转换为 ObjectPath 时的错误
905    BasePath(InvalidObjectPath),
906
907    /// 转换日期格式的错误
908    LastModified(chrono::ParseError),
909
910    // /// 接收 Xml 转换时的错误
911    // Xml(quick_xml::Error),
912    /// 非法的 StorageClass
913    InvalidStorageClass,
914}
915
916impl From<InvalidObjectPath> for BuildInItemErrorKind {
917    fn from(value: InvalidObjectPath) -> Self {
918        Self::BasePath(value)
919    }
920}
921
922impl<P: PointerFamily, Item: RefineObject<E>, E: Error + 'static>
923    RefineObjectList<Item, ObjectListError, E> for ObjectList<P, Item>
924{
925    #[inline]
926    fn set_key_count(&mut self, key_count: &str) -> Result<(), ObjectListError> {
927        self.key_count = key_count.parse().map_err(|e| ObjectListError {
928            source: key_count.to_owned(),
929            kind: ObjectListErrorKind::KeyCount(e),
930        })?;
931        Ok(())
932    }
933
934    #[inline]
935    fn set_prefix(&mut self, prefix: &str) -> Result<(), ObjectListError> {
936        if prefix.is_empty() {
937            self.prefix = None;
938        } else {
939            let mut string = String::from(prefix);
940            string += "/";
941            self.prefix = Some(string.parse().map_err(|e| ObjectListError {
942                source: prefix.to_owned(),
943                kind: ObjectListErrorKind::Prefix(e),
944            })?)
945        }
946        Ok(())
947    }
948
949    #[inline]
950    fn set_common_prefix(
951        &mut self,
952        list: &[std::borrow::Cow<'_, str>],
953    ) -> Result<(), ObjectListError> {
954        self.common_prefixes = Vec::with_capacity(list.len());
955        for val in list.iter() {
956            self.common_prefixes
957                .push(val.parse().map_err(|e| ObjectListError {
958                    source: val.to_string(),
959                    kind: ObjectListErrorKind::CommonPrefix(e),
960                })?);
961        }
962        Ok(())
963    }
964
965    #[inline]
966    fn set_max_keys(&mut self, max_keys: &str) -> Result<(), ObjectListError> {
967        self.max_keys = max_keys.parse().map_err(|e| ObjectListError {
968            source: max_keys.to_string(),
969            kind: ObjectListErrorKind::MaxKeys(e),
970        })?;
971        Ok(())
972    }
973
974    #[inline]
975    fn set_next_continuation_token_str(&mut self, token: &str) -> Result<(), ObjectListError> {
976        self.next_continuation_token = token.to_owned();
977        Ok(())
978    }
979
980    #[inline]
981    fn set_list(&mut self, list: Vec<Item>) -> Result<(), ObjectListError> {
982        self.object_list = list;
983        Ok(())
984    }
985}
986
987/// decode xml to object list error collection
988#[derive(Debug)]
989#[non_exhaustive]
990pub struct ObjectListError {
991    source: String,
992    kind: ObjectListErrorKind,
993}
994
995impl ObjectListError {
996    #[cfg(test)]
997    pub(crate) fn test_new() -> Self {
998        Self {
999            source: "foo".to_string(),
1000            kind: ObjectListErrorKind::Bar,
1001        }
1002    }
1003}
1004
1005impl Display for ObjectListError {
1006    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1007        use ObjectListErrorKind::*;
1008        let kind: &str = match &self.kind {
1009            KeyCount(_) => "key-count",
1010            Prefix(_) => "prefix",
1011            CommonPrefix(_) => "common-prefix",
1012            MaxKeys(_) => "max-keys",
1013            #[cfg(test)]
1014            Bar => "bar",
1015        };
1016        write!(f, "parse {kind} failed, gived str: {}", self.source)
1017    }
1018}
1019
1020impl Error for ObjectListError {
1021    fn source(&self) -> Option<&(dyn Error + 'static)> {
1022        use ObjectListErrorKind::*;
1023        match &self.kind {
1024            KeyCount(e) | MaxKeys(e) => Some(e),
1025            Prefix(e) | CommonPrefix(e) => Some(e),
1026            #[cfg(test)]
1027            Bar => None,
1028        }
1029    }
1030}
1031
1032impl ListError for ObjectListError {}
1033
1034/// decode xml to object list error collection
1035#[derive(Debug)]
1036#[non_exhaustive]
1037enum ObjectListErrorKind {
1038    /// when covert key_count failed ,return this error
1039    KeyCount(ParseIntError),
1040    /// when covert prefix failed ,return this error
1041    Prefix(InvalidObjectDir),
1042    /// when covert common_prefix failed ,return this error
1043    CommonPrefix(InvalidObjectDir),
1044    /// when covert max_keys failed ,return this error
1045    MaxKeys(ParseIntError),
1046    #[cfg(test)]
1047    Bar,
1048}
1049
1050impl Client {
1051    /// 查询默认 bucket 的文件列表
1052    ///
1053    /// 查询条件参数有多种方式,具体参考 [`get_object_list`] 文档
1054    ///
1055    /// [`get_object_list`]: crate::bucket::Bucket::get_object_list
1056    #[inline(always)]
1057    pub async fn get_object_list<Q: IntoIterator<Item = (QueryKey, QueryValue)>>(
1058        &self,
1059        query: Q,
1060    ) -> Result<ObjectList, ExtractListError> {
1061        self.get_object_list2(Query::from_iter(query)).await
1062    }
1063
1064    /// 查询默认 bucket 的文件列表
1065    pub async fn get_object_list2(&self, query: Query) -> Result<ObjectList, ExtractListError> {
1066        let bucket = BucketBase::new(self.bucket.to_owned(), self.endpoint.to_owned());
1067
1068        let (bucket_url, resource) = bucket.get_url_resource(&query);
1069
1070        let mut list = ObjectList::<ArcPointer> {
1071            object_list: Vec::with_capacity(query.get_max_keys()),
1072            bucket,
1073            ..Default::default()
1074        };
1075
1076        let response = self.builder(Method::GET, bucket_url, resource)?;
1077        let content = response.send_adjust_error().await?;
1078
1079        list.decode(
1080            &content.text().await?,
1081            ObjectList::<ArcPointer>::init_object,
1082        )?;
1083
1084        list.set_client(Arc::new(self.clone()));
1085        list.set_search_query(query);
1086
1087        Ok(list)
1088    }
1089
1090    /// # 可将 object 列表导出到外部类型(关注便捷性)
1091    ///
1092    /// 从 Client 中的默认 bucket 中获取,如需获取其他 bucket 的,可调用 `set_bucket` 更改后调用
1093    ///
1094    /// 也可以通过调用 `set_endpoint` 更改可用区
1095    ///
1096    /// 可以参考下面示例,或者项目中的 `examples/custom.rs`
1097    /// ## 示例
1098    /// ```rust
1099    /// use aliyun_oss_client::{
1100    ///     decode::{ListError, RefineObject, RefineObjectList},
1101    ///     object::{ExtractListError, InitObject},
1102    ///     Client,
1103    /// };
1104    /// use dotenv::dotenv;
1105    /// use thiserror::Error;
1106    ///
1107    /// #[derive(Debug)]
1108    /// struct MyFile {
1109    ///     key: String,
1110    ///     #[allow(dead_code)]
1111    ///     other: String,
1112    /// }
1113    /// impl RefineObject<MyError> for MyFile {
1114    ///     fn set_key(&mut self, key: &str) -> Result<(), MyError> {
1115    ///         self.key = key.to_string();
1116    ///         Ok(())
1117    ///     }
1118    /// }
1119    ///
1120    /// #[derive(Default, Debug)]
1121    /// struct MyBucket {
1122    ///     name: String,
1123    ///     files: Vec<MyFile>,
1124    /// }
1125    ///
1126    /// impl RefineObjectList<MyFile, MyError> for MyBucket {
1127    ///     fn set_name(&mut self, name: &str) -> Result<(), MyError> {
1128    ///         self.name = name.to_string();
1129    ///         Ok(())
1130    ///     }
1131    ///     fn set_list(&mut self, list: Vec<MyFile>) -> Result<(), MyError> {
1132    ///         self.files = list;
1133    ///         Ok(())
1134    ///     }
1135    /// }
1136    ///
1137    /// #[derive(Debug, Error)]
1138    /// #[error("my error")]
1139    /// enum MyError {}
1140    ///
1141    /// impl ListError for MyError {}
1142    ///
1143    /// async fn run() -> Result<(), ExtractListError> {
1144    ///     dotenv().ok();
1145    ///     use aliyun_oss_client::BucketName;
1146    ///
1147    ///     let client = Client::from_env().unwrap();
1148    ///
1149    ///     // 除了设置Default 外,还可以做更多设置
1150    ///     let mut bucket = MyBucket {
1151    ///         name: "abc".to_string(),
1152    ///         files: Vec::with_capacity(20),
1153    ///     };
1154    ///
1155    ///     // 利用闭包对 MyFile 做一下初始化设置
1156    ///     impl InitObject<MyFile> for MyBucket {
1157    ///         fn init_object(&mut self) -> Option<MyFile> {
1158    ///             Some(MyFile {
1159    ///               key: String::default(),
1160    ///               other: "abc".to_string(),
1161    ///             })
1162    ///         }
1163    ///     }
1164    ///
1165    ///     client.base_object_list([], &mut bucket).await?;
1166    ///
1167    ///     println!("bucket: {:?}", bucket);
1168    ///
1169    ///     Ok(())
1170    /// }
1171    /// ```
1172    #[inline]
1173    pub async fn base_object_list<
1174        Q: IntoIterator<Item = (QueryKey, QueryValue)>,
1175        List,
1176        Item,
1177        E: ListError,
1178        ItemErr: Error + 'static,
1179    >(
1180        &self,
1181        query: Q,
1182        list: &mut List,
1183    ) -> Result<(), ExtractListError>
1184    where
1185        List: RefineObjectList<Item, E, ItemErr> + InitObject<Item>,
1186        Item: RefineObject<ItemErr>,
1187    {
1188        let query = Query::from_iter(query);
1189
1190        self.base_object_list2(&query, list).await
1191    }
1192
1193    /// # 可将 object 列表导出到外部类型(关注性能)
1194    ///
1195    /// 从 Client 中的默认 bucket 中获取,如需获取其他 bucket 的,可调用 `set_bucket` 更改后调用
1196    ///
1197    /// 也可以通过调用 `set_endpoint` 更改可用区
1198    pub async fn base_object_list2<List, Item, E: ListError, ItemErr: Error + 'static>(
1199        &self,
1200        query: &Query,
1201        list: &mut List,
1202    ) -> Result<(), ExtractListError>
1203    where
1204        List: RefineObjectList<Item, E, ItemErr> + InitObject<Item>,
1205        Item: RefineObject<ItemErr>,
1206    {
1207        let bucket = self.get_bucket_base();
1208        let (bucket_url, resource) = bucket.get_url_resource(query);
1209
1210        let response = self.builder(Method::GET, bucket_url, resource)?;
1211        let content = response.send_adjust_error().await?;
1212
1213        list.decode(&content.text().await?, List::init_object)?;
1214
1215        Ok(())
1216    }
1217
1218    /// # 获取包含自定义类型的 object 集合
1219    /// 其包含在 [`ObjectList`] 对象中
1220    ///
1221    /// [`ObjectList`]: crate::object::ObjectList
1222    pub async fn get_custom_object<Item, ItemErr>(
1223        &self,
1224        query: &Query,
1225    ) -> Result<Objects<Item>, ExtractListError>
1226    where
1227        Item: RefineObject<ItemErr>,
1228        Objects<Item>: InitObject<Item>,
1229        ItemErr: Error + 'static,
1230    {
1231        let mut list = Objects::<Item>::default();
1232
1233        self.base_object_list2(query, &mut list).await?;
1234
1235        Ok(list)
1236    }
1237}
1238
1239/// 为 [`base_object_list`] 方法,返回一个统一的 Error
1240///
1241/// [`base_object_list`]: crate::client::Client::base_object_list
1242#[derive(Debug)]
1243#[non_exhaustive]
1244pub struct ExtractListError {
1245    pub(crate) kind: ExtractListErrorKind,
1246}
1247
1248impl ExtractListError {
1249    /// 判断 Error 类型是否为 "没有更多信息"
1250    pub fn is_no_more(&self) -> bool {
1251        matches!(self.kind, ExtractListErrorKind::NoMoreFile)
1252    }
1253}
1254
1255/// [`ExtractListError`] 类型的枚举
1256///
1257/// [`ExtractListError`]: crate::object::ExtractListError
1258#[derive(Debug)]
1259#[non_exhaustive]
1260pub(crate) enum ExtractListErrorKind {
1261    #[doc(hidden)]
1262    Builder(BuilderError),
1263
1264    #[doc(hidden)]
1265    Reqwest(reqwest::Error),
1266
1267    /// 解析 xml 错误
1268    Decode(InnerListError),
1269
1270    /// 用于 Stream
1271    NoMoreFile,
1272}
1273
1274impl From<InnerListError> for ExtractListError {
1275    fn from(value: InnerListError) -> Self {
1276        use ExtractListErrorKind::*;
1277        Self {
1278            kind: Decode(value),
1279        }
1280    }
1281}
1282impl From<BuilderError> for ExtractListError {
1283    fn from(value: BuilderError) -> Self {
1284        use ExtractListErrorKind::*;
1285        Self {
1286            kind: Builder(value),
1287        }
1288    }
1289}
1290impl From<reqwest::Error> for ExtractListError {
1291    fn from(value: reqwest::Error) -> Self {
1292        use ExtractListErrorKind::*;
1293        Self {
1294            kind: Reqwest(value),
1295        }
1296    }
1297}
1298impl Display for ExtractListError {
1299    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1300        use ExtractListErrorKind::*;
1301        match &self.kind {
1302            Builder(_) => "builder error".fmt(f),
1303            Reqwest(_) => "reqwest error".fmt(f),
1304            Decode(_) => "decode xml failed".fmt(f),
1305            NoMoreFile => "no more file".fmt(f),
1306        }
1307    }
1308}
1309impl Error for ExtractListError {
1310    fn source(&self) -> Option<&(dyn Error + 'static)> {
1311        use ExtractListErrorKind::*;
1312        match &self.kind {
1313            Builder(e) => Some(e),
1314            Reqwest(e) => Some(e),
1315            Decode(e) => e.get_source(),
1316            NoMoreFile => None,
1317        }
1318    }
1319}
1320
1321#[cfg(feature = "blocking")]
1322impl ClientRc {
1323    /// 查询默认 bucket 的文件列表
1324    ///
1325    /// 查询条件参数有多种方式,具体参考 [`get_object_list`](../bucket/struct.Bucket.html#method.get_object_list) 文档
1326    pub fn get_object_list<Q: IntoIterator<Item = (QueryKey, QueryValue)>>(
1327        self,
1328        query: Q,
1329    ) -> Result<ObjectList<RcPointer>, ExtractListError> {
1330        let query = Query::from_iter(query);
1331
1332        let bucket = BucketBase::new(self.bucket.to_owned(), self.endpoint.to_owned());
1333
1334        let (bucket_url, resource) = bucket.get_url_resource(&query);
1335
1336        let mut list = ObjectList::<RcPointer> {
1337            object_list: Vec::with_capacity(query.get_max_keys()),
1338            bucket,
1339            ..Default::default()
1340        };
1341
1342        let response = self.builder(Method::GET, bucket_url, resource)?;
1343        let content = response.send_adjust_error()?;
1344
1345        list.decode(&content.text()?, ObjectList::<RcPointer>::init_object)?;
1346
1347        list.set_client(Rc::new(self));
1348        list.set_search_query(query);
1349
1350        Ok(list)
1351    }
1352
1353    /// 可将 object 列表导出到外部 struct
1354    #[inline]
1355    pub fn base_object_list<
1356        Q: IntoIterator<Item = (QueryKey, QueryValue)>,
1357        List,
1358        Item,
1359        F,
1360        E: ListError,
1361        ItemErr: Error + 'static,
1362    >(
1363        &self,
1364        query: Q,
1365        list: &mut List,
1366        init_object: F,
1367    ) -> Result<(), ExtractListError>
1368    where
1369        List: RefineObjectList<Item, E, ItemErr>,
1370        Item: RefineObject<ItemErr>,
1371        F: Fn(&mut List) -> Option<Item>,
1372    {
1373        let bucket = BucketBase::new(self.bucket.clone(), self.endpoint.to_owned());
1374
1375        let query = Query::from_iter(query);
1376        let (bucket_url, resource) = bucket.get_url_resource(&query);
1377
1378        let response = self.builder(Method::GET, bucket_url, resource)?;
1379        let content = response.send_adjust_error()?;
1380
1381        list.decode(&content.text()?, init_object)?;
1382
1383        Ok(())
1384    }
1385}
1386
1387#[cfg(feature = "blocking")]
1388impl Iterator for ObjectList<RcPointer> {
1389    type Item = ObjectList<RcPointer>;
1390    fn next(&mut self) -> Option<Self> {
1391        if !self.next_continuation_token.is_empty() {
1392            self.search_query
1393                .insert(CONTINUATION_TOKEN, self.next_continuation_token.to_owned());
1394            self.get_object_list().ok()
1395        } else {
1396            None
1397        }
1398    }
1399}
1400
1401// use std::task::Poll::{self, Ready};
1402
1403// impl Stream for ObjectList<ArcPointer> {
1404//     type Item = ObjectList<ArcPointer>;
1405
1406//     fn poll_next(
1407//         self: std::pin::Pin<&mut Self>,
1408//         cx: &mut std::task::Context<'_>,
1409//     ) -> Poll<Option<Self::Item>> {
1410//         match self.next_query() {
1411//             Some(query) => {
1412//                 let mut url = self.bucket.to_url();
1413//                 url.set_search_query(&query);
1414
1415//                 let canonicalized = CanonicalizedResource::from_bucket_query(&self.bucket, &query);
1416
1417//                 let builder = self.builder(Method::GET, url, canonicalized);
1418//                 match builder {
1419//                     Err(err) => Ready(None),
1420//                     Ok(builder) => {
1421//                         let waker = cx.waker().clone();
1422
1423//                         std::thread::spawn(move || {
1424//                             let response = builder.send_adjust_error();
1425
1426//                             let response = futures::executor::block_on(response);
1427//                             let text = response.unwrap().text();
1428//                             let text = futures::executor::block_on(text);
1429
1430//                             let text = text.unwrap();
1431
1432//                             let bucket_arc = Arc::new(self.bucket);
1433
1434//                             let init_object = || {
1435//                                 let object = Object::<ArcPointer>::default();
1436//                                 object.base.set_bucket(bucket_arc.clone());
1437//                                 object
1438//                             };
1439
1440//                             self.decode(&text, init_object).unwrap();
1441
1442//                             self.set_search_query(query);
1443
1444//                             waker.wake();
1445//                         });
1446
1447//                         Poll::Pending
1448//                     }
1449//                 }
1450//             }
1451//             None => Ready(None),
1452//         }
1453//     }
1454// }
1455
1456#[oss_gen_rc]
1457impl PartialEq<Object<ArcPointer>> for Object<ArcPointer> {
1458    #[inline]
1459    fn eq(&self, other: &Object<ArcPointer>) -> bool {
1460        self.base == other.base
1461            && self.last_modified == other.last_modified
1462            && self.etag == other.etag
1463            && self._type == other._type
1464            && self.size == other.size
1465            && self.storage_class == other.storage_class
1466    }
1467}
1468
1469impl<T: PointerFamily> PartialEq<DateTime<Utc>> for Object<T> {
1470    #[inline]
1471    fn eq(&self, other: &DateTime<Utc>) -> bool {
1472        &self.last_modified == other
1473    }
1474}
1475
1476impl<T: PointerFamily> PartialEq<u64> for Object<T> {
1477    #[inline]
1478    fn eq(&self, other: &u64) -> bool {
1479        &self.size == other
1480    }
1481}
1482
1483#[oss_gen_rc]
1484impl PartialEq<ObjectBase<ArcPointer>> for Object<ArcPointer> {
1485    #[inline]
1486    fn eq(&self, other: &ObjectBase<ArcPointer>) -> bool {
1487        &self.base == other
1488    }
1489}
1490
1491/// 未来计划支持的功能
1492#[derive(Default)]
1493#[doc(hidden)]
1494pub struct PutObject<'a> {
1495    pub forbid_overwrite: bool,
1496    pub server_side_encryption: Option<Encryption>,
1497    pub server_side_data_encryption: Option<Encryption>,
1498    pub server_side_encryption_key_id: Option<&'a str>,
1499    pub object_acl: ObjectAcl,
1500    pub storage_class: StorageClass,
1501    pub tagging: Option<&'a str>,
1502}
1503
1504/// 未来计划支持的功能
1505#[derive(Default)]
1506#[doc(hidden)]
1507pub enum Encryption {
1508    #[default]
1509    Aes256,
1510    Kms,
1511    Sm4,
1512}
1513
1514/// 未来计划支持的功能
1515#[derive(Default)]
1516#[doc(hidden)]
1517pub enum ObjectAcl {
1518    #[default]
1519    Default,
1520    Private,
1521    PublicRead,
1522    PublicReadWrite,
1523}
1524
1525/// 存储类型
1526#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
1527#[non_exhaustive]
1528pub struct StorageClass {
1529    kind: StorageClassKind,
1530}
1531
1532#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
1533#[non_exhaustive]
1534enum StorageClassKind {
1535    /// Standard 默认
1536    #[default]
1537    Standard,
1538    /// IA
1539    IA,
1540    /// Archive
1541    Archive,
1542    /// ColdArchive
1543    ColdArchive,
1544}
1545
1546impl StorageClass {
1547    /// Archive
1548    pub const ARCHIVE: Self = Self {
1549        kind: StorageClassKind::Archive,
1550    };
1551    /// IA
1552    pub const IA: Self = Self {
1553        kind: StorageClassKind::IA,
1554    };
1555    /// Standard
1556    pub const STANDARD: Self = Self {
1557        kind: StorageClassKind::Standard,
1558    };
1559    /// ColdArchive
1560    pub const COLD_ARCHIVE: Self = Self {
1561        kind: StorageClassKind::ColdArchive,
1562    };
1563
1564    /// init StorageClass
1565    pub fn new(s: &str) -> Option<StorageClass> {
1566        let start_char = s.chars().next()?;
1567
1568        let kind = match start_char {
1569            'a' | 'A' => StorageClassKind::Archive,
1570            'i' | 'I' => StorageClassKind::IA,
1571            's' | 'S' => StorageClassKind::Standard,
1572            'c' | 'C' => StorageClassKind::ColdArchive,
1573            _ => return None,
1574        };
1575        Some(Self { kind })
1576    }
1577}
1578
1579/// 未来计划支持的功能
1580#[derive(Default)]
1581#[doc(hidden)]
1582pub struct CopyObject<'a> {
1583    pub forbid_overwrite: bool,
1584    pub copy_source: &'a str,
1585    pub copy_source_if_match: Option<&'a str>,
1586    pub copy_source_if_none_match: Option<&'a str>,
1587    pub copy_source_if_unmodified_since: Option<&'a str>,
1588    pub copy_source_if_modified_since: Option<&'a str>,
1589    pub metadata_directive: CopyDirective,
1590    pub server_side_encryption: Option<Encryption>,
1591    pub server_side_encryption_key_id: Option<&'a str>,
1592    pub object_acl: ObjectAcl,
1593    pub storage_class: StorageClass,
1594    pub tagging: Option<&'a str>,
1595    pub tagging_directive: CopyDirective,
1596}
1597
1598/// 未来计划支持的功能
1599#[derive(Default)]
1600#[doc(hidden)]
1601pub enum CopyDirective {
1602    #[default]
1603    Copy,
1604    Replace,
1605}