• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tu6ge / oss-rs / 5287224613

pending completion
5287224613

push

github

tu6ge
fix(test)

2 of 2 new or added lines in 1 file covered. (100.0%)

6202 of 6429 relevant lines covered (96.47%)

9.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.82
/src/object.rs
1
//! # Object 相关功能
4✔
2
//! `ObjectList` 对应文件列表,`Object` 对应的是单个文件对象
3
//!
4
//! `ObjectList` 也可以支持自定义的类型存储单个文件对象,例如 [issue 12](https://github.com/tu6ge/oss-rs/issues/12) 提到的,有些时候,
5
//! Oss 接口不仅返回文件路径,还会返回目录路径,可以使用如下例子进行适配
6
//!
7
//! ```rust,no_run
8
//! use aliyun_oss_client::{
9
//!     decode::RefineObject,
10
//!     object::Objects,
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<MyError> for MyObject {
23
//!     fn set_key(&mut self, key: &str) -> Result<(), MyError> {
24
//!         let res = key.parse::<ObjectPath>();
25
//!
26
//!         *self = match res {
27
//!             Ok(file) => MyObject::File(file),
28
//!             _ => {
29
//!                 let re = key.parse::<ObjectDir>();
30
//!                 MyObject::Dir(re.unwrap())
31
//!             }
32
//!         };
33
//!
34
//!         Ok(())
35
//!     }
36
//! }
37
//!
38
//! #[derive(Debug)]
39
//! struct MyError(String);
40
//!
41
//! use std::fmt::{self, Display};
42
//!
43
//! impl Display for MyError {
44
//!     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45
//!         f.write_fmt(format_args!("{}", self.0))
46
//!     }
47
//! }
48
//! impl std::error::Error for MyError {}
49
//!
50
//! impl From<InvalidObjectDir> for MyError {
51
//!     fn from(value: InvalidObjectDir) -> Self {
52
//!         Self(value.to_string())
53
//!     }
54
//! }
55
//!
56
//! type MyList = Objects<MyObject, MyError>;
57
//!
58
//! #[tokio::main]
59
//! async fn main() {
60
//!     dotenv().ok();
61
//!
62
//!     let client = Client::from_env().unwrap();
63
//!
64
//!     let mut list = MyList::default();
65
//!
66
//!     let init_object = || MyObject::File(ObjectPath::default());
67
//!
68
//!     let _ = client
69
//!         .base_object_list(
70
//!             "xxxxxx".parse::<BucketName>().unwrap(),
71
//!             [],
72
//!             &mut list,
73
//!             init_object,
74
//!         )
75
//!         .await;
76
//!
77
//!     println!("list: {:?}", list.to_vec());
78
//! }
79
//! ```
80

81
use crate::bucket::Bucket;
82
#[cfg(feature = "blocking")]
83
use crate::builder::RcPointer;
84
use crate::builder::{ArcPointer, BuilderError, PointerFamily};
85
use crate::client::ClientArc;
86
#[cfg(feature = "blocking")]
87
use crate::client::ClientRc;
88
use crate::config::{get_url_resource_with_bucket, BucketBase};
89
use crate::decode::{InnerListError, ListError, RefineObject, RefineObjectList};
90
#[cfg(feature = "blocking")]
91
use crate::file::blocking::AlignBuilder as BlockingAlignBuilder;
92
use crate::file::AlignBuilder;
93
use crate::types::object::ObjectPathInner;
94
use crate::types::{
95
    core::SetOssQuery,
96
    object::{
97
        CommonPrefixes, InvalidObjectDir, InvalidObjectPath, ObjectBase, ObjectDir, ObjectPath,
98
    },
99
    CanonicalizedResource, Query, QueryKey, QueryValue, CONTINUATION_TOKEN,
100
};
101
use crate::{BucketName, Client, EndPoint, KeyId, KeySecret};
102
use async_stream::try_stream;
103
use chrono::{DateTime, NaiveDateTime, Utc};
104
use futures_core::stream::Stream;
105
use http::Method;
106
use oss_derive::oss_gen_rc;
107
use url::Url;
108

109
use std::error::Error;
110
use std::fmt::{self, Display};
111
use std::marker::PhantomData;
112
use std::num::ParseIntError;
113
#[cfg(feature = "blocking")]
114
use std::rc::Rc;
115
use std::sync::Arc;
116
use std::vec::IntoIter;
117

118
#[cfg(test)]
119
mod test;
120

121
/// # 存放对象列表的结构体
122
/// before name is `ObjectList`
123
/// TODO impl core::ops::Index
124
#[derive(Clone)]
125
#[non_exhaustive]
126
pub struct ObjectList<
127
    P: PointerFamily = ArcPointer,
128
    Item: RefineObject<E> = Object<P>,
129
    E: Error + 'static = BuildInItemError,
130
> {
131
    pub(crate) bucket: BucketBase,
132
    prefix: Option<ObjectDir<'static>>,
133
    max_keys: u32,
134
    key_count: u64,
135
    /// 存放单个文件对象的 Vec 集合
136
    object_list: Vec<Item>,
137
    next_continuation_token: String,
138
    common_prefixes: CommonPrefixes,
139
    client: P::PointerType,
140
    search_query: Query,
141
    ph_err: PhantomData<E>,
142
}
143

144
/// sync ObjectList alias
145
pub type Objects<Item = Object<ArcPointer>, Error = BuildInItemError> =
146
    ObjectList<ArcPointer, Item, Error>;
147
/// blocking ObjectList alias
148
#[cfg(feature = "blocking")]
149
pub type ObjectsBlocking<Item = Object<RcPointer>, Error = BuildInItemError> =
150
    ObjectList<RcPointer, Item, Error>;
151

152
impl<T: PointerFamily, Item: RefineObject<E>, E: Error> fmt::Debug for ObjectList<T, Item, E> {
153
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1✔
154
        f.debug_struct("ObjectList")
7✔
155
            .field("bucket", &self.bucket)
1✔
156
            .field("prefix", &self.prefix)
157
            .field("max_keys", &self.max_keys)
1✔
158
            .field("key_count", &self.key_count)
1✔
159
            .field("next_continuation_token", &self.next_continuation_token)
1✔
160
            .field("common_prefixes", &self.common_prefixes)
1✔
161
            .field("search_query", &self.search_query)
1✔
162
            .finish()
163
    }
1✔
164
}
165

166
impl<T: PointerFamily, Item: RefineObject<E>, E: Error> Default for ObjectList<T, Item, E> {
167
    fn default() -> Self {
15✔
168
        Self {
15✔
169
            bucket: BucketBase::default(),
15✔
170
            prefix: Option::default(),
15✔
171
            max_keys: u32::default(),
15✔
172
            key_count: u64::default(),
15✔
173
            object_list: Vec::new(),
15✔
174
            next_continuation_token: String::default(),
15✔
175
            common_prefixes: CommonPrefixes::default(),
15✔
176
            client: T::PointerType::default(),
15✔
177
            search_query: Query::default(),
15✔
178
            ph_err: PhantomData,
179
        }
180
    }
15✔
181
}
182

183
impl<T: PointerFamily, Item: RefineObject<E>, E: Error> AsMut<Query> for ObjectList<T, Item, E> {
184
    fn as_mut(&mut self) -> &mut Query {
185
        &mut self.search_query
186
    }
187
}
188

189
impl<T: PointerFamily, Item: RefineObject<E>, E: Error> AsRef<BucketBase>
190
    for ObjectList<T, Item, E>
191
{
192
    fn as_ref(&self) -> &BucketBase {
193
        &self.bucket
194
    }
195
}
196

197
impl<T: PointerFamily, Item: RefineObject<E>, E: Error> AsRef<BucketName>
198
    for ObjectList<T, Item, E>
199
{
200
    fn as_ref(&self) -> &BucketName {
201
        self.bucket.as_ref()
202
    }
203
}
204

205
impl<T: PointerFamily, Item: RefineObject<E>, E: Error> AsRef<EndPoint> for ObjectList<T, Item, E> {
206
    fn as_ref(&self) -> &EndPoint {
207
        self.bucket.as_ref()
208
    }
209
}
210

211
impl<T: PointerFamily, Item: RefineObject<E>, E: Error> ObjectList<T, Item, E> {
212
    /// 文件列表的初始化方法
213
    #[allow(clippy::too_many_arguments)]
214
    pub fn new<Q: IntoIterator<Item = (QueryKey, QueryValue)>>(
8✔
215
        bucket: BucketBase,
216
        prefix: Option<ObjectDir<'static>>,
217
        max_keys: u32,
218
        key_count: u64,
219
        object_list: Vec<Item>,
220
        next_continuation_token: Option<String>,
221
        client: T::PointerType,
222
        search_query: Q,
223
    ) -> Self {
224
        Self {
8✔
225
            bucket,
226
            prefix,
227
            max_keys,
228
            key_count,
229
            object_list,
230
            next_continuation_token: next_continuation_token.unwrap_or_default(),
8✔
231
            common_prefixes: CommonPrefixes::default(),
8✔
232
            client,
233
            search_query: Query::from_iter(search_query),
8✔
234
            ph_err: PhantomData,
235
        }
236
    }
8✔
237

238
    /// 返回 bucket 元信息的引用
239
    pub fn bucket(&self) -> &BucketBase {
11✔
240
        &self.bucket
11✔
241
    }
11✔
242

243
    /// 返回 prefix 的引用
244
    pub fn prefix(&self) -> &Option<ObjectDir<'static>> {
6✔
245
        &self.prefix
246
    }
6✔
247

248
    /// 获取文件夹下的子文件夹名,子文件夹下递归的所有文件和文件夹不包含在这里。
249
    pub fn common_prefixes(&self) -> &CommonPrefixes {
7✔
250
        &self.common_prefixes
7✔
251
    }
7✔
252

253
    /// 设置 common_prefixes 信息
254
    pub fn set_common_prefixes<P: IntoIterator<Item = ObjectDir<'static>>>(&mut self, prefixes: P) {
1✔
255
        self.common_prefixes = CommonPrefixes::from_iter(prefixes);
1✔
256
    }
1✔
257

258
    /// 返回 max_keys
259
    pub fn max_keys(&self) -> &u32 {
7✔
260
        &self.max_keys
7✔
261
    }
7✔
262

263
    /// 返回 key_count
264
    pub fn key_count(&self) -> &u64 {
5✔
265
        &self.key_count
5✔
266
    }
5✔
267

268
    /// # 返回下一个 continuation_token
269
    /// 用于翻页使用
270
    pub fn next_continuation_token_str(&self) -> &String {
7✔
271
        &self.next_continuation_token
7✔
272
    }
7✔
273

274
    /// 返回查询条件
275
    pub fn search_query(&self) -> &Query {
5✔
276
        &self.search_query
5✔
277
    }
5✔
278

279
    /// # 下一页的查询条件
280
    ///
281
    /// 如果有下一页,返回 Some(Query)
282
    /// 如果没有下一页,则返回 None
283
    pub fn next_query(&self) -> Option<Query> {
2✔
284
        if !self.next_continuation_token.is_empty() {
2✔
285
            let mut search_query = self.search_query.clone();
1✔
286
            search_query.insert(CONTINUATION_TOKEN, self.next_continuation_token.to_owned());
1✔
287
            Some(search_query)
1✔
288
        } else {
289
            None
1✔
290
        }
291
    }
2✔
292

293
    /// 将 object 列表转化为迭代器
294
    pub fn object_iter(self) -> IntoIter<Item> {
1✔
295
        self.object_list.into_iter()
1✔
296
    }
1✔
297
}
298

299
#[oss_gen_rc]
2✔
300
impl<Item: RefineObject<E>, E: Error> ObjectList<ArcPointer, Item, E> {
301
    /// 设置 Client
302
    pub(crate) fn set_client(&mut self, client: Arc<ClientArc>) {
2✔
303
        self.client = client;
2✔
304
    }
2✔
305

306
    pub(crate) fn from_bucket(
4✔
307
        bucket: &Bucket<ArcPointer>,
308
        capacity: usize,
309
    ) -> ObjectList<ArcPointer> {
310
        ObjectList::<ArcPointer> {
4✔
311
            bucket: bucket.base.clone(),
4✔
312
            client: Arc::clone(&bucket.client),
3✔
313
            object_list: Vec::with_capacity(capacity),
4✔
314
            ..Default::default()
4✔
315
        }
316
    }
4✔
317

318
    /// 获取 Client 引用
319
    pub(crate) fn client(&self) -> Arc<ClientArc> {
1✔
320
        Arc::clone(&self.client)
1✔
321
    }
1✔
322
}
323

324
impl ObjectList<ArcPointer> {
325
    /// 异步获取下一页的数据
326
    pub async fn get_next_list(&self) -> Result<ObjectList<ArcPointer>, ExtractListError> {
×
327
        match self.next_query() {
328
            None => Err(ExtractListError {
329
                kind: ExtractListErrorKind::NoMoreFile,
330
            }),
331
            Some(query) => {
332
                let mut url = self.bucket.to_url();
333
                url.set_oss_query(&query);
334

335
                let canonicalized = CanonicalizedResource::from_bucket_query(&self.bucket, &query);
336

337
                let response = self
338
                    .builder(Method::GET, url, canonicalized)?
339
                    .send_adjust_error()
340
                    .await?;
341

342
                let mut list = ObjectList::<ArcPointer> {
343
                    client: self.client(),
344
                    bucket: self.bucket.clone(),
345
                    object_list: Vec::with_capacity(query.get_max_keys()),
346
                    ..Default::default()
347
                };
348

349
                list.decode(&response.text().await?, || {
350
                    Object::from_bucket(Arc::new(self.bucket.clone()))
351
                })?;
352

353
                list.set_search_query(query);
354
                Ok(list)
355
            }
356
        }
357
    }
×
358

359
    /// # 将 object_list 转化为 stream, 返回第二页,第三页... 的内容
360
    ///
361
    /// *不够完善,最后一次迭代返回的是 `Some(Err(OssError::WithoutMore))`,而不是 `None`*
362
    ///
363
    /// ## 用法
364
    ///
365
    /// 1. 添加依赖
366
    /// ```toml
367
    /// [dependencies]
368
    /// futures="0.3"
369
    /// ```
370
    /// 2. 将返回结果 pin 住
371
    /// ```no_run
372
    /// # use dotenv::dotenv;
373
    /// # use aliyun_oss_client::Client;
374
    /// # #[tokio::main]
375
    /// # async fn main() {
376
    /// # dotenv().ok();
377
    /// use futures::{pin_mut, StreamExt};
378
    /// # let client = Client::from_env().unwrap();
379
    /// # let query = [("max-keys".into(), 100u8.into())];
380
    /// # let object_list = client.get_object_list(query).await.unwrap();
381
    /// let stream = object_list.into_stream();
382
    /// pin_mut!(stream);
383
    ///
384
    /// let second_list = stream.next().await;
385
    /// let third_list = stream.next().await;
386
    /// println!("second_list: {:?}", second_list);
387
    /// println!("third_list: {:?}", third_list);
388
    /// # }
389
    /// ```
390
    pub fn into_stream(self) -> impl Stream<Item = Result<Self, ExtractListError>> {
×
391
        try_stream! {
×
392
            let result = self.get_next_list().await?;
393
            yield result;
394
        }
395
    }
×
396
}
397

398
impl<Item: RefineObject<E>, E: Error + 'static> ObjectList<ArcPointer, Item, E> {
399
    /// 自定义 Item 时,获取下一页数据
400
    pub async fn get_next_base<F>(&self, init_object: F) -> Result<Self, ExtractListError>
401
    where
402
        F: FnMut() -> Item,
403
    {
404
        match self.next_query() {
405
            None => Err(ExtractListError {
406
                kind: ExtractListErrorKind::NoMoreFile,
407
            }),
408
            Some(query) => {
409
                let mut list = Self::default();
410
                let name = self.bucket.get_name().clone();
411
                self.client()
412
                    .base_object_list(name, query, &mut list, init_object)
413
                    .await?;
414

415
                Ok(list)
416
            }
417
        }
418
    }
419
}
420

421
#[cfg(feature = "blocking")]
422
impl ObjectList<RcPointer> {
423
    fn clone_base(&self) -> Self {
1✔
424
        Self {
1✔
425
            client: Rc::clone(&self.client),
1✔
426
            bucket: self.bucket.clone(),
1✔
427
            search_query: self.search_query.clone(),
1✔
428
            max_keys: self.max_keys,
1✔
429
            object_list: Vec::with_capacity(self.max_keys as usize),
1✔
430
            ..Default::default()
1✔
431
        }
432
    }
1✔
433
    /// 从 OSS 获取 object 列表信息
434
    pub fn get_object_list(&mut self) -> Result<Self, ExtractListError> {
1✔
435
        let name = self.bucket.get_name();
1✔
436

437
        let client = self.client();
1✔
438

439
        let mut list = ObjectList::<RcPointer>::clone_base(self);
1✔
440

441
        let init_object = || Object::<RcPointer>::from_bucket(Rc::new(self.bucket.clone()));
2✔
442

443
        client
2✔
444
            .base_object_list(
445
                name.to_owned(),
1✔
446
                self.search_query.clone(),
1✔
447
                &mut list,
448
                init_object,
449
            )
450
            .map_err(ExtractListError::from)?;
×
451

452
        Ok(list)
1✔
453
    }
1✔
454
}
455

456
impl<T: PointerFamily, Item: RefineObject<E>, E: Error + 'static> ObjectList<T, Item, E> {
457
    /// 设置查询条件
458
    #[inline]
459
    pub fn set_search_query(&mut self, search_query: Query) {
4✔
460
        self.search_query = search_query;
4✔
461
    }
4✔
462

463
    /// 设置 bucket 元信息
464
    pub fn set_bucket(&mut self, bucket: BucketBase) {
1✔
465
        self.bucket = bucket;
1✔
466
    }
1✔
467

468
    /// 获取 bucket 名称
469
    pub fn bucket_name(&self) -> &str {
1✔
470
        self.bucket.name()
1✔
471
    }
1✔
472

473
    /// 返回 object 的 Vec 集合
474
    pub fn to_vec(self) -> Vec<Item> {
475
        self.object_list
476
    }
477

478
    /// 返回文件数量
479
    pub fn len(&self) -> usize {
480
        self.object_list.len()
481
    }
482

483
    /// 返回是否存在文件
484
    pub fn is_empty(&self) -> bool {
485
        self.object_list.is_empty()
486
    }
487
}
488

489
/// 存放单个对象的结构体
490
#[derive(Clone, Debug, Hash)]
491
#[non_exhaustive]
492
pub struct Object<PointerSel: PointerFamily = ArcPointer> {
493
    pub(crate) base: ObjectBase<PointerSel>,
494
    last_modified: DateTime<Utc>,
495
    etag: String,
496
    _type: String,
497
    size: u64,
498
    storage_class: StorageClass,
499
}
500

501
/// 异步的 Object struct
502
pub type ObjectArc = Object<ArcPointer>;
503

504
impl<T: PointerFamily> Default for Object<T> {
505
    fn default() -> Self {
20✔
506
        Object {
20✔
507
            base: ObjectBase::<T>::default(),
20✔
508
            last_modified: DateTime::<Utc>::from_utc(
20✔
509
                #[allow(clippy::unwrap_used)]
510
                NaiveDateTime::from_timestamp_opt(0, 0).unwrap(),
20✔
511
                Utc,
512
            ),
513
            etag: String::default(),
20✔
514
            _type: String::default(),
20✔
515
            size: 0,
516
            storage_class: StorageClass::default(),
20✔
517
        }
518
    }
20✔
519
}
520

521
impl<T: PointerFamily> AsRef<ObjectPath> for Object<T> {
522
    fn as_ref(&self) -> &ObjectPath {
1✔
523
        self.base.as_ref()
1✔
524
    }
1✔
525
}
526

527
impl<T: PointerFamily> AsRef<DateTime<Utc>> for Object<T> {
528
    fn as_ref(&self) -> &DateTime<Utc> {
529
        &self.last_modified
530
    }
531
}
532

533
impl<T: PointerFamily> AsRef<StorageClass> for Object<T> {
534
    fn as_ref(&self) -> &StorageClass {
535
        &self.storage_class
536
    }
537
}
538

539
impl<T: PointerFamily> Object<T> {
540
    /// 初始化 Object 结构体
541
    pub fn new(
12✔
542
        bucket: T::Bucket,
543
        path: ObjectPath,
544
        last_modified: DateTime<Utc>,
545
        etag: String,
546
        _type: String,
547
        size: u64,
548
        storage_class: StorageClass,
549
    ) -> Self {
550
        let base = ObjectBase::<T>::new2(bucket, path);
12✔
551
        Self {
12✔
552
            base,
12✔
553
            last_modified,
554
            etag,
555
            _type,
556
            size,
557
            storage_class,
558
        }
559
    }
12✔
560

561
    pub(crate) fn from_bucket(bucket: T::Bucket) -> Self {
8✔
562
        Self {
8✔
563
            base: ObjectBase::<T>::init_with_bucket(bucket),
8✔
564
            ..Default::default()
8✔
565
        }
566
    }
8✔
567

568
    /// 读取 Object 元信息
569
    #[inline]
570
    pub fn base(&self) -> &ObjectBase<T> {
571
        &self.base
572
    }
573

574
    /// 设置 Object 元信息
575
    #[inline]
576
    pub fn set_base(&mut self, base: ObjectBase<T>) {
1✔
577
        self.base = base;
1✔
578
    }
1✔
579

580
    /// 读取最后修改时间
581
    #[inline]
582
    pub fn last_modified(&self) -> &DateTime<Utc> {
583
        &self.last_modified
584
    }
585

586
    /// 设置最后修改时间
587
    #[inline]
588
    pub fn set_last_modified(&mut self, last_modified: DateTime<Utc>) {
589
        self.last_modified = last_modified;
590
    }
591

592
    /// 读取 etag 信息
593
    #[inline]
594
    pub fn etag(&self) -> &String {
595
        &self.etag
596
    }
597

598
    /// 设置 etag
599
    #[inline]
600
    pub fn set_etag(&mut self, etag: String) {
601
        self.etag = etag
602
    }
603

604
    /// 读取 type
605
    #[inline]
606
    pub fn get_type_string(&self) -> &String {
607
        &self._type
608
    }
609

610
    /// 设置 type
611
    #[inline]
612
    pub fn set_type_string(&mut self, _type: String) {
613
        self._type = _type;
614
    }
615

616
    /// 读取文件 size
617
    #[inline]
618
    pub fn size(&self) -> u64 {
619
        self.size
620
    }
621

622
    /// 设置文件 size
623
    #[inline]
624
    pub fn set_size(&mut self, size: u64) {
625
        self.size = size;
626
    }
627

628
    /// 读取 storage_class
629
    #[inline]
630
    pub fn storage_class(&self) -> &StorageClass {
631
        &self.storage_class
632
    }
633

634
    /// 设置 storage_class
635
    #[inline]
636
    pub fn set_storage_class(&mut self, storage_class: StorageClass) {
637
        self.storage_class = storage_class;
638
    }
639

640
    /// 获取一部分数据
641
    pub fn pieces(
642
        self,
643
    ) -> (
644
        ObjectBase<T>,
645
        DateTime<Utc>,
646
        String,
647
        String,
648
        u64,
649
        StorageClass,
650
    ) {
651
        (
652
            self.base,
653
            self.last_modified,
654
            self.etag,
655
            self._type,
656
            self.size,
657
            self.storage_class,
658
        )
659
    }
660

661
    /// 读取 文件路径
662
    pub fn path(&self) -> ObjectPath {
663
        self.base.path()
664
    }
665

666
    #[doc(hidden)]
667
    pub fn path_string(&self) -> String {
668
        self.base.path().to_string()
669
    }
670
}
671

672
impl Object<ArcPointer> {
673
    #[cfg(test)]
674
    pub fn test_path(path: &'static str) -> Self {
1✔
675
        let mut object = Self::default();
1✔
676
        object.set_base(ObjectBase::<ArcPointer>::new2(
1✔
677
            Arc::new(BucketBase::default()),
1✔
678
            path.try_into().unwrap(),
1✔
679
        ));
680
        object
681
    }
1✔
682
}
683

684
impl<T: PointerFamily> From<Object<T>> for ObjectPathInner<'static> {
685
    #[inline]
686
    fn from(obj: Object<T>) -> Self {
687
        obj.base.path
688
    }
689
}
690

691
#[oss_gen_rc]
×
692
impl Object<ArcPointer> {
693
    /// # Object 构建器
694
    /// 用例
695
    /// ```
696
    /// # use aliyun_oss_client::{config::BucketBase, ObjectPath, object::{ObjectArc, StorageClass},EndPoint};
697
    /// # use chrono::{DateTime, NaiveDateTime, Utc};
698
    /// let bucket = BucketBase::new(
699
    ///     "bucket-name".parse().unwrap(),
700
    ///     EndPoint::CN_QINGDAO,
701
    /// );
702
    /// let mut builder = ObjectArc::builder("abc".parse::<ObjectPath>().unwrap());
703
    ///
704
    /// builder
705
    ///     .bucket_base(bucket)
706
    ///     .last_modified(DateTime::<Utc>::from_utc(
707
    ///         NaiveDateTime::from_timestamp_opt(123000, 0).unwrap(),
708
    ///         Utc,
709
    ///     ))
710
    ///     .etag("foo1".to_owned())
711
    ///     .set_type("foo2".to_owned())
712
    ///     .size(123)
713
    ///     .storage_class(StorageClass::IA);
714
    ///
715
    /// let object = builder.build();
716
    /// ```
717
    pub fn builder(path: ObjectPath) -> ObjectBuilder<ArcPointer> {
5✔
718
        ObjectBuilder::<ArcPointer>::new(Arc::default(), path)
5✔
719
    }
5✔
720

721
    /// 带签名的 Url 链接
722
    pub fn to_sign_url(&self, key: &KeyId, secret: &KeySecret, expires: i64) -> Url {
1✔
723
        self.base.to_sign_url(key, secret, expires)
1✔
724
    }
1✔
725
}
726

727
/// Object 结构体的构建器
728
pub struct ObjectBuilder<T: PointerFamily = ArcPointer> {
729
    object: Object<T>,
730
}
731

732
impl<T: PointerFamily> ObjectBuilder<T> {
733
    /// 初始化 Object 构建器
734
    pub fn new(bucket: T::Bucket, path: ObjectPath) -> Self {
5✔
735
        let base = ObjectBase::<T>::new2(bucket, path);
5✔
736
        Self {
5✔
737
            object: Object {
5✔
738
                base,
5✔
739
                last_modified: DateTime::<Utc>::from_utc(
5✔
740
                    #[allow(clippy::unwrap_used)]
741
                    NaiveDateTime::from_timestamp_opt(0, 0).unwrap(),
5✔
742
                    Utc,
743
                ),
744
                ..Default::default()
5✔
745
            },
746
        }
747
    }
5✔
748

749
    /// 设置元信息
750
    pub fn bucket(&mut self, bucket: T::Bucket) -> &mut Self {
1✔
751
        self.object.base.set_bucket(bucket);
1✔
752
        self
753
    }
1✔
754

755
    /// 设置 last_modified
756
    pub fn last_modified(&mut self, date: DateTime<Utc>) -> &mut Self {
1✔
757
        self.object.last_modified = date;
1✔
758
        self
759
    }
1✔
760

761
    /// 设置 etag
762
    pub fn etag(&mut self, etag: String) -> &mut Self {
1✔
763
        self.object.etag = etag;
1✔
764
        self
765
    }
1✔
766

767
    /// 设置 type
768
    pub fn set_type(&mut self, _type: String) -> &mut Self {
1✔
769
        self.object._type = _type;
1✔
770
        self
771
    }
1✔
772

773
    /// 设置 size
774
    pub fn size(&mut self, size: u64) -> &mut Self {
1✔
775
        self.object.size = size;
1✔
776
        self
777
    }
1✔
778

779
    /// 设置 storage_class
780
    pub fn storage_class(&mut self, storage_class: StorageClass) -> &mut Self {
1✔
781
        self.object.storage_class = storage_class;
1✔
782
        self
783
    }
1✔
784

785
    /// 返回 object
786
    pub fn build(self) -> Object<T> {
3✔
787
        self.object
3✔
788
    }
3✔
789
}
790

791
#[oss_gen_rc]
×
792
impl ObjectBuilder<ArcPointer> {
793
    /// 设置元信息
794
    pub fn bucket_base(&mut self, base: BucketBase) -> &mut Self {
4✔
795
        self.object.base.set_bucket(Arc::new(base));
4✔
796
        self
797
    }
4✔
798
}
799

800
impl<T: PointerFamily + Sized> RefineObject<BuildInItemError> for Object<T> {
801
    #[inline]
802
    fn set_key(&mut self, key: &str) -> Result<(), BuildInItemError> {
8✔
803
        self.base
24✔
804
            .set_path(key.to_owned())
8✔
805
            .map_err(|e| BuildInItemError {
10✔
806
                source: key.to_string(),
1✔
807
                kind: BuildInItemErrorKind::BasePath(e),
1✔
808
            })
1✔
809
    }
8✔
810

811
    #[inline]
812
    fn set_last_modified(&mut self, value: &str) -> Result<(), BuildInItemError> {
8✔
813
        self.last_modified = value.parse().map_err(|e| BuildInItemError {
10✔
814
            source: value.to_string(),
1✔
815
            kind: BuildInItemErrorKind::LastModified(e),
1✔
816
        })?;
2✔
817
        Ok(())
7✔
818
    }
8✔
819

820
    #[inline]
821
    fn set_etag(&mut self, value: &str) -> Result<(), BuildInItemError> {
7✔
822
        self.etag = value.to_string();
7✔
823
        Ok(())
7✔
824
    }
7✔
825

826
    #[inline]
827
    fn set_type(&mut self, value: &str) -> Result<(), BuildInItemError> {
7✔
828
        self._type = value.to_string();
7✔
829
        Ok(())
7✔
830
    }
7✔
831

832
    #[inline]
833
    fn set_size(&mut self, size: &str) -> Result<(), BuildInItemError> {
8✔
834
        self.size = size.parse().map_err(|e| BuildInItemError {
12✔
835
            source: size.to_string(),
2✔
836
            kind: BuildInItemErrorKind::Size(e),
2✔
837
        })?;
4✔
838
        Ok(())
6✔
839
    }
8✔
840

841
    #[inline]
842
    fn set_storage_class(&mut self, storage_class: &str) -> Result<(), BuildInItemError> {
8✔
843
        self.storage_class = StorageClass::new(storage_class).ok_or(BuildInItemError {
16✔
844
            source: storage_class.to_string(),
8✔
845
            kind: BuildInItemErrorKind::InvalidStorageClass,
8✔
846
        })?;
1✔
847
        Ok(())
7✔
848
    }
8✔
849
}
850

851
/// Xml 转化为内置 Object 时的错误集合
852
#[derive(Debug)]
10✔
853
#[non_exhaustive]
854
pub struct BuildInItemError {
855
    source: String,
856
    kind: BuildInItemErrorKind,
5✔
857
}
858

859
impl BuildInItemError {
860
    #[cfg(test)]
861
    pub(crate) fn test_new() -> Self {
2✔
862
        Self {
2✔
863
            source: "foo".to_string(),
2✔
864
            kind: BuildInItemErrorKind::InvalidStorageClass,
2✔
865
        }
866
    }
2✔
867
}
868

869
impl Display for BuildInItemError {
870
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6✔
871
        use BuildInItemErrorKind::*;
872
        let kind = match &self.kind {
6✔
873
            Size(_) => "size",
2✔
874
            BasePath(_) => "base-path",
1✔
875
            LastModified(_) => "last-modified",
1✔
876
            InvalidStorageClass => "storage-class",
2✔
877
        };
878
        write!(f, "parse {kind} failed, gived str: {}", self.source)
6✔
879
    }
6✔
880
}
881

882
impl Error for BuildInItemError {
883
    fn source(&self) -> Option<&(dyn Error + 'static)> {
4✔
884
        use BuildInItemErrorKind::*;
885
        match &self.kind {
4✔
886
            Size(e) => Some(e),
1✔
887
            BasePath(e) => Some(e),
1✔
888
            LastModified(e) => Some(e),
1✔
889
            InvalidStorageClass => None,
1✔
890
        }
891
    }
4✔
892
}
893

894
/// Xml 转化为内置 Object 时的错误集合
895
#[derive(Debug)]
5✔
896
#[non_exhaustive]
897
enum BuildInItemErrorKind {
898
    /// 转换数字类型的错误
899
    Size(ParseIntError),
1✔
900

901
    /// 转换为 ObjectPath 时的错误
902
    BasePath(InvalidObjectPath),
1✔
903

904
    /// 转换日期格式的错误
905
    LastModified(chrono::ParseError),
1✔
906

907
    // /// 接收 Xml 转换时的错误
908
    // Xml(quick_xml::Error),
909
    /// 非法的 StorageClass
910
    InvalidStorageClass,
911
}
912

913
impl<P: PointerFamily, Item: RefineObject<E>, E: Error + 'static>
914
    RefineObjectList<Item, ObjectListError, E> for ObjectList<P, Item, E>
915
{
916
    #[inline]
917
    fn set_key_count(&mut self, key_count: &str) -> Result<(), ObjectListError> {
7✔
918
        self.key_count = key_count.parse().map_err(|e| ObjectListError {
11✔
919
            source: key_count.to_owned(),
2✔
920
            kind: ObjectListErrorKind::KeyCount(e),
2✔
921
        })?;
4✔
922
        Ok(())
5✔
923
    }
7✔
924

925
    #[inline]
926
    fn set_prefix(&mut self, prefix: &str) -> Result<(), ObjectListError> {
9✔
927
        if prefix.is_empty() {
9✔
928
            self.prefix = None;
7✔
929
        } else {
930
            let mut string = String::from(prefix);
2✔
931
            string += "/";
2✔
932
            self.prefix = Some(string.parse().map_err(|e| ObjectListError {
4✔
933
                source: prefix.to_owned(),
1✔
934
                kind: ObjectListErrorKind::Prefix(e),
1✔
935
            })?)
2✔
936
        }
2✔
937
        Ok(())
8✔
938
    }
9✔
939

940
    #[inline]
941
    fn set_common_prefix(
2✔
942
        &mut self,
943
        list: &[std::borrow::Cow<'_, str>],
944
    ) -> Result<(), ObjectListError> {
945
        for val in list.iter() {
2✔
946
            self.common_prefixes
1✔
947
                .push(val.parse().map_err(|e| ObjectListError {
3✔
948
                    source: val.to_string(),
1✔
949
                    kind: ObjectListErrorKind::CommonPrefix(e),
1✔
950
                })?);
2✔
951
        }
952
        Ok(())
1✔
953
    }
2✔
954

955
    #[inline]
956
    fn set_max_keys(&mut self, max_keys: &str) -> Result<(), ObjectListError> {
9✔
957
        self.max_keys = max_keys.parse().map_err(|e| ObjectListError {
13✔
958
            source: max_keys.to_string(),
2✔
959
            kind: ObjectListErrorKind::MaxKeys(e),
2✔
960
        })?;
4✔
961
        Ok(())
7✔
962
    }
9✔
963

964
    #[inline]
965
    fn set_next_continuation_token_str(&mut self, token: &str) -> Result<(), ObjectListError> {
1✔
966
        self.next_continuation_token = token.to_owned();
1✔
967
        Ok(())
1✔
968
    }
1✔
969

970
    #[inline]
971
    fn set_list(&mut self, list: Vec<Item>) -> Result<(), ObjectListError> {
5✔
972
        self.object_list = list;
5✔
973
        Ok(())
5✔
974
    }
5✔
975
}
976

977
/// decode xml to object list error collection
978
#[derive(Debug)]
10✔
979
#[non_exhaustive]
980
pub struct ObjectListError {
981
    source: String,
982
    kind: ObjectListErrorKind,
5✔
983
}
984

985
impl ObjectListError {
986
    #[cfg(test)]
987
    pub(crate) fn test_new() -> Self {
1✔
988
        Self {
1✔
989
            source: "foo".to_string(),
1✔
990
            kind: ObjectListErrorKind::Bar,
1✔
991
        }
992
    }
1✔
993
}
994

995
impl Display for ObjectListError {
996
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
7✔
997
        use ObjectListErrorKind::*;
998
        let kind: &str = match &self.kind {
7✔
999
            KeyCount(_) => "key-count",
2✔
1000
            Prefix(_) => "prefix",
1✔
1001
            CommonPrefix(_) => "common-prefix",
1✔
1002
            MaxKeys(_) => "max-keys",
2✔
1003
            #[cfg(test)]
1004
            Bar => "bar",
1✔
1005
        };
1006
        write!(f, "parse {kind} failed, gived str: {}", self.source)
7✔
1007
    }
7✔
1008
}
1009

1010
impl Error for ObjectListError {
1011
    fn source(&self) -> Option<&(dyn Error + 'static)> {
4✔
1012
        use ObjectListErrorKind::*;
1013
        match &self.kind {
4✔
1014
            KeyCount(e) | MaxKeys(e) => Some(e),
2✔
1015
            Prefix(e) | CommonPrefix(e) => Some(e),
2✔
1016
            #[cfg(test)]
1017
            Bar => None,
×
1018
        }
1019
    }
4✔
1020
}
1021

1022
impl ListError for ObjectListError {}
1023

1024
/// decode xml to object list error collection
1025
#[derive(Debug)]
5✔
1026
#[non_exhaustive]
1027
enum ObjectListErrorKind {
1028
    /// when covert key_count failed ,return this error
1029
    KeyCount(ParseIntError),
1✔
1030
    /// when covert prefix failed ,return this error
1031
    Prefix(InvalidObjectDir),
1✔
1032
    /// when covert common_prefix failed ,return this error
1033
    CommonPrefix(InvalidObjectDir),
1✔
1034
    /// when covert max_keys failed ,return this error
1035
    MaxKeys(ParseIntError),
1✔
1036
    #[cfg(test)]
1037
    Bar,
1038
}
1039

1040
impl Client {
1041
    /// 查询默认 bucket 的文件列表
1042
    ///
1043
    /// 查询条件参数有多种方式,具体参考 [`get_object_list`] 文档
1044
    ///
1045
    /// [`get_object_list`]: crate::bucket::Bucket::get_object_list
1046
    #[inline(always)]
1047
    pub async fn get_object_list<Q: IntoIterator<Item = (QueryKey, QueryValue)>>(
3✔
1048
        &self,
3✔
1049
        query: Q,
3✔
1050
    ) -> Result<ObjectList, ExtractListError> {
6✔
1051
        self.get_object_list2(Query::from_iter(query)).await
3✔
1052
    }
6✔
1053

1054
    /// 查询默认 bucket 的文件列表
1055
    pub async fn get_object_list2(&self, query: Query) -> Result<ObjectList, ExtractListError> {
9✔
1056
        let bucket = BucketBase::new(self.bucket.to_owned(), self.endpoint.to_owned());
3✔
1057

1058
        let (bucket_url, resource) = bucket.get_url_resource(&query);
3✔
1059
        let bucket_arc = Arc::new(bucket.clone());
3✔
1060

1061
        let mut list = ObjectList::<ArcPointer> {
3✔
1062
            object_list: Vec::with_capacity(query.get_max_keys()),
3✔
1063
            bucket,
3✔
1064
            ..Default::default()
3✔
1065
        };
3✔
1066

1067
        let response = self.builder(Method::GET, bucket_url, resource)?;
3✔
1068
        let content = response.send_adjust_error().await?;
3✔
1069

1070
        list.decode(&content.text().await?, || {
6✔
1071
            Object::from_bucket(bucket_arc.clone())
3✔
1072
        })?;
8✔
1073

1074
        list.set_client(Arc::new(self.clone()));
1✔
1075
        list.set_search_query(query);
1✔
1076

1077
        Ok(list)
1✔
1078
    }
7✔
1079

1080
    /// # 可将 object 列表导出到外部类型(关注便捷性)
1081
    /// 可以参考下面示例,或者项目中的 `examples/custom.rs`
1082
    /// ## 示例
1083
    /// ```rust
1084
    /// use aliyun_oss_client::{
1085
    ///     decode::{ListError, RefineObject, RefineObjectList},
1086
    ///     object::ExtractListError,
1087
    ///     Client,
1088
    /// };
1089
    /// use dotenv::dotenv;
1090
    /// use thiserror::Error;
1091
    ///
1092
    /// #[derive(Debug)]
1093
    /// struct MyFile {
1094
    ///     key: String,
1095
    ///     #[allow(dead_code)]
1096
    ///     other: String,
1097
    /// }
1098
    /// impl RefineObject<MyError> for MyFile {
1099
    ///     fn set_key(&mut self, key: &str) -> Result<(), MyError> {
1100
    ///         self.key = key.to_string();
1101
    ///         Ok(())
1102
    ///     }
1103
    /// }
1104
    ///
1105
    /// #[derive(Default, Debug)]
1106
    /// struct MyBucket {
1107
    ///     name: String,
1108
    ///     files: Vec<MyFile>,
1109
    /// }
1110
    ///
1111
    /// impl RefineObjectList<MyFile, MyError> for MyBucket {
1112
    ///     fn set_name(&mut self, name: &str) -> Result<(), MyError> {
1113
    ///         self.name = name.to_string();
1114
    ///         Ok(())
1115
    ///     }
1116
    ///     fn set_list(&mut self, list: Vec<MyFile>) -> Result<(), MyError> {
1117
    ///         self.files = list;
1118
    ///         Ok(())
1119
    ///     }
1120
    /// }
1121
    ///
1122
    /// #[derive(Debug, Error)]
1123
    /// #[error("my error")]
1124
    /// enum MyError {}
1125
    ///
1126
    /// impl ListError for MyError {}
1127
    ///
1128
    /// async fn run() -> Result<(), ExtractListError> {
1129
    ///     dotenv().ok();
1130
    ///     use aliyun_oss_client::BucketName;
1131
    ///
1132
    ///     let client = Client::from_env().unwrap();
1133
    ///
1134
    ///     // 除了设置Default 外,还可以做更多设置
1135
    ///     let mut bucket = MyBucket::default();
1136
    ///
1137
    ///     // 利用闭包对 MyFile 做一下初始化设置
1138
    ///     let init_file = || MyFile {
1139
    ///         key: String::default(),
1140
    ///         other: "abc".to_string(),
1141
    ///     };
1142
    ///     //let bucket_name = env::var("ALIYUN_BUCKET").unwrap();
1143
    ///     let bucket_name = "abc".parse::<BucketName>().unwrap();
1144
    ///
1145
    ///     client
1146
    ///         .base_object_list(bucket_name, [], &mut bucket, init_file)
1147
    ///         .await?;
1148
    ///
1149
    ///     println!("bucket: {:?}", bucket);
1150
    ///
1151
    ///     Ok(())
1152
    /// }
1153
    /// ```
1154
    #[inline]
1155
    pub async fn base_object_list<
1156
        Name: Into<BucketName>,
1157
        Q: IntoIterator<Item = (QueryKey, QueryValue)>,
1158
        List,
1159
        Item,
1160
        F,
1161
        E: ListError,
1162
        ItemErr: Error + 'static,
1163
    >(
1164
        &self,
1165
        name: Name,
1166
        query: Q,
1167
        list: &mut List,
1168
        init_object: F,
1169
    ) -> Result<(), ExtractListError>
1170
    where
1171
        List: RefineObjectList<Item, E, ItemErr>,
1172
        Item: RefineObject<ItemErr>,
1173
        F: FnMut() -> Item,
1174
    {
1175
        let query = Query::from_iter(query);
1176
        let name = name.into();
1177

1178
        self.base_object_list2(&name, &query, list, init_object)
1179
            .await
1180
    }
1181

1182
    /// # 可将 object 列表导出到外部类型(关注性能)
1183
    pub async fn base_object_list2<List, Item, F, E: ListError, ItemErr: Error + 'static>(
1184
        &self,
1185
        name: &BucketName,
1186
        query: &Query,
1187
        list: &mut List,
1188
        init_object: F,
1189
    ) -> Result<(), ExtractListError>
1190
    where
1191
        List: RefineObjectList<Item, E, ItemErr>,
1192
        Item: RefineObject<ItemErr>,
1193
        F: FnMut() -> Item,
1194
    {
1195
        let (bucket_url, resource) = get_url_resource_with_bucket(self.as_ref(), name, query);
1196

1197
        let response = self.builder(Method::GET, bucket_url, resource)?;
1198
        let content = response.send_adjust_error().await?;
1199

1200
        list.decode(&content.text().await?, init_object)?;
1201

1202
        Ok(())
1203
    }
1204
}
1205

1206
/// 为 [`base_object_list`] 方法,返回一个统一的 Error
1207
///
1208
/// [`base_object_list`]: crate::client::Client::base_object_list
1209
#[derive(Debug)]
8✔
1210
#[non_exhaustive]
1211
pub struct ExtractListError {
1212
    pub(crate) kind: ExtractListErrorKind,
4✔
1213
}
1214

1215
/// [`ExtractListError`] 类型的枚举
1216
///
1217
/// [`ExtractListError`]: crate::object::ExtractListError
1218
#[derive(Debug)]
4✔
1219
#[non_exhaustive]
1220
pub(crate) enum ExtractListErrorKind {
1221
    #[doc(hidden)]
1222
    Builder(BuilderError),
3✔
1223

1224
    #[doc(hidden)]
1225
    Reqwest(reqwest::Error),
×
1226

1227
    /// 解析 xml 错误
1228
    Decode(InnerListError),
×
1229

1230
    /// 用于 Stream
1231
    NoMoreFile,
1232
}
1233

1234
impl From<InnerListError> for ExtractListError {
1235
    fn from(value: InnerListError) -> Self {
4✔
1236
        use ExtractListErrorKind::*;
1237
        Self {
4✔
1238
            kind: Decode(value),
4✔
1239
        }
1240
    }
4✔
1241
}
1242
impl From<BuilderError> for ExtractListError {
1243
    fn from(value: BuilderError) -> Self {
5✔
1244
        use ExtractListErrorKind::*;
1245
        Self {
5✔
1246
            kind: Builder(value),
5✔
1247
        }
1248
    }
5✔
1249
}
1250
impl From<reqwest::Error> for ExtractListError {
1251
    fn from(value: reqwest::Error) -> Self {
1✔
1252
        use ExtractListErrorKind::*;
1253
        Self {
1✔
1254
            kind: Reqwest(value),
1✔
1255
        }
1256
    }
1✔
1257
}
1258
impl Display for ExtractListError {
1259
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
8✔
1260
        use ExtractListErrorKind::*;
1261
        match &self.kind {
8✔
1262
            Builder(_) => "builder error".fmt(f),
1✔
1263
            Reqwest(_) => "reqwest error".fmt(f),
1✔
1264
            Decode(_) => "decode xml failed".fmt(f),
4✔
1265
            NoMoreFile => "no more file".fmt(f),
2✔
1266
        }
1267
    }
8✔
1268
}
1269
impl Error for ExtractListError {
1270
    fn source(&self) -> Option<&(dyn Error + 'static)> {
7✔
1271
        use ExtractListErrorKind::*;
1272
        match &self.kind {
7✔
1273
            Builder(e) => Some(e),
1✔
1274
            Reqwest(e) => Some(e),
1✔
1275
            Decode(e) => e.get_source(),
4✔
1276
            NoMoreFile => None,
1✔
1277
        }
1278
    }
7✔
1279
}
1280

1281
#[cfg(feature = "blocking")]
1282
impl ClientRc {
1283
    /// 查询默认 bucket 的文件列表
1284
    ///
1285
    /// 查询条件参数有多种方式,具体参考 [`get_object_list`](../bucket/struct.Bucket.html#method.get_object_list) 文档
1286
    pub fn get_object_list<Q: IntoIterator<Item = (QueryKey, QueryValue)>>(
1✔
1287
        self,
1288
        query: Q,
1289
    ) -> Result<ObjectList<RcPointer>, ExtractListError> {
1290
        let name = self.get_bucket_name();
1✔
1291
        let bucket = BucketBase::new(name.clone(), self.get_endpoint().to_owned());
1✔
1292

1293
        let mut list = ObjectList::<RcPointer>::default();
1✔
1294
        list.set_bucket(bucket.clone());
1✔
1295

1296
        let bucket_arc = Rc::new(bucket);
1✔
1297

1298
        let query = Query::from_iter(query);
1✔
1299

1300
        let (bucket_url, resource) = bucket_arc.get_url_resource(&query);
1✔
1301

1302
        let response = self.builder(Method::GET, bucket_url, resource)?;
1✔
1303
        let content = response.send_adjust_error()?;
1✔
1304

1305
        list.decode(&content.text()?, || {
2✔
1306
            Object::<RcPointer>::from_bucket(bucket_arc.clone())
1✔
1307
        })?;
2✔
1308

1309
        list.set_client(Rc::new(self));
1✔
1310
        list.set_search_query(query);
1✔
1311

1312
        Ok(list)
1✔
1313
    }
1✔
1314

1315
    /// 可将 object 列表导出到外部 struct
1316
    #[inline]
1317
    pub fn base_object_list<
1✔
1318
        Name: Into<BucketName>,
1319
        Q: IntoIterator<Item = (QueryKey, QueryValue)>,
1320
        List,
1321
        Item,
1322
        F,
1323
        E: ListError,
1324
        ItemErr: Error + 'static,
1325
    >(
1326
        &self,
1327
        name: Name,
1328
        query: Q,
1329
        list: &mut List,
1330
        init_object: F,
1331
    ) -> Result<(), ExtractListError>
1332
    where
1333
        List: RefineObjectList<Item, E, ItemErr>,
1334
        Item: RefineObject<ItemErr>,
1335
        F: FnMut() -> Item,
1336
    {
1337
        let bucket = BucketBase::new(name.into(), self.get_endpoint().to_owned());
1✔
1338

1339
        let query = Query::from_iter(query);
1✔
1340
        let (bucket_url, resource) = bucket.get_url_resource(&query);
1✔
1341

1342
        let response = self.builder(Method::GET, bucket_url, resource)?;
1✔
1343
        let content = response.send_adjust_error()?;
1✔
1344

1345
        list.decode(&content.text()?, init_object)?;
1✔
1346

1347
        Ok(())
1✔
1348
    }
1✔
1349
}
1350

1351
#[cfg(feature = "blocking")]
1352
impl Iterator for ObjectList<RcPointer> {
1353
    type Item = ObjectList<RcPointer>;
1354
    fn next(&mut self) -> Option<Self> {
×
1355
        if !self.next_continuation_token.is_empty() {
×
1356
            self.search_query
×
1357
                .insert(CONTINUATION_TOKEN, self.next_continuation_token.to_owned());
×
1358
            self.get_object_list().ok()
×
1359
        } else {
1360
            None
×
1361
        }
1362
    }
×
1363
}
1364

1365
// use std::task::Poll::{self, Ready};
1366

1367
// impl Stream for ObjectList<ArcPointer> {
1368
//     type Item = ObjectList<ArcPointer>;
1369

1370
//     fn poll_next(
1371
//         self: std::pin::Pin<&mut Self>,
1372
//         cx: &mut std::task::Context<'_>,
1373
//     ) -> Poll<Option<Self::Item>> {
1374
//         match self.next_query() {
1375
//             Some(query) => {
1376
//                 let mut url = self.bucket.to_url();
1377
//                 url.set_search_query(&query);
1378

1379
//                 let canonicalized = CanonicalizedResource::from_bucket_query(&self.bucket, &query);
1380

1381
//                 let builder = self.builder(Method::GET, url, canonicalized);
1382
//                 match builder {
1383
//                     Err(err) => Ready(None),
1384
//                     Ok(builder) => {
1385
//                         let waker = cx.waker().clone();
1386

1387
//                         std::thread::spawn(move || {
1388
//                             let response = builder.send_adjust_error();
1389

1390
//                             let response = futures::executor::block_on(response);
1391
//                             let text = response.unwrap().text();
1392
//                             let text = futures::executor::block_on(text);
1393

1394
//                             let text = text.unwrap();
1395

1396
//                             let bucket_arc = Arc::new(self.bucket);
1397

1398
//                             let init_object = || {
1399
//                                 let object = Object::<ArcPointer>::default();
1400
//                                 object.base.set_bucket(bucket_arc.clone());
1401
//                                 object
1402
//                             };
1403

1404
//                             self.decode(&text, init_object).unwrap();
1405

1406
//                             self.set_search_query(query);
1407

1408
//                             waker.wake();
1409
//                         });
1410

1411
//                         Poll::Pending
1412
//                     }
1413
//                 }
1414
//             }
1415
//             None => Ready(None),
1416
//         }
1417
//     }
1418
// }
1419

1420
#[oss_gen_rc]
1421
impl PartialEq<Object<ArcPointer>> for Object<ArcPointer> {
1422
    #[inline]
1423
    fn eq(&self, other: &Object<ArcPointer>) -> bool {
8✔
1424
        self.base == other.base
8✔
1425
            && self.last_modified == other.last_modified
6✔
1426
            && self.etag == other.etag
5✔
1427
            && self._type == other._type
4✔
1428
            && self.size == other.size
3✔
1429
            && self.storage_class == other.storage_class
2✔
1430
    }
8✔
1431
}
1432

1433
impl<T: PointerFamily> PartialEq<DateTime<Utc>> for Object<T> {
1434
    #[inline]
1435
    fn eq(&self, other: &DateTime<Utc>) -> bool {
1436
        &self.last_modified == other
1437
    }
1438
}
1439

1440
impl<T: PointerFamily> PartialEq<u64> for Object<T> {
1441
    #[inline]
1442
    fn eq(&self, other: &u64) -> bool {
1443
        &self.size == other
1444
    }
1445
}
1446

1447
#[oss_gen_rc]
1448
impl PartialEq<ObjectBase<ArcPointer>> for Object<ArcPointer> {
1449
    #[inline]
1450
    fn eq(&self, other: &ObjectBase<ArcPointer>) -> bool {
×
1451
        &self.base == other
×
1452
    }
×
1453
}
1454

1455
/// 未来计划支持的功能
1456
#[derive(Default)]
×
1457
#[doc(hidden)]
1458
pub struct PutObject<'a> {
1459
    pub forbid_overwrite: bool,
×
1460
    pub server_side_encryption: Option<Encryption>,
×
1461
    pub server_side_data_encryption: Option<Encryption>,
×
1462
    pub server_side_encryption_key_id: Option<&'a str>,
×
1463
    pub object_acl: ObjectAcl,
×
1464
    pub storage_class: StorageClass,
×
1465
    pub tagging: Option<&'a str>,
×
1466
}
1467

1468
/// 未来计划支持的功能
1469
#[derive(Default)]
×
1470
#[doc(hidden)]
1471
pub enum Encryption {
1472
    #[default]
1473
    Aes256,
1474
    Kms,
1475
    Sm4,
1476
}
1477

1478
/// 未来计划支持的功能
1479
#[derive(Default)]
×
1480
#[doc(hidden)]
1481
pub enum ObjectAcl {
1482
    #[default]
1483
    Default,
1484
    Private,
1485
    PublicRead,
1486
    PublicReadWrite,
1487
}
1488

1489
/// 存储类型
1490
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
72✔
1491
#[non_exhaustive]
1492
pub struct StorageClass {
1493
    kind: StorageClassKind,
36✔
1494
}
1495

1496
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
44✔
1497
#[non_exhaustive]
1498
enum StorageClassKind {
1499
    /// Standard 默认
1500
    #[default]
1501
    Standard,
1502
    /// IA
1503
    IA,
1504
    /// Archive
1505
    Archive,
1506
    /// ColdArchive
1507
    ColdArchive,
1508
}
1509

1510
impl StorageClass {
1511
    /// Archive
1512
    pub const ARCHIVE: Self = Self {
1513
        kind: StorageClassKind::Archive,
1514
    };
1515
    /// IA
1516
    pub const IA: Self = Self {
1517
        kind: StorageClassKind::IA,
1518
    };
1519
    /// Standard
1520
    pub const STANDARD: Self = Self {
1521
        kind: StorageClassKind::Standard,
1522
    };
1523
    /// ColdArchive
1524
    pub const COLD_ARCHIVE: Self = Self {
1525
        kind: StorageClassKind::ColdArchive,
1526
    };
1527

1528
    /// init StorageClass
1529
    pub fn new(s: &str) -> Option<StorageClass> {
23✔
1530
        let start_char = s.chars().next()?;
23✔
1531

1532
        let kind = match start_char {
22✔
1533
            'a' | 'A' => StorageClassKind::Archive,
4✔
1534
            'i' | 'I' => StorageClassKind::IA,
2✔
1535
            's' | 'S' => StorageClassKind::Standard,
10✔
1536
            'c' | 'C' => StorageClassKind::ColdArchive,
2✔
1537
            _ => return None,
4✔
1538
        };
1539
        Some(Self { kind })
18✔
1540
    }
23✔
1541
}
1542

1543
/// 未来计划支持的功能
1544
#[derive(Default)]
×
1545
#[doc(hidden)]
1546
pub struct CopyObject<'a> {
1547
    pub forbid_overwrite: bool,
×
1548
    pub copy_source: &'a str,
×
1549
    pub copy_source_if_match: Option<&'a str>,
×
1550
    pub copy_source_if_none_match: Option<&'a str>,
×
1551
    pub copy_source_if_unmodified_since: Option<&'a str>,
×
1552
    pub copy_source_if_modified_since: Option<&'a str>,
×
1553
    pub metadata_directive: CopyDirective,
×
1554
    pub server_side_encryption: Option<Encryption>,
×
1555
    pub server_side_encryption_key_id: Option<&'a str>,
×
1556
    pub object_acl: ObjectAcl,
×
1557
    pub storage_class: StorageClass,
×
1558
    pub tagging: Option<&'a str>,
×
1559
    pub tagging_directive: CopyDirective,
×
1560
}
1561

1562
/// 未来计划支持的功能
1563
#[derive(Default)]
×
1564
#[doc(hidden)]
1565
pub enum CopyDirective {
1566
    #[default]
1567
    Copy,
1568
    Replace,
1569
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc