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

tu6ge / oss-rs / 5863951548

pending completion
5863951548

Pull #24

github

tu6ge
feat(client): Reduce constraints on generic param
Pull Request #24: Branch0.12

39 of 39 new or added lines in 4 files covered. (100.0%)

6180 of 6422 relevant lines covered (96.23%)

9.24 hits per line

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

89.89
/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
#[cfg(feature = "blocking")]
110
use std::rc::Rc;
111
use std::{
112
    error::Error,
113
    fmt::{self, Display},
114
    marker::PhantomData,
115
    num::ParseIntError,
116
    slice::{Iter, IterMut},
117
    sync::Arc,
118
    vec::IntoIter,
119
};
120

121
#[cfg(test)]
122
mod test;
123

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

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

155
/// 存放单个对象的结构体
156
#[derive(Clone, Debug)]
157
#[non_exhaustive]
158
pub struct Object<PointerSel: PointerFamily = ArcPointer> {
159
    pub(crate) base: ObjectBase<PointerSel>,
160
    last_modified: DateTime<Utc>,
161
    etag: String,
162
    _type: String,
163
    size: u64,
164
    storage_class: StorageClass,
165
}
166

167
/// 异步的 Object struct
168
pub type ObjectArc = Object<ArcPointer>;
169

170
impl<T: PointerFamily, Item: RefineObject<E>, E: Error> fmt::Debug for ObjectList<T, Item, E> {
171
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1✔
172
        f.debug_struct("ObjectList")
7✔
173
            .field("bucket", &self.bucket)
1✔
174
            .field("prefix", &self.prefix)
175
            .field("max_keys", &self.max_keys)
1✔
176
            .field("key_count", &self.key_count)
1✔
177
            .field("next_continuation_token", &self.next_continuation_token)
1✔
178
            .field("common_prefixes", &self.common_prefixes)
1✔
179
            .field("search_query", &self.search_query)
1✔
180
            .finish()
181
    }
1✔
182
}
183

184
#[oss_gen_rc]
4✔
185
impl<Item: RefineObject<E>, E: Error> Default for ObjectList<ArcPointer, Item, E> {
186
    fn default() -> Self {
15✔
187
        Self {
15✔
188
            bucket: BucketBase::default(),
15✔
189
            prefix: Option::default(),
15✔
190
            max_keys: u32::default(),
15✔
191
            key_count: u64::default(),
15✔
192
            object_list: Vec::new(),
15✔
193
            next_continuation_token: String::default(),
15✔
194
            common_prefixes: CommonPrefixes::default(),
15✔
195
            client: Arc::new(ClientArc::default()),
11✔
196
            search_query: Query::default(),
15✔
197
            ph_err: PhantomData,
198
        }
199
    }
15✔
200
}
201

202
impl<T: PointerFamily, Item: RefineObject<E>, E: Error> AsMut<Query> for ObjectList<T, Item, E> {
203
    fn as_mut(&mut self) -> &mut Query {
204
        &mut self.search_query
205
    }
206
}
207

208
impl<T: PointerFamily, Item: RefineObject<E>, E: Error> AsRef<BucketBase>
209
    for ObjectList<T, Item, E>
210
{
211
    fn as_ref(&self) -> &BucketBase {
212
        &self.bucket
213
    }
214
}
215

216
impl<T: PointerFamily, Item: RefineObject<E>, E: Error> AsRef<BucketName>
217
    for ObjectList<T, Item, E>
218
{
219
    fn as_ref(&self) -> &BucketName {
220
        self.bucket.as_ref()
221
    }
222
}
223

224
impl<T: PointerFamily, Item: RefineObject<E>, E: Error> AsRef<EndPoint> for ObjectList<T, Item, E> {
225
    fn as_ref(&self) -> &EndPoint {
226
        self.bucket.as_ref()
227
    }
228
}
229

230
impl<T: PointerFamily, Item: RefineObject<E>, E: Error> ObjectList<T, Item, E> {
231
    /// 文件列表的初始化方法
232
    #[allow(clippy::too_many_arguments)]
233
    pub fn new<Q: IntoIterator<Item = (QueryKey, QueryValue)>>(
8✔
234
        bucket: BucketBase,
235
        prefix: Option<ObjectDir<'static>>,
236
        max_keys: u32,
237
        key_count: u64,
238
        object_list: Vec<Item>,
239
        next_continuation_token: Option<String>,
240
        client: T::PointerType,
241
        search_query: Q,
242
    ) -> Self {
243
        Self {
8✔
244
            bucket,
245
            prefix,
246
            max_keys,
247
            key_count,
248
            object_list,
249
            next_continuation_token: next_continuation_token.unwrap_or_default(),
8✔
250
            common_prefixes: CommonPrefixes::default(),
8✔
251
            client,
252
            search_query: Query::from_iter(search_query),
8✔
253
            ph_err: PhantomData,
254
        }
255
    }
8✔
256

257
    /// 返回 bucket 元信息的引用
258
    pub fn bucket(&self) -> &BucketBase {
11✔
259
        &self.bucket
11✔
260
    }
11✔
261

262
    /// 返回 prefix 的引用
263
    pub fn prefix(&self) -> &Option<ObjectDir<'static>> {
6✔
264
        &self.prefix
265
    }
6✔
266

267
    /// 获取文件夹下的子文件夹名,子文件夹下递归的所有文件和文件夹不包含在这里。
268
    pub fn common_prefixes(&self) -> &CommonPrefixes {
7✔
269
        &self.common_prefixes
7✔
270
    }
7✔
271

272
    /// 设置 common_prefixes 信息
273
    pub fn set_common_prefixes<P: IntoIterator<Item = ObjectDir<'static>>>(&mut self, prefixes: P) {
1✔
274
        self.common_prefixes = CommonPrefixes::from_iter(prefixes);
1✔
275
    }
1✔
276

277
    /// 返回 max_keys
278
    pub fn max_keys(&self) -> &u32 {
7✔
279
        &self.max_keys
7✔
280
    }
7✔
281

282
    /// 返回 key_count
283
    pub fn key_count(&self) -> &u64 {
5✔
284
        &self.key_count
5✔
285
    }
5✔
286

287
    /// # 返回下一个 continuation_token
288
    /// 用于翻页使用
289
    pub fn next_continuation_token_str(&self) -> &String {
7✔
290
        &self.next_continuation_token
7✔
291
    }
7✔
292

293
    /// 返回查询条件
294
    pub fn search_query(&self) -> &Query {
5✔
295
        &self.search_query
5✔
296
    }
5✔
297

298
    /// # 下一页的查询条件
299
    ///
300
    /// 如果有下一页,返回 Some(Query)
301
    /// 如果没有下一页,则返回 None
302
    pub fn next_query(&self) -> Option<Query> {
2✔
303
        if !self.next_continuation_token.is_empty() {
2✔
304
            let mut search_query = self.search_query.clone();
1✔
305
            search_query.insert(CONTINUATION_TOKEN, self.next_continuation_token.to_owned());
1✔
306
            Some(search_query)
1✔
307
        } else {
308
            None
1✔
309
        }
310
    }
2✔
311

312
    /// 将 object 列表转化实现了 `IntoIter` Trait的外部类型
313
    pub fn object_iter(self) -> IntoIter<Item> {
1✔
314
        self.object_list.into_iter()
1✔
315
    }
1✔
316

317
    /// 将 object 列表转化实现了 `IntoIter` Trait的外部类型
318
    pub fn object_into_iter(self) -> IntoIter<Item> {
319
        self.object_list.into_iter()
320
    }
321

322
    /// 返回 object 列表迭代器
323
    pub fn object_iter2(&self) -> Iter<Item> {
324
        self.object_list.iter()
325
    }
326

327
    /// 将 object 列表转化为迭代器的可变引用
328
    pub fn object_iter_mut(&mut self) -> IterMut<Item> {
329
        self.object_list.iter_mut()
330
    }
331
}
332

333
#[oss_gen_rc]
2✔
334
impl<Item: RefineObject<E>, E: Error> ObjectList<ArcPointer, Item, E> {
335
    /// 设置 Client
336
    pub(crate) fn set_client(&mut self, client: Arc<ClientArc>) {
2✔
337
        self.client = client;
2✔
338
    }
2✔
339

340
    pub(crate) fn from_bucket(
4✔
341
        bucket: &Bucket<ArcPointer>,
342
        capacity: usize,
343
    ) -> ObjectList<ArcPointer> {
344
        ObjectList::<ArcPointer> {
4✔
345
            bucket: bucket.base.clone(),
4✔
346
            client: Arc::clone(&bucket.client),
3✔
347
            object_list: Vec::with_capacity(capacity),
4✔
348
            ..Default::default()
4✔
349
        }
350
    }
4✔
351

352
    /// 获取 Client 引用
353
    pub(crate) fn client(&self) -> Arc<ClientArc> {
1✔
354
        Arc::clone(&self.client)
1✔
355
    }
1✔
356
}
357

358
impl ObjectList<ArcPointer> {
359
    /// 异步获取下一页的数据
360
    pub async fn get_next_list(&self) -> Result<ObjectList<ArcPointer>, ExtractListError> {
×
361
        match self.next_query() {
362
            None => Err(ExtractListError {
363
                kind: ExtractListErrorKind::NoMoreFile,
364
            }),
365
            Some(query) => {
366
                let mut url = self.bucket.to_url();
367
                url.set_oss_query(&query);
368

369
                let canonicalized = CanonicalizedResource::from_bucket_query(&self.bucket, &query);
370

371
                let response = self
372
                    .builder(Method::GET, url, canonicalized)?
373
                    .send_adjust_error()
374
                    .await?;
375

376
                let mut list = ObjectList::<ArcPointer> {
377
                    client: self.client(),
378
                    bucket: self.bucket.clone(),
379
                    object_list: Vec::with_capacity(query.get_max_keys()),
380
                    ..Default::default()
381
                };
382

383
                list.decode(&response.text().await?, || {
384
                    Object::from_bucket(Arc::new(self.bucket.clone()))
385
                })?;
386

387
                list.set_search_query(query);
388
                Ok(list)
389
            }
390
        }
391
    }
×
392

393
    /// # 将 object_list 转化为 stream, 返回第二页,第三页... 的内容
394
    ///
395
    /// *不够完善,最后一次迭代返回的是 `Some(Err(OssError::WithoutMore))`,而不是 `None`*
396
    ///
397
    /// ## 用法
398
    ///
399
    /// 1. 添加依赖
400
    /// ```toml
401
    /// [dependencies]
402
    /// futures="0.3"
403
    /// ```
404
    /// 2. 将返回结果 pin 住
405
    /// ```no_run
406
    /// # use dotenv::dotenv;
407
    /// # use aliyun_oss_client::Client;
408
    /// # #[tokio::main]
409
    /// # async fn main() {
410
    /// # dotenv().ok();
411
    /// use futures::{pin_mut, StreamExt};
412
    /// # let client = Client::from_env().unwrap();
413
    /// # let query = [("max-keys".into(), 100u8.into())];
414
    /// # let object_list = client.get_object_list(query).await.unwrap();
415
    /// let stream = object_list.into_stream();
416
    /// pin_mut!(stream);
417
    ///
418
    /// let second_list = stream.next().await;
419
    /// let third_list = stream.next().await;
420
    /// println!("second_list: {:?}", second_list);
421
    /// println!("third_list: {:?}", third_list);
422
    /// # }
423
    /// ```
424
    pub fn into_stream(self) -> impl Stream<Item = Result<Self, ExtractListError>> {
×
425
        try_stream! {
×
426
            let result = self.get_next_list().await?;
427
            yield result;
428
        }
429
    }
×
430
}
431

432
impl<Item: RefineObject<E>, E: Error + 'static> ObjectList<ArcPointer, Item, E> {
433
    /// 自定义 Item 时,获取下一页数据
434
    pub async fn get_next_base<F>(&self, init_object: F) -> Result<Self, ExtractListError>
435
    where
436
        F: FnMut() -> Item,
437
    {
438
        match self.next_query() {
439
            None => Err(ExtractListError {
440
                kind: ExtractListErrorKind::NoMoreFile,
441
            }),
442
            Some(query) => {
443
                let mut list = Self::default();
444
                let name = self.bucket.get_name().clone();
445
                self.client()
446
                    .base_object_list(name, query, &mut list, init_object)
447
                    .await?;
448

449
                Ok(list)
450
            }
451
        }
452
    }
453
}
454

455
#[cfg(feature = "blocking")]
456
impl ObjectList<RcPointer> {
457
    fn clone_base(&self) -> Self {
1✔
458
        Self {
1✔
459
            client: Rc::clone(&self.client),
1✔
460
            bucket: self.bucket.clone(),
1✔
461
            search_query: self.search_query.clone(),
1✔
462
            max_keys: self.max_keys,
1✔
463
            object_list: Vec::with_capacity(self.max_keys as usize),
1✔
464
            ..Default::default()
1✔
465
        }
466
    }
1✔
467
    /// 从 OSS 获取 object 列表信息
468
    pub fn get_object_list(&mut self) -> Result<Self, ExtractListError> {
1✔
469
        let name = self.bucket.get_name();
1✔
470

471
        let client = self.client();
1✔
472

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

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

477
        client
2✔
478
            .base_object_list(
479
                name.to_owned(),
1✔
480
                self.search_query.clone(),
1✔
481
                &mut list,
482
                init_object,
483
            )
484
            .map_err(ExtractListError::from)?;
×
485

486
        Ok(list)
1✔
487
    }
1✔
488
}
489

490
impl<T: PointerFamily, Item: RefineObject<E>, E: Error + 'static> ObjectList<T, Item, E> {
491
    /// 设置查询条件
492
    #[inline]
493
    pub fn set_search_query(&mut self, search_query: Query) {
4✔
494
        self.search_query = search_query;
4✔
495
    }
4✔
496

497
    /// 设置 bucket 元信息
498
    pub fn set_bucket(&mut self, bucket: BucketBase) {
1✔
499
        self.bucket = bucket;
1✔
500
    }
1✔
501

502
    /// 获取 bucket 名称
503
    pub fn bucket_name(&self) -> &str {
1✔
504
        self.bucket.name()
1✔
505
    }
1✔
506

507
    /// 返回 object 的 Vec 集合
508
    pub fn to_vec(self) -> Vec<Item> {
509
        self.object_list
510
    }
511

512
    /// 返回文件数量
513
    pub fn len(&self) -> usize {
514
        self.object_list.len()
515
    }
516

517
    /// 返回是否存在文件
518
    pub fn is_empty(&self) -> bool {
519
        self.object_list.is_empty()
520
    }
521
}
522

523
impl<T: PointerFamily> Default for Object<T> {
524
    fn default() -> Self {
15✔
525
        Object {
15✔
526
            base: ObjectBase::<T>::default(),
15✔
527
            last_modified: DateTime::<Utc>::from_utc(
15✔
528
                #[allow(clippy::unwrap_used)]
529
                NaiveDateTime::from_timestamp_opt(0, 0).unwrap(),
15✔
530
                Utc,
531
            ),
532
            etag: String::default(),
15✔
533
            _type: String::default(),
15✔
534
            size: 0,
535
            storage_class: StorageClass::default(),
15✔
536
        }
537
    }
15✔
538
}
539

540
impl<T: PointerFamily> AsRef<ObjectPath> for Object<T> {
541
    fn as_ref(&self) -> &ObjectPath {
1✔
542
        self.base.as_ref()
1✔
543
    }
1✔
544
}
545

546
impl<T: PointerFamily> AsRef<DateTime<Utc>> for Object<T> {
547
    fn as_ref(&self) -> &DateTime<Utc> {
548
        &self.last_modified
549
    }
550
}
551

552
impl<T: PointerFamily> AsRef<StorageClass> for Object<T> {
553
    fn as_ref(&self) -> &StorageClass {
554
        &self.storage_class
555
    }
556
}
557

558
impl<T: PointerFamily> Object<T> {
559
    /// 初始化 Object 结构体
560
    pub fn new(
12✔
561
        bucket: T::Bucket,
562
        path: ObjectPath,
563
        last_modified: DateTime<Utc>,
564
        etag: String,
565
        _type: String,
566
        size: u64,
567
        storage_class: StorageClass,
568
    ) -> Self {
569
        let base = ObjectBase::<T>::new2(bucket, path);
12✔
570
        Self {
12✔
571
            base,
12✔
572
            last_modified,
573
            etag,
574
            _type,
575
            size,
576
            storage_class,
577
        }
578
    }
12✔
579

580
    pub(crate) fn from_bucket(bucket: T::Bucket) -> Self {
8✔
581
        Self {
8✔
582
            base: ObjectBase::<T>::init_with_bucket(bucket),
8✔
583
            ..Default::default()
8✔
584
        }
585
    }
8✔
586

587
    /// 读取 Object 元信息
588
    #[inline]
589
    pub fn base(&self) -> &ObjectBase<T> {
590
        &self.base
591
    }
592

593
    /// 设置 Object 元信息
594
    #[inline]
595
    pub fn set_base(&mut self, base: ObjectBase<T>) {
1✔
596
        self.base = base;
1✔
597
    }
1✔
598

599
    /// 读取最后修改时间
600
    #[inline]
601
    pub fn last_modified(&self) -> &DateTime<Utc> {
602
        &self.last_modified
603
    }
604

605
    /// 设置最后修改时间
606
    #[inline]
607
    pub fn set_last_modified(&mut self, last_modified: DateTime<Utc>) {
608
        self.last_modified = last_modified;
609
    }
610

611
    /// 读取 etag 信息
612
    #[inline]
613
    pub fn etag(&self) -> &String {
614
        &self.etag
615
    }
616

617
    /// 设置 etag
618
    #[inline]
619
    pub fn set_etag(&mut self, etag: String) {
620
        self.etag = etag
621
    }
622

623
    /// 读取 type
624
    #[inline]
625
    pub fn get_type_string(&self) -> &String {
626
        &self._type
627
    }
628

629
    /// 设置 type
630
    #[inline]
631
    pub fn set_type_string(&mut self, _type: String) {
632
        self._type = _type;
633
    }
634

635
    /// 读取文件 size
636
    #[inline]
637
    pub fn size(&self) -> u64 {
638
        self.size
639
    }
640

641
    /// 设置文件 size
642
    #[inline]
643
    pub fn set_size(&mut self, size: u64) {
644
        self.size = size;
645
    }
646

647
    /// 读取 storage_class
648
    #[inline]
649
    pub fn storage_class(&self) -> &StorageClass {
650
        &self.storage_class
651
    }
652

653
    /// 设置 storage_class
654
    #[inline]
655
    pub fn set_storage_class(&mut self, storage_class: StorageClass) {
656
        self.storage_class = storage_class;
657
    }
658

659
    /// 获取一部分数据
660
    pub fn pieces(
661
        self,
662
    ) -> (
663
        ObjectBase<T>,
664
        DateTime<Utc>,
665
        String,
666
        String,
667
        u64,
668
        StorageClass,
669
    ) {
670
        (
671
            self.base,
672
            self.last_modified,
673
            self.etag,
674
            self._type,
675
            self.size,
676
            self.storage_class,
677
        )
678
    }
679

680
    /// 读取 文件路径
681
    pub fn path(&self) -> ObjectPath {
682
        self.base.path()
683
    }
684

685
    #[doc(hidden)]
686
    pub fn path_string(&self) -> String {
687
        self.base.path().to_string()
688
    }
689
}
690

691
impl Object<ArcPointer> {
692
    #[cfg(test)]
693
    pub fn test_path(path: &'static str) -> Self {
1✔
694
        let mut object = Self::default();
1✔
695
        object.set_base(ObjectBase::<ArcPointer>::new2(
1✔
696
            Arc::new(BucketBase::default()),
1✔
697
            path.try_into().unwrap(),
1✔
698
        ));
699
        object
700
    }
1✔
701
}
702

703
impl<T: PointerFamily> From<Object<T>> for ObjectPathInner<'static> {
704
    #[inline]
705
    fn from(obj: Object<T>) -> Self {
706
        obj.base.path
707
    }
708
}
709

710
#[oss_gen_rc]
×
711
impl Object<ArcPointer> {
712
    /// # Object 构建器
713
    /// 用例
714
    /// ```
715
    /// # use aliyun_oss_client::{config::BucketBase, ObjectPath, object::{ObjectArc, StorageClass},EndPoint};
716
    /// # use chrono::{DateTime, NaiveDateTime, Utc};
717
    /// let bucket = BucketBase::new(
718
    ///     "bucket-name".parse().unwrap(),
719
    ///     EndPoint::CN_QINGDAO,
720
    /// );
721
    /// let mut builder = ObjectArc::builder("abc".parse::<ObjectPath>().unwrap());
722
    ///
723
    /// builder
724
    ///     .bucket_base(bucket)
725
    ///     .last_modified(DateTime::<Utc>::from_utc(
726
    ///         NaiveDateTime::from_timestamp_opt(123000, 0).unwrap(),
727
    ///         Utc,
728
    ///     ))
729
    ///     .etag("foo1".to_owned())
730
    ///     .set_type("foo2".to_owned())
731
    ///     .size(123)
732
    ///     .storage_class(StorageClass::IA);
733
    ///
734
    /// let object = builder.build();
735
    /// ```
736
    pub fn builder(path: ObjectPath) -> ObjectBuilder<ArcPointer> {
5✔
737
        ObjectBuilder::<ArcPointer>::new(Arc::default(), path)
5✔
738
    }
5✔
739

740
    /// 带签名的 Url 链接
741
    pub fn to_sign_url(&self, key: &KeyId, secret: &KeySecret, expires: i64) -> Url {
1✔
742
        self.base.to_sign_url(key, secret, expires)
1✔
743
    }
1✔
744
}
745

746
/// Object 结构体的构建器
747
pub struct ObjectBuilder<T: PointerFamily = ArcPointer> {
748
    object: Object<T>,
749
}
750

751
impl<T: PointerFamily> ObjectBuilder<T> {
752
    /// 初始化 Object 构建器
753
    pub fn new(bucket: T::Bucket, path: ObjectPath) -> Self {
5✔
754
        let base = ObjectBase::<T>::new2(bucket, path);
5✔
755
        Self {
5✔
756
            object: Object {
5✔
757
                base,
5✔
758
                last_modified: DateTime::<Utc>::from_utc(
5✔
759
                    #[allow(clippy::unwrap_used)]
760
                    NaiveDateTime::from_timestamp_opt(0, 0).unwrap(),
5✔
761
                    Utc,
762
                ),
763
                etag: String::default(),
5✔
764
                _type: String::default(),
5✔
765
                size: 0,
766
                storage_class: StorageClass::default(),
5✔
767
            },
768
        }
769
    }
5✔
770

771
    /// 设置元信息
772
    pub fn bucket(&mut self, bucket: T::Bucket) -> &mut Self {
1✔
773
        self.object.base.set_bucket(bucket);
1✔
774
        self
775
    }
1✔
776

777
    /// 设置 last_modified
778
    pub fn last_modified(&mut self, date: DateTime<Utc>) -> &mut Self {
1✔
779
        self.object.last_modified = date;
1✔
780
        self
781
    }
1✔
782

783
    /// 设置 etag
784
    pub fn etag(&mut self, etag: String) -> &mut Self {
1✔
785
        self.object.etag = etag;
1✔
786
        self
787
    }
1✔
788

789
    /// 设置 type
790
    pub fn set_type(&mut self, _type: String) -> &mut Self {
1✔
791
        self.object._type = _type;
1✔
792
        self
793
    }
1✔
794

795
    /// 设置 size
796
    pub fn size(&mut self, size: u64) -> &mut Self {
1✔
797
        self.object.size = size;
1✔
798
        self
799
    }
1✔
800

801
    /// 设置 storage_class
802
    pub fn storage_class(&mut self, storage_class: StorageClass) -> &mut Self {
1✔
803
        self.object.storage_class = storage_class;
1✔
804
        self
805
    }
1✔
806

807
    /// 返回 object
808
    pub fn build(self) -> Object<T> {
3✔
809
        self.object
3✔
810
    }
3✔
811
}
812

813
#[oss_gen_rc]
×
814
impl ObjectBuilder<ArcPointer> {
815
    /// 设置元信息
816
    pub fn bucket_base(&mut self, base: BucketBase) -> &mut Self {
4✔
817
        self.object.base.set_bucket(Arc::new(base));
4✔
818
        self
819
    }
4✔
820
}
821

822
impl<T: PointerFamily + Sized> RefineObject<BuildInItemError> for Object<T> {
823
    #[inline]
824
    fn set_key(&mut self, key: &str) -> Result<(), BuildInItemError> {
8✔
825
        self.base
24✔
826
            .set_path(key.to_owned())
8✔
827
            .map_err(|e| BuildInItemError {
10✔
828
                source: key.to_string(),
1✔
829
                kind: BuildInItemErrorKind::BasePath(e),
1✔
830
            })
1✔
831
    }
8✔
832

833
    #[inline]
834
    fn set_last_modified(&mut self, value: &str) -> Result<(), BuildInItemError> {
8✔
835
        self.last_modified = value.parse().map_err(|e| BuildInItemError {
10✔
836
            source: value.to_string(),
1✔
837
            kind: BuildInItemErrorKind::LastModified(e),
1✔
838
        })?;
2✔
839
        Ok(())
7✔
840
    }
8✔
841

842
    #[inline]
843
    fn set_etag(&mut self, value: &str) -> Result<(), BuildInItemError> {
7✔
844
        self.etag = value.to_string();
7✔
845
        Ok(())
7✔
846
    }
7✔
847

848
    #[inline]
849
    fn set_type(&mut self, value: &str) -> Result<(), BuildInItemError> {
7✔
850
        self._type = value.to_string();
7✔
851
        Ok(())
7✔
852
    }
7✔
853

854
    #[inline]
855
    fn set_size(&mut self, size: &str) -> Result<(), BuildInItemError> {
8✔
856
        self.size = size.parse().map_err(|e| BuildInItemError {
12✔
857
            source: size.to_string(),
2✔
858
            kind: BuildInItemErrorKind::Size(e),
2✔
859
        })?;
4✔
860
        Ok(())
6✔
861
    }
8✔
862

863
    #[inline]
864
    fn set_storage_class(&mut self, storage_class: &str) -> Result<(), BuildInItemError> {
8✔
865
        self.storage_class = StorageClass::new(storage_class).ok_or(BuildInItemError {
16✔
866
            source: storage_class.to_string(),
8✔
867
            kind: BuildInItemErrorKind::InvalidStorageClass,
8✔
868
        })?;
1✔
869
        Ok(())
7✔
870
    }
8✔
871
}
872

873
/// Xml 转化为内置 Object 时的错误集合
874
#[derive(Debug)]
10✔
875
#[non_exhaustive]
876
pub struct BuildInItemError {
877
    source: String,
878
    kind: BuildInItemErrorKind,
5✔
879
}
880

881
impl BuildInItemError {
882
    #[cfg(test)]
883
    pub(crate) fn test_new() -> Self {
2✔
884
        Self {
2✔
885
            source: "foo".to_string(),
2✔
886
            kind: BuildInItemErrorKind::InvalidStorageClass,
2✔
887
        }
888
    }
2✔
889
}
890

891
impl Display for BuildInItemError {
892
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6✔
893
        use BuildInItemErrorKind::*;
894
        let kind = match &self.kind {
6✔
895
            Size(_) => "size",
2✔
896
            BasePath(_) => "base-path",
1✔
897
            LastModified(_) => "last-modified",
1✔
898
            InvalidStorageClass => "storage-class",
2✔
899
        };
900
        write!(f, "parse {kind} failed, gived str: {}", self.source)
6✔
901
    }
6✔
902
}
903

904
impl Error for BuildInItemError {
905
    fn source(&self) -> Option<&(dyn Error + 'static)> {
4✔
906
        use BuildInItemErrorKind::*;
907
        match &self.kind {
4✔
908
            Size(e) => Some(e),
1✔
909
            BasePath(e) => Some(e),
1✔
910
            LastModified(e) => Some(e),
1✔
911
            InvalidStorageClass => None,
1✔
912
        }
913
    }
4✔
914
}
915

916
/// Xml 转化为内置 Object 时的错误集合
917
#[derive(Debug)]
5✔
918
#[non_exhaustive]
919
enum BuildInItemErrorKind {
920
    /// 转换数字类型的错误
921
    Size(ParseIntError),
1✔
922

923
    /// 转换为 ObjectPath 时的错误
924
    BasePath(InvalidObjectPath),
1✔
925

926
    /// 转换日期格式的错误
927
    LastModified(chrono::ParseError),
1✔
928

929
    // /// 接收 Xml 转换时的错误
930
    // Xml(quick_xml::Error),
931
    /// 非法的 StorageClass
932
    InvalidStorageClass,
933
}
934

935
impl<P: PointerFamily, Item: RefineObject<E>, E: Error + 'static>
936
    RefineObjectList<Item, ObjectListError, E> for ObjectList<P, Item, E>
937
{
938
    #[inline]
939
    fn set_key_count(&mut self, key_count: &str) -> Result<(), ObjectListError> {
7✔
940
        self.key_count = key_count.parse().map_err(|e| ObjectListError {
11✔
941
            source: key_count.to_owned(),
2✔
942
            kind: ObjectListErrorKind::KeyCount(e),
2✔
943
        })?;
4✔
944
        Ok(())
5✔
945
    }
7✔
946

947
    #[inline]
948
    fn set_prefix(&mut self, prefix: &str) -> Result<(), ObjectListError> {
9✔
949
        if prefix.is_empty() {
9✔
950
            self.prefix = None;
7✔
951
        } else {
952
            let mut string = String::from(prefix);
2✔
953
            string += "/";
2✔
954
            self.prefix = Some(string.parse().map_err(|e| ObjectListError {
4✔
955
                source: prefix.to_owned(),
1✔
956
                kind: ObjectListErrorKind::Prefix(e),
1✔
957
            })?)
2✔
958
        }
2✔
959
        Ok(())
8✔
960
    }
9✔
961

962
    #[inline]
963
    fn set_common_prefix(
2✔
964
        &mut self,
965
        list: &[std::borrow::Cow<'_, str>],
966
    ) -> Result<(), ObjectListError> {
967
        for val in list.iter() {
2✔
968
            self.common_prefixes
1✔
969
                .push(val.parse().map_err(|e| ObjectListError {
3✔
970
                    source: val.to_string(),
1✔
971
                    kind: ObjectListErrorKind::CommonPrefix(e),
1✔
972
                })?);
2✔
973
        }
974
        Ok(())
1✔
975
    }
2✔
976

977
    #[inline]
978
    fn set_max_keys(&mut self, max_keys: &str) -> Result<(), ObjectListError> {
9✔
979
        self.max_keys = max_keys.parse().map_err(|e| ObjectListError {
13✔
980
            source: max_keys.to_string(),
2✔
981
            kind: ObjectListErrorKind::MaxKeys(e),
2✔
982
        })?;
4✔
983
        Ok(())
7✔
984
    }
9✔
985

986
    #[inline]
987
    fn set_next_continuation_token_str(&mut self, token: &str) -> Result<(), ObjectListError> {
1✔
988
        self.next_continuation_token = token.to_owned();
1✔
989
        Ok(())
1✔
990
    }
1✔
991

992
    #[inline]
993
    fn set_list(&mut self, list: Vec<Item>) -> Result<(), ObjectListError> {
5✔
994
        self.object_list = list;
5✔
995
        Ok(())
5✔
996
    }
5✔
997
}
998

999
/// decode xml to object list error collection
1000
#[derive(Debug)]
10✔
1001
#[non_exhaustive]
1002
pub struct ObjectListError {
1003
    source: String,
1004
    kind: ObjectListErrorKind,
5✔
1005
}
1006

1007
impl ObjectListError {
1008
    #[cfg(test)]
1009
    pub(crate) fn test_new() -> Self {
1✔
1010
        Self {
1✔
1011
            source: "foo".to_string(),
1✔
1012
            kind: ObjectListErrorKind::Bar,
1✔
1013
        }
1014
    }
1✔
1015
}
1016

1017
impl Display for ObjectListError {
1018
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
7✔
1019
        use ObjectListErrorKind::*;
1020
        let kind: &str = match &self.kind {
7✔
1021
            KeyCount(_) => "key-count",
2✔
1022
            Prefix(_) => "prefix",
1✔
1023
            CommonPrefix(_) => "common-prefix",
1✔
1024
            MaxKeys(_) => "max-keys",
2✔
1025
            #[cfg(test)]
1026
            Bar => "bar",
1✔
1027
        };
1028
        write!(f, "parse {kind} failed, gived str: {}", self.source)
7✔
1029
    }
7✔
1030
}
1031

1032
impl Error for ObjectListError {
1033
    fn source(&self) -> Option<&(dyn Error + 'static)> {
4✔
1034
        use ObjectListErrorKind::*;
1035
        match &self.kind {
4✔
1036
            KeyCount(e) | MaxKeys(e) => Some(e),
2✔
1037
            Prefix(e) | CommonPrefix(e) => Some(e),
2✔
1038
            #[cfg(test)]
1039
            Bar => None,
×
1040
        }
1041
    }
4✔
1042
}
1043

1044
impl ListError for ObjectListError {}
1045

1046
/// decode xml to object list error collection
1047
#[derive(Debug)]
5✔
1048
#[non_exhaustive]
1049
enum ObjectListErrorKind {
1050
    /// when covert key_count failed ,return this error
1051
    KeyCount(ParseIntError),
1✔
1052
    /// when covert prefix failed ,return this error
1053
    Prefix(InvalidObjectDir),
1✔
1054
    /// when covert common_prefix failed ,return this error
1055
    CommonPrefix(InvalidObjectDir),
1✔
1056
    /// when covert max_keys failed ,return this error
1057
    MaxKeys(ParseIntError),
1✔
1058
    #[cfg(test)]
1059
    Bar,
1060
}
1061

1062
impl Client {
1063
    /// 查询默认 bucket 的文件列表
1064
    ///
1065
    /// 查询条件参数有多种方式,具体参考 [`get_object_list`] 文档
1066
    ///
1067
    /// [`get_object_list`]: crate::bucket::Bucket::get_object_list
1068
    #[inline(always)]
1069
    pub async fn get_object_list<Q: IntoIterator<Item = (QueryKey, QueryValue)>>(
3✔
1070
        &self,
3✔
1071
        query: Q,
3✔
1072
    ) -> Result<ObjectList, ExtractListError> {
6✔
1073
        self.get_object_list2(Query::from_iter(query)).await
3✔
1074
    }
6✔
1075

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

1080
        let (bucket_url, resource) = bucket.get_url_resource(&query);
3✔
1081
        let bucket_arc = Arc::new(bucket.clone());
3✔
1082

1083
        let mut list = ObjectList::<ArcPointer> {
3✔
1084
            object_list: Vec::with_capacity(query.get_max_keys()),
3✔
1085
            bucket,
3✔
1086
            ..Default::default()
3✔
1087
        };
3✔
1088

1089
        let response = self.builder(Method::GET, bucket_url, resource)?;
3✔
1090
        let content = response.send_adjust_error().await?;
3✔
1091

1092
        list.decode(&content.text().await?, || {
6✔
1093
            Object::from_bucket(bucket_arc.clone())
3✔
1094
        })?;
8✔
1095

1096
        list.set_client(Arc::new(self.clone()));
1✔
1097
        list.set_search_query(query);
1✔
1098

1099
        Ok(list)
1✔
1100
    }
7✔
1101

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

1200
        self.base_object_list2(&name, &query, list, init_object)
1201
            .await
1202
    }
1203

1204
    /// # 可将 object 列表导出到外部类型(关注性能)
1205
    pub async fn base_object_list2<List, Item, F, E: ListError, ItemErr: Error + 'static>(
1206
        &self,
1207
        name: &BucketName,
1208
        query: &Query,
1209
        list: &mut List,
1210
        init_object: F,
1211
    ) -> Result<(), ExtractListError>
1212
    where
1213
        List: RefineObjectList<Item, E, ItemErr>,
1214
        Item: RefineObject<ItemErr>,
1215
        F: FnMut() -> Item,
1216
    {
1217
        let (bucket_url, resource) = get_url_resource_with_bucket(self.as_ref(), name, query);
1218

1219
        let response = self.builder(Method::GET, bucket_url, resource)?;
1220
        let content = response.send_adjust_error().await?;
1221

1222
        list.decode(&content.text().await?, init_object)?;
1223

1224
        Ok(())
1225
    }
1226
}
1227

1228
/// 为 [`base_object_list`] 方法,返回一个统一的 Error
1229
///
1230
/// [`base_object_list`]: crate::client::Client::base_object_list
1231
#[derive(Debug)]
8✔
1232
#[non_exhaustive]
1233
pub struct ExtractListError {
1234
    pub(crate) kind: ExtractListErrorKind,
4✔
1235
}
1236

1237
/// [`ExtractListError`] 类型的枚举
1238
///
1239
/// [`ExtractListError`]: crate::object::ExtractListError
1240
#[derive(Debug)]
4✔
1241
#[non_exhaustive]
1242
pub(crate) enum ExtractListErrorKind {
1243
    #[doc(hidden)]
1244
    Builder(BuilderError),
3✔
1245

1246
    #[doc(hidden)]
1247
    Reqwest(reqwest::Error),
×
1248

1249
    /// 解析 xml 错误
1250
    Decode(InnerListError),
×
1251

1252
    /// 用于 Stream
1253
    NoMoreFile,
1254
}
1255

1256
impl From<InnerListError> for ExtractListError {
1257
    fn from(value: InnerListError) -> Self {
4✔
1258
        use ExtractListErrorKind::*;
1259
        Self {
4✔
1260
            kind: Decode(value),
4✔
1261
        }
1262
    }
4✔
1263
}
1264
impl From<BuilderError> for ExtractListError {
1265
    fn from(value: BuilderError) -> Self {
5✔
1266
        use ExtractListErrorKind::*;
1267
        Self {
5✔
1268
            kind: Builder(value),
5✔
1269
        }
1270
    }
5✔
1271
}
1272
impl From<reqwest::Error> for ExtractListError {
1273
    fn from(value: reqwest::Error) -> Self {
1✔
1274
        use ExtractListErrorKind::*;
1275
        Self {
1✔
1276
            kind: Reqwest(value),
1✔
1277
        }
1278
    }
1✔
1279
}
1280
impl Display for ExtractListError {
1281
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
8✔
1282
        use ExtractListErrorKind::*;
1283
        match &self.kind {
8✔
1284
            Builder(_) => "builder error".fmt(f),
1✔
1285
            Reqwest(_) => "reqwest error".fmt(f),
1✔
1286
            Decode(_) => "decode xml failed".fmt(f),
4✔
1287
            NoMoreFile => "no more file".fmt(f),
2✔
1288
        }
1289
    }
8✔
1290
}
1291
impl Error for ExtractListError {
1292
    fn source(&self) -> Option<&(dyn Error + 'static)> {
7✔
1293
        use ExtractListErrorKind::*;
1294
        match &self.kind {
7✔
1295
            Builder(e) => Some(e),
1✔
1296
            Reqwest(e) => Some(e),
1✔
1297
            Decode(e) => e.get_source(),
4✔
1298
            NoMoreFile => None,
1✔
1299
        }
1300
    }
7✔
1301
}
1302

1303
#[cfg(feature = "blocking")]
1304
impl ClientRc {
1305
    /// 查询默认 bucket 的文件列表
1306
    ///
1307
    /// 查询条件参数有多种方式,具体参考 [`get_object_list`](../bucket/struct.Bucket.html#method.get_object_list) 文档
1308
    pub fn get_object_list<Q: IntoIterator<Item = (QueryKey, QueryValue)>>(
1✔
1309
        self,
1310
        query: Q,
1311
    ) -> Result<ObjectList<RcPointer>, ExtractListError> {
1312
        let name = self.get_bucket_name();
1✔
1313
        let bucket = BucketBase::new(name.clone(), self.get_endpoint().to_owned());
1✔
1314

1315
        let mut list = ObjectList::<RcPointer>::default();
1✔
1316
        list.set_bucket(bucket.clone());
1✔
1317

1318
        let bucket_arc = Rc::new(bucket);
1✔
1319

1320
        let query = Query::from_iter(query);
1✔
1321

1322
        let (bucket_url, resource) = bucket_arc.get_url_resource(&query);
1✔
1323

1324
        let response = self.builder(Method::GET, bucket_url, resource)?;
1✔
1325
        let content = response.send_adjust_error()?;
1✔
1326

1327
        list.decode(&content.text()?, || {
2✔
1328
            Object::<RcPointer>::from_bucket(bucket_arc.clone())
1✔
1329
        })?;
2✔
1330

1331
        list.set_client(Rc::new(self));
1✔
1332
        list.set_search_query(query);
1✔
1333

1334
        Ok(list)
1✔
1335
    }
1✔
1336

1337
    /// 可将 object 列表导出到外部 struct
1338
    #[inline]
1339
    pub fn base_object_list<
1✔
1340
        Name: Into<BucketName>,
1341
        Q: IntoIterator<Item = (QueryKey, QueryValue)>,
1342
        List,
1343
        Item,
1344
        F,
1345
        E: ListError,
1346
        ItemErr: Error + 'static,
1347
    >(
1348
        &self,
1349
        name: Name,
1350
        query: Q,
1351
        list: &mut List,
1352
        init_object: F,
1353
    ) -> Result<(), ExtractListError>
1354
    where
1355
        List: RefineObjectList<Item, E, ItemErr>,
1356
        Item: RefineObject<ItemErr>,
1357
        F: FnMut() -> Item,
1358
    {
1359
        let bucket = BucketBase::new(name.into(), self.get_endpoint().to_owned());
1✔
1360

1361
        let query = Query::from_iter(query);
1✔
1362
        let (bucket_url, resource) = bucket.get_url_resource(&query);
1✔
1363

1364
        let response = self.builder(Method::GET, bucket_url, resource)?;
1✔
1365
        let content = response.send_adjust_error()?;
1✔
1366

1367
        list.decode(&content.text()?, init_object)?;
1✔
1368

1369
        Ok(())
1✔
1370
    }
1✔
1371
}
1372

1373
#[cfg(feature = "blocking")]
1374
impl Iterator for ObjectList<RcPointer> {
1375
    type Item = ObjectList<RcPointer>;
1376
    fn next(&mut self) -> Option<Self> {
×
1377
        if !self.next_continuation_token.is_empty() {
×
1378
            self.search_query
×
1379
                .insert(CONTINUATION_TOKEN, self.next_continuation_token.to_owned());
×
1380
            self.get_object_list().ok()
×
1381
        } else {
1382
            None
×
1383
        }
1384
    }
×
1385
}
1386

1387
// use std::task::Poll::{self, Ready};
1388

1389
// impl Stream for ObjectList<ArcPointer> {
1390
//     type Item = ObjectList<ArcPointer>;
1391

1392
//     fn poll_next(
1393
//         self: std::pin::Pin<&mut Self>,
1394
//         cx: &mut std::task::Context<'_>,
1395
//     ) -> Poll<Option<Self::Item>> {
1396
//         match self.next_query() {
1397
//             Some(query) => {
1398
//                 let mut url = self.bucket.to_url();
1399
//                 url.set_search_query(&query);
1400

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

1403
//                 let builder = self.builder(Method::GET, url, canonicalized);
1404
//                 match builder {
1405
//                     Err(err) => Ready(None),
1406
//                     Ok(builder) => {
1407
//                         let waker = cx.waker().clone();
1408

1409
//                         std::thread::spawn(move || {
1410
//                             let response = builder.send_adjust_error();
1411

1412
//                             let response = futures::executor::block_on(response);
1413
//                             let text = response.unwrap().text();
1414
//                             let text = futures::executor::block_on(text);
1415

1416
//                             let text = text.unwrap();
1417

1418
//                             let bucket_arc = Arc::new(self.bucket);
1419

1420
//                             let init_object = || {
1421
//                                 let object = Object::<ArcPointer>::default();
1422
//                                 object.base.set_bucket(bucket_arc.clone());
1423
//                                 object
1424
//                             };
1425

1426
//                             self.decode(&text, init_object).unwrap();
1427

1428
//                             self.set_search_query(query);
1429

1430
//                             waker.wake();
1431
//                         });
1432

1433
//                         Poll::Pending
1434
//                     }
1435
//                 }
1436
//             }
1437
//             None => Ready(None),
1438
//         }
1439
//     }
1440
// }
1441

1442
#[oss_gen_rc]
1443
impl PartialEq<Object<ArcPointer>> for Object<ArcPointer> {
1444
    #[inline]
1445
    fn eq(&self, other: &Object<ArcPointer>) -> bool {
8✔
1446
        self.base == other.base
8✔
1447
            && self.last_modified == other.last_modified
6✔
1448
            && self.etag == other.etag
5✔
1449
            && self._type == other._type
4✔
1450
            && self.size == other.size
3✔
1451
            && self.storage_class == other.storage_class
2✔
1452
    }
8✔
1453
}
1454

1455
impl<T: PointerFamily> PartialEq<DateTime<Utc>> for Object<T> {
1456
    #[inline]
1457
    fn eq(&self, other: &DateTime<Utc>) -> bool {
1458
        &self.last_modified == other
1459
    }
1460
}
1461

1462
impl<T: PointerFamily> PartialEq<u64> for Object<T> {
1463
    #[inline]
1464
    fn eq(&self, other: &u64) -> bool {
1465
        &self.size == other
1466
    }
1467
}
1468

1469
#[oss_gen_rc]
1470
impl PartialEq<ObjectBase<ArcPointer>> for Object<ArcPointer> {
1471
    #[inline]
1472
    fn eq(&self, other: &ObjectBase<ArcPointer>) -> bool {
×
1473
        &self.base == other
×
1474
    }
×
1475
}
1476

1477
/// 未来计划支持的功能
1478
#[derive(Default)]
×
1479
#[doc(hidden)]
1480
pub struct PutObject<'a> {
1481
    pub forbid_overwrite: bool,
×
1482
    pub server_side_encryption: Option<Encryption>,
×
1483
    pub server_side_data_encryption: Option<Encryption>,
×
1484
    pub server_side_encryption_key_id: Option<&'a str>,
×
1485
    pub object_acl: ObjectAcl,
×
1486
    pub storage_class: StorageClass,
×
1487
    pub tagging: Option<&'a str>,
×
1488
}
1489

1490
/// 未来计划支持的功能
1491
#[derive(Default)]
×
1492
#[doc(hidden)]
1493
pub enum Encryption {
1494
    #[default]
1495
    Aes256,
1496
    Kms,
1497
    Sm4,
1498
}
1499

1500
/// 未来计划支持的功能
1501
#[derive(Default)]
×
1502
#[doc(hidden)]
1503
pub enum ObjectAcl {
1504
    #[default]
1505
    Default,
1506
    Private,
1507
    PublicRead,
1508
    PublicReadWrite,
1509
}
1510

1511
/// 存储类型
1512
#[derive(Debug, Default, Clone, PartialEq, Eq)]
72✔
1513
#[non_exhaustive]
1514
pub struct StorageClass {
1515
    kind: StorageClassKind,
36✔
1516
}
1517

1518
#[derive(Debug, Default, Clone, PartialEq, Eq)]
44✔
1519
#[non_exhaustive]
1520
enum StorageClassKind {
1521
    /// Standard 默认
1522
    #[default]
1523
    Standard,
1524
    /// IA
1525
    IA,
1526
    /// Archive
1527
    Archive,
1528
    /// ColdArchive
1529
    ColdArchive,
1530
}
1531

1532
impl StorageClass {
1533
    /// Archive
1534
    pub const ARCHIVE: Self = Self {
1535
        kind: StorageClassKind::Archive,
1536
    };
1537
    /// IA
1538
    pub const IA: Self = Self {
1539
        kind: StorageClassKind::IA,
1540
    };
1541
    /// Standard
1542
    pub const STANDARD: Self = Self {
1543
        kind: StorageClassKind::Standard,
1544
    };
1545
    /// ColdArchive
1546
    pub const COLD_ARCHIVE: Self = Self {
1547
        kind: StorageClassKind::ColdArchive,
1548
    };
1549

1550
    /// init StorageClass
1551
    pub fn new(s: &str) -> Option<StorageClass> {
23✔
1552
        let start_char = s.chars().next()?;
23✔
1553

1554
        let kind = match start_char {
22✔
1555
            'a' | 'A' => StorageClassKind::Archive,
4✔
1556
            'i' | 'I' => StorageClassKind::IA,
2✔
1557
            's' | 'S' => StorageClassKind::Standard,
10✔
1558
            'c' | 'C' => StorageClassKind::ColdArchive,
2✔
1559
            _ => return None,
4✔
1560
        };
1561
        Some(Self { kind })
18✔
1562
    }
23✔
1563
}
1564

1565
/// 未来计划支持的功能
1566
#[derive(Default)]
×
1567
#[doc(hidden)]
1568
pub struct CopyObject<'a> {
1569
    pub forbid_overwrite: bool,
×
1570
    pub copy_source: &'a str,
×
1571
    pub copy_source_if_match: Option<&'a str>,
×
1572
    pub copy_source_if_none_match: Option<&'a str>,
×
1573
    pub copy_source_if_unmodified_since: Option<&'a str>,
×
1574
    pub copy_source_if_modified_since: Option<&'a str>,
×
1575
    pub metadata_directive: CopyDirective,
×
1576
    pub server_side_encryption: Option<Encryption>,
×
1577
    pub server_side_encryption_key_id: Option<&'a str>,
×
1578
    pub object_acl: ObjectAcl,
×
1579
    pub storage_class: StorageClass,
×
1580
    pub tagging: Option<&'a str>,
×
1581
    pub tagging_directive: CopyDirective,
×
1582
}
1583

1584
/// 未来计划支持的功能
1585
#[derive(Default)]
×
1586
#[doc(hidden)]
1587
pub enum CopyDirective {
1588
    #[default]
1589
    Copy,
1590
    Replace,
1591
}
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