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

tu6ge / oss-rs / 5791781892

pending completion
5791781892

push

github

web-flow
feat(decode)!: remove init object fn, and add InitObject trait (#25)

* feat(decode)!: change init object fn

* feat(blocking)

* style(doc)

* feat(decode)!: change init object fn

* feat(object)!: change get_next_base

change get_next_base return type , when has not next page condition
return `None`, or try get next page data, if success
return `Some(Ok(_))`, failed return `Some(Err(_))`

* feat(object): merge error type

merge object_init error and object item error

* feat(decode)!: change init_object

before return `T`, now return `Option<T>`

* fix

* fix

* feat(object)!: create InitObject trait

通过实现 InitObject trait 来初始化 object 类型 (自定义类型)

* fix

* fix

* feat(bucket)!: support InitObject

* style

* feat(bucket)!: change base_bucket_info

58 of 58 new or added lines in 5 files covered. (100.0%)

6200 of 6443 relevant lines covered (96.23%)

9.31 hits per line

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

86.64
/src/decode.rs
1
//! # 解析 aliyun OSS 接口返回的 xml 原始数据的 trait
×
2
//! 开发者可利用该 trait 将 xml 高效地转化为 rust 的 struct 或者 enum 类型
3
//!
4
//! 本 trait 是零拷贝的,所以可以做到很高效
5
//!
6
//! ## 示例
7
//! ```
8
//! use aliyun_oss_client::decode::{RefineObject, RefineObjectList};
9
//! use thiserror::Error;
10
//!
11
//! struct MyFile {
12
//!     key: String,
13
//!     #[allow(dead_code)]
14
//!     other: String,
15
//! }
16
//! impl RefineObject<MyError> for MyFile {
17
//!
18
//!     fn set_key(&mut self, key: &str) -> Result<(), MyError> {
19
//!         self.key = key.to_string();
20
//!         Ok(())
21
//!     }
22
//! }
23
//!
24
//! #[derive(Default)]
25
//! struct MyBucket {
26
//!     name: String,
27
//!     files: Vec<MyFile>,
28
//! }
29
//!
30
//! impl RefineObjectList<MyFile, MyError> for MyBucket {
31
//!
32
//!     fn set_name(&mut self, name: &str) -> Result<(), MyError> {
33
//!         self.name = name.to_string();
34
//!         Ok(())
35
//!     }
36
//!     fn set_list(&mut self, list: Vec<MyFile>) -> Result<(), MyError> {
37
//!         self.files = list;
38
//!         Ok(())
39
//!     }
40
//! }
41
//!
42
//! use aliyun_oss_client::DecodeListError;
43
//!
44
//! // 自定义的 Error 需要实现这个 Trait,用于内部解析方法在调用时,统一处理异常
45
//! #[derive(Debug, Error, DecodeListError)]
46
//! #[error("my error")]
47
//! struct MyError {}
48
//!
49
//! fn get_with_xml() -> Result<(), aliyun_oss_client::decode::InnerListError> {
50
//!     // 这是阿里云接口返回的原始数据
51
//!     let xml = r#"<?xml version="1.0" encoding="UTF-8"?>
52
//!         <ListBucketResult>
53
//!           <Name>foo_bucket</Name>
54
//!           <Prefix></Prefix>
55
//!           <MaxKeys>100</MaxKeys>
56
//!           <Delimiter></Delimiter>
57
//!           <IsTruncated>false</IsTruncated>
58
//!           <NextContinuationToken>CiphcHBzL1RhdXJpIFB1Ymxpc2ggQXBwXzAuMS42X3g2NF9lbi1VUy5tc2kQAA--</NextContinuationToken>
59
//!           <Contents>
60
//!             <Key>9AB932LY.jpeg</Key>
61
//!             <LastModified>2022-06-26T09:53:21.000Z</LastModified>
62
//!             <ETag>"F75A15996D0857B16FA31A3B16624C26"</ETag>
63
//!             <Type>Normal</Type>
64
//!             <Size>18027</Size>
65
//!             <StorageClass>Standard</StorageClass>
66
//!           </Contents>
67
//!           <KeyCount>3</KeyCount>
68
//!         </ListBucketResult>"#;
69
//!
70
//!     // 除了设置Default 外,还可以做更多设置
71
//!     let mut bucket = MyBucket::default();
72
//!
73
//!     // 利用闭包对 MyFile 做一下初始化设置
74
//!     // 可以根据传入的列表信息,为元素添加更多能力
75
//!     fn init_file(_list: &mut MyBucket) -> Option<MyFile> {
76
//!         Some(MyFile {
77
//!             key: String::default(),
78
//!             other: "abc".to_string(),
79
//!         })
80
//!     }
81
//!
82
//!     bucket.decode(xml, init_file)?;
83
//!
84
//!     assert!(bucket.name == "foo_bucket");
85
//!     assert!(bucket.files[0].key == "9AB932LY.jpeg");
86
//!
87
//!     Ok(())
88
//! }
89
//!
90
//! let res = get_with_xml();
91
//!
92
//! if let Err(err) = res {
93
//!     eprintln!("{}", err);
94
//! }
95
//! ```
96

97
use std::borrow::Cow;
98
use std::error::Error as StdError;
99
use std::fmt::Display;
100
use std::num::ParseIntError;
101

102
use quick_xml::{events::Event, Reader};
103

104
use crate::types::InvalidEndPoint;
105
#[cfg(feature = "core")]
106
use crate::{
107
    errors::OssError,
108
    types::object::{InvalidObjectDir, InvalidObjectPath},
109
};
110

111
#[cfg(test)]
112
mod test;
113

114
const PREFIX: &[u8] = b"Prefix";
115
const COMMON_PREFIX: &[u8] = b"CommonPrefixes";
116
const NAME: &[u8] = b"Name";
117
const MAX_KEYS: &[u8] = b"MaxKeys";
118
const KEY_COUNT: &[u8] = b"KeyCount";
119
const IS_TRUNCATED: &[u8] = b"IsTruncated";
120
const NEXT_CONTINUATION_TOKEN: &[u8] = b"NextContinuationToken";
121
const KEY: &[u8] = b"Key";
122
const LAST_MODIFIED: &[u8] = b"LastModified";
123
const E_TAG: &[u8] = b"ETag";
124
const TYPE: &[u8] = b"Type";
125
const SIZE: &[u8] = b"Size";
126
const STORAGE_CLASS: &[u8] = b"StorageClass";
127
const BUCKET: &[u8] = b"Bucket";
128

129
const CREATION_DATE: &[u8] = b"CreationDate";
130
const EXTRANET_ENDPOINT: &[u8] = b"ExtranetEndpoint";
131
const INTRANET_ENDPOINT: &[u8] = b"IntranetEndpoint";
132
const LOCATION: &[u8] = b"Location";
133

134
const MARKER: &[u8] = b"Marker";
135
const NEXT_MARKER: &[u8] = b"NextMarker";
136
const ID: &[u8] = b"ID";
137
const DISPLAY_NAME: &[u8] = b"DisplayName";
138
const CONTENTS: &[u8] = b"Contents";
139

140
const TRUE: &str = "true";
141

142
/// 将一个 object 的数据写入到 rust 类型
143
pub trait RefineObject<Error: StdError + 'static> {
144
    /// 提取 key
145
    fn set_key(&mut self, _key: &str) -> Result<(), Error> {
5✔
146
        Ok(())
5✔
147
    }
5✔
148

149
    /// 提取最后修改时间
150
    fn set_last_modified(&mut self, _last_modified: &str) -> Result<(), Error> {
3✔
151
        Ok(())
3✔
152
    }
3✔
153

154
    /// 提取 etag
155
    fn set_etag(&mut self, _etag: &str) -> Result<(), Error> {
3✔
156
        Ok(())
3✔
157
    }
3✔
158

159
    /// 提取 type
160
    fn set_type(&mut self, _type: &str) -> Result<(), Error> {
3✔
161
        Ok(())
3✔
162
    }
3✔
163

164
    /// 提取 size
165
    fn set_size(&mut self, _size: &str) -> Result<(), Error> {
3✔
166
        Ok(())
3✔
167
    }
3✔
168

169
    /// 提取 storage_class
170
    fn set_storage_class(&mut self, _storage_class: &str) -> Result<(), Error> {
3✔
171
        Ok(())
3✔
172
    }
3✔
173

174
    /// 对单个 objcet 部分的 xml 内容进行解析
175
    fn decode(&mut self, xml: &str) -> Result<(), InnerItemError> {
16✔
176
        let mut reader = Reader::from_str(xml);
16✔
177
        let mut buf = Vec::with_capacity(xml.len());
16✔
178
        loop {
179
            match reader.read_event_into(&mut buf) {
184✔
180
                Ok(Event::Start(e)) => match e.name().as_ref() {
154✔
181
                    KEY => self.set_key(&reader.read_text(e.to_end().name())?)?,
101✔
182
                    LAST_MODIFIED => {
69✔
183
                        self.set_last_modified(&reader.read_text(e.to_end().name())?)?
14✔
184
                    }
14✔
185
                    E_TAG => {
42✔
186
                        let tag = reader.read_text(e.to_end().name())?;
14✔
187
                        self.set_etag(tag.trim_matches('"'))?;
14✔
188
                    }
14✔
189
                    TYPE => self.set_type(&reader.read_text(e.to_end().name())?)?,
14✔
190
                    SIZE => {
191
                        self.set_size(&reader.read_text(e.to_end().name())?)?;
14✔
192
                    }
193
                    STORAGE_CLASS => {
194
                        self.set_storage_class(&reader.read_text(e.to_end().name())?)?;
13✔
195
                    }
196
                    _ => (),
197
                },
85✔
198
                Ok(Event::Eof) => {
199
                    break;
200
                } // exits the loop when reaching end of file
201
                Err(e) => {
×
202
                    return Err(InnerItemError::from(e));
×
203
                }
204
                _ => (), //
×
205
            }
184✔
206
            buf.clear();
168✔
207
        }
208
        Ok(())
15✔
209
    }
16✔
210
}
211

212
/// 将 object 列表写入到 rust 类型
213
pub trait RefineObjectList<T, Error, ItemErr = Error>
214
where
215
    T: RefineObject<ItemErr>,
216
    Error: ListError,
217
    ItemErr: StdError + 'static,
218
{
219
    /// 提取 bucket 名
220
    fn set_name(&mut self, _name: &str) -> Result<(), Error> {
9✔
221
        Ok(())
9✔
222
    }
9✔
223

224
    /// 提取前缀
225
    fn set_prefix(&mut self, _prefix: &str) -> Result<(), Error> {
1✔
226
        Ok(())
1✔
227
    }
1✔
228

229
    /// 提取文件目录
230
    fn set_common_prefix(&mut self, _list: &[Cow<'_, str>]) -> Result<(), Error> {
×
231
        Ok(())
×
232
    }
×
233

234
    /// 提取 max_keys
235
    fn set_max_keys(&mut self, _max_keys: &str) -> Result<(), Error> {
1✔
236
        Ok(())
1✔
237
    }
1✔
238

239
    /// 提取 key_count
240
    fn set_key_count(&mut self, _key_count: &str) -> Result<(), Error> {
1✔
241
        Ok(())
1✔
242
    }
1✔
243

244
    /// 提取翻页信息 token
245
    fn set_next_continuation_token_str(&mut self, _token: &str) -> Result<(), Error> {
×
246
        Ok(())
×
247
    }
×
248

249
    /// 提取 object 列表
250
    fn set_list(&mut self, _list: Vec<T>) -> Result<(), Error> {
3✔
251
        Ok(())
3✔
252
    }
3✔
253

254
    /// 用于解析 common prefix
255
    fn decode_common_prefix(&mut self, xml: &str) -> Result<(), InnerListError> {
1✔
256
        let mut reader = Reader::from_str(xml);
1✔
257
        let mut buf = Vec::with_capacity(xml.len());
1✔
258
        let mut prefix_vec = Vec::new();
1✔
259

260
        loop {
261
            match reader.read_event_into(&mut buf) {
5✔
262
                Ok(Event::Start(e)) => {
2✔
263
                    if e.name().as_ref() == PREFIX {
2✔
264
                        prefix_vec.push(reader.read_text(e.to_end().name())?);
2✔
265
                    }
266
                }
2✔
267
                Ok(Event::Eof) => {
268
                    break;
269
                } // exits the loop when reaching end of file
270
                Err(e) => {
×
271
                    return Err(InnerListError::from(e));
×
272
                }
273
                _ => (), // There are several other `Event`s we do not consider here
×
274
            }
5✔
275
            buf.clear();
4✔
276
        }
277
        self.set_common_prefix(&prefix_vec)?;
1✔
278

279
        Ok(())
1✔
280
    }
1✔
281

282
    /// # 由 xml 转 struct 的底层实现
283
    /// - `init_object` 用于初始化 object 结构体的方法
284
    fn decode<F>(&mut self, xml: &str, init_object: F) -> Result<(), InnerListError>
11✔
285
    where
286
        F: for<'a> Fn(&'a mut Self) -> Option<T>,
287
    {
288
        //println!("from_xml: {:#}", xml);
289
        let mut result = Vec::new();
11✔
290
        let mut reader = Reader::from_str(xml);
11✔
291
        reader.trim_text(true);
11✔
292
        let mut buf = Vec::with_capacity(xml.len());
11✔
293

294
        loop {
295
            match reader.read_event_into(&mut buf) {
139✔
296
                Ok(Event::Start(e)) => {
85✔
297
                    match e.name().as_ref() {
140✔
298
                        COMMON_PREFIX => {
85✔
299
                            self.decode_common_prefix(&reader.read_text(e.to_end().name())?)?;
1✔
300
                        }
301
                        PREFIX => {
84✔
302
                            self.set_prefix(&reader.read_text(e.to_end().name())?)?;
11✔
303
                        }
304
                        NAME => self.set_name(&reader.read_text(e.to_end().name())?)?,
83✔
305
                        MAX_KEYS => self.set_max_keys(&reader.read_text(e.to_end().name())?)?,
73✔
306
                        KEY_COUNT => self.set_key_count(&reader.read_text(e.to_end().name())?)?,
61✔
307
                        IS_TRUNCATED => {
30✔
308
                            //is_truncated = reader.read_text(e.to_end().name())?.to_string() == TRUE
309
                        }
310
                        NEXT_CONTINUATION_TOKEN => {
21✔
311
                            self.set_next_continuation_token_str(
1✔
312
                                &reader.read_text(e.to_end().name())?,
1✔
313
                            )?;
1✔
314
                        }
315
                        CONTENTS => {
316
                            // <Contents></Contents> 标签内部的数据对应单个 object 信息
317
                            let mut object =
318
                                init_object(self).ok_or(InnerListError::init_error(true))?;
15✔
319
                            object.decode(&reader.read_text(e.to_end().name())?)?;
15✔
320
                            result.push(object);
14✔
321
                        }
1✔
322
                        _ => (),
323
                    }
324
                }
85✔
325
                Ok(Event::Eof) => {
326
                    self.set_list(result)?;
8✔
327
                    break;
328
                } // exits the loop when reaching end of file
329
                Err(e) => {
×
330
                    return Err(InnerListError::from(e));
×
331
                }
332
                _ => (), // There are several other `Event`s we do not consider here
×
333
            }
139✔
334
            buf.clear();
128✔
335
        }
336

337
        Ok(())
8✔
338
    }
11✔
339
}
340

341
/// 将一个 bucket 的数据写入到 rust 类型
342
pub trait RefineBucket<Error: StdError + 'static> {
343
    /// 提取 bucket name
344
    fn set_name(&mut self, _name: &str) -> Result<(), Error> {
345
        Ok(())
346
    }
347

348
    /// 提取 bucket 创建时间
349
    fn set_creation_date(&mut self, _creation_date: &str) -> Result<(), Error> {
350
        Ok(())
351
    }
352

353
    /// 提取 location
354
    fn set_location(&mut self, _location: &str) -> Result<(), Error> {
355
        Ok(())
356
    }
357

358
    /// 提取 extranet_endpoint
359
    fn set_extranet_endpoint(&mut self, _extranet_endpoint: &str) -> Result<(), Error> {
2✔
360
        Ok(())
2✔
361
    }
2✔
362

363
    /// 提取 intranet_endpoint
364
    fn set_intranet_endpoint(&mut self, _intranet_endpoint: &str) -> Result<(), Error> {
2✔
365
        Ok(())
2✔
366
    }
2✔
367

368
    /// 提取 storage_class
369
    fn set_storage_class(&mut self, _storage_class: &str) -> Result<(), Error> {
370
        Ok(())
371
    }
372

373
    /// 解析 OSS 接口返回的 xml 数据
374
    fn decode(&mut self, xml: &str) -> Result<(), InnerItemError> {
5✔
375
        //println!("from_xml: {:#}", xml);
376
        let mut reader = Reader::from_str(xml);
5✔
377
        reader.trim_text(true);
5✔
378
        let mut buf = Vec::with_capacity(xml.len());
5✔
379

380
        loop {
381
            match reader.read_event_into(&mut buf) {
183✔
382
                Ok(Event::Start(e)) => match e.name().as_ref() {
119✔
383
                    NAME => self.set_name(&reader.read_text(e.to_end().name())?)?,
93✔
384
                    CREATION_DATE => {
83✔
385
                        self.set_creation_date(&reader.read_text(e.to_end().name())?)?
5✔
386
                    }
5✔
387
                    EXTRANET_ENDPOINT => {
67✔
388
                        self.set_extranet_endpoint(&reader.read_text(e.to_end().name())?)?
5✔
389
                    }
5✔
390
                    INTRANET_ENDPOINT => {
391
                        self.set_intranet_endpoint(&reader.read_text(e.to_end().name())?)?
5✔
392
                    }
5✔
393
                    LOCATION => self.set_location(&reader.read_text(e.to_end().name())?)?,
62✔
394
                    STORAGE_CLASS => {
395
                        self.set_storage_class(&reader.read_text(e.to_end().name())?)?
5✔
396
                    }
5✔
397
                    _ => (),
398
                },
88✔
399
                Ok(Event::Eof) => {
400
                    break;
401
                } // exits the loop when reaching end of file
402
                Err(e) => {
×
403
                    return Err(InnerItemError::from(e));
×
404
                }
405
                _ => (), // There are several other `Event`s we do not consider here
×
406
            }
183✔
407
            buf.clear();
178✔
408
        }
409
        Ok(())
5✔
410
    }
5✔
411
}
412

413
/// 将 bucket 列表的数据写入到 rust 类型
414
pub trait RefineBucketList<T: RefineBucket<ItemErr>, Error, ItemErr = Error>
415
where
416
    Error: ListError,
417
    ItemErr: StdError + 'static,
418
{
419
    /// 提取 prefix
420
    fn set_prefix(&mut self, _prefix: &str) -> Result<(), Error> {
421
        Ok(())
422
    }
423

424
    /// 提取 marker
425
    fn set_marker(&mut self, _marker: &str) -> Result<(), Error> {
426
        Ok(())
427
    }
428

429
    /// 提取 max_keys
430
    fn set_max_keys(&mut self, _max_keys: &str) -> Result<(), Error> {
431
        Ok(())
432
    }
433

434
    /// 提取 is_truncated
435
    fn set_is_truncated(&mut self, _is_truncated: bool) -> Result<(), Error> {
436
        Ok(())
437
    }
438

439
    /// 提取 next_marker
440
    fn set_next_marker(&mut self, _next_marker: &str) -> Result<(), Error> {
441
        Ok(())
442
    }
443

444
    /// 提取 id
445
    fn set_id(&mut self, _id: &str) -> Result<(), Error> {
446
        Ok(())
447
    }
448

449
    /// 提取 display_name
450
    fn set_display_name(&mut self, _display_name: &str) -> Result<(), Error> {
451
        Ok(())
452
    }
453

454
    /// 提取 bucket 列表
455
    fn set_list(&mut self, _list: Vec<T>) -> Result<(), Error> {
1✔
456
        Ok(())
1✔
457
    }
1✔
458

459
    /// 解析 OSS 接口返回的 xml 数据
460
    fn decode<F>(&mut self, xml: &str, init_bucket: F) -> Result<(), InnerListError>
3✔
461
    where
462
        F: for<'a> Fn(&'a mut Self) -> Option<T>,
463
    {
464
        let mut result = Vec::new();
3✔
465
        let mut reader = Reader::from_str(xml);
3✔
466
        reader.trim_text(true);
3✔
467
        let mut buf = Vec::with_capacity(xml.len());
3✔
468

469
        loop {
470
            match reader.read_event_into(&mut buf) {
16✔
471
                Ok(Event::Start(e)) => match e.name().as_ref() {
10✔
472
                    PREFIX => self.set_prefix(&reader.read_text(e.to_end().name())?)?,
7✔
473
                    MARKER => self.set_marker(&reader.read_text(e.to_end().name())?)?,
×
474
                    MAX_KEYS => self.set_max_keys(&reader.read_text(e.to_end().name())?)?,
5✔
475
                    IS_TRUNCATED => {
4✔
476
                        self.set_is_truncated(reader.read_text(e.to_end().name())? == TRUE)?;
×
477
                    }
478
                    NEXT_MARKER => self.set_next_marker(&reader.read_text(e.to_end().name())?)?,
3✔
479
                    ID => self.set_id(&reader.read_text(e.to_end().name())?)?,
4✔
480
                    DISPLAY_NAME => self.set_display_name(&reader.read_text(e.to_end().name())?)?,
1✔
481
                    BUCKET => {
482
                        // <Bucket></Bucket> 标签内部的数据对应单个 bucket 信息
483
                        let mut bucket =
484
                            init_bucket(self).ok_or(InnerListError::init_error(false))?;
2✔
485
                        bucket.decode(&reader.read_text(e.to_end().name())?)?;
2✔
486
                        result.push(bucket);
2✔
487
                    }
×
488
                    _ => (),
489
                },
7✔
490
                Ok(Event::Eof) => {
491
                    self.set_list(result)?;
3✔
492
                    break;
493
                } // exits the loop when reaching end of file
494
                Err(e) => {
×
495
                    return Err(InnerListError::from(e));
×
496
                }
497
                _ => (), // There are several other `Event`s we do not consider here
×
498
            }
16✔
499
            buf.clear();
13✔
500
        }
501
        Ok(())
3✔
502
    }
3✔
503
}
504

505
/// # Object 的 Error 中间层
506
/// 当外部实现 [`RefineObject`] 时,所使用的 Error ,可先转换为这个,
507
/// 变成一个已知的 Error 类型
508
///
509
/// [`RefineObject`]: crate::decode::RefineObject
510
#[derive(Debug)]
8✔
511
#[doc(hidden)]
512
#[non_exhaustive]
513
pub struct InnerItemError(Box<dyn StdError + 'static>);
4✔
514

515
impl<T: StdError + 'static> From<T> for InnerItemError {
516
    fn from(err: T) -> Self {
2✔
517
        Self(Box::new(err))
2✔
518
    }
2✔
519
}
520

521
impl Display for InnerItemError {
522
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
1✔
523
        write!(fmt, "{}", self.0)
1✔
524
    }
1✔
525
}
526

527
impl InnerItemError {
528
    #[cfg(test)]
529
    pub(crate) fn new() -> Self {
9✔
530
        #[derive(Debug)]
4✔
531
        struct MyError;
532
        impl Display for MyError {
533
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5✔
534
                "demo".fmt(f)
5✔
535
            }
5✔
536
        }
537
        impl StdError for MyError {}
538

539
        Self(Box::new(MyError {}))
9✔
540
    }
9✔
541

542
    pub fn get_source(&self) -> Option<&(dyn StdError + 'static)> {
5✔
543
        Some(self.0.as_ref())
5✔
544
    }
5✔
545
}
546

547
/// 当外部要实现 [`RefineObjectList`] 时,Error 类需要实现此 Trait
548
///
549
/// [`RefineObjectList`]: crate::decode::RefineObjectList
550
pub trait ListError: StdError + 'static {}
551

552
impl ListError for ParseIntError {}
553

554
impl ListError for InvalidEndPoint {}
555

556
#[cfg(feature = "core")]
557
impl ListError for InvalidObjectPath {}
558
#[cfg(feature = "core")]
559
impl ListError for InvalidObjectDir {}
560
#[cfg(feature = "core")]
561
impl ListError for chrono::ParseError {}
562
#[cfg(feature = "core")]
563
impl ListError for OssError {}
564

565
impl<T: ListError> From<T> for InnerListError {
566
    fn from(err: T) -> InnerListError {
3✔
567
        Self {
3✔
568
            kind: ListErrorKind::Custom(Box::new(err)),
3✔
569
        }
570
    }
3✔
571
}
572

573
/// # ObjectList 的 Error 中间层
574
/// 当外部实现 [`RefineObjectList`] 时,所使用的 Error ,可先转换为这个,
575
/// 变成一个已知的 Error 类型
576
///
577
/// [`RefineObjectList`]: crate::decode::RefineObjectList
578
#[derive(Debug)]
6✔
579
#[non_exhaustive]
580
pub struct InnerListError {
581
    kind: ListErrorKind,
3✔
582
}
583

584
impl Display for InnerListError {
585
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
6✔
586
        use ListErrorKind::*;
587
        match &self.kind {
6✔
588
            Item(item) => write!(fmt, "{}", item.0),
1✔
589
            Xml(xml) => write!(fmt, "{xml}"),
3✔
590
            Custom(out) => write!(fmt, "{out}"),
2✔
591
            InitItemFailed(is_object) => {
×
592
                if *is_object {
×
593
                    write!(fmt, "init_object failed")
×
594
                } else {
595
                    write!(fmt, "init_bucket failed")
×
596
                }
597
            }
598
        }
599
    }
6✔
600
}
601

602
impl InnerListError {
603
    #[cfg(test)]
604
    #[allow(dead_code)]
605
    pub(crate) fn from_xml() -> Self {
5✔
606
        Self {
5✔
607
            kind: ListErrorKind::Xml(Box::new(quick_xml::Error::TextNotFound)),
5✔
608
        }
609
    }
5✔
610

611
    // fn custom<E: StdError + 'static>(err: E) -> Self {
612
    //     Self {
613
    //         kind: ListErrorKind::Custom(Box::new(err)),
614
    //     }
615
    // }
616

617
    fn init_error(is_object: bool) -> Self {
18✔
618
        Self {
18✔
619
            kind: ListErrorKind::InitItemFailed(is_object),
18✔
620
        }
621
    }
18✔
622

623
    #[cfg(test)]
624
    #[allow(dead_code)]
625
    pub(crate) fn from_custom() -> Self {
1✔
626
        #[derive(Debug)]
×
627
        struct MyError;
628
        impl Display for MyError {
629
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1✔
630
                "custom".fmt(f)
1✔
631
            }
1✔
632
        }
633
        impl StdError for MyError {}
634
        Self {
1✔
635
            kind: ListErrorKind::Custom(Box::new(MyError {})),
1✔
636
        }
637
    }
1✔
638

639
    /// 获取更详细的错误信息
640
    pub fn get_source(&self) -> Option<&(dyn StdError + 'static)> {
8✔
641
        use ListErrorKind::*;
642
        match &self.kind {
8✔
643
            Item(item) => item.get_source(),
2✔
644
            Xml(xml) => Some(xml),
3✔
645
            Custom(out) => Some(out.as_ref()),
3✔
646
            InitItemFailed(_) => None,
×
647
        }
648
    }
8✔
649
}
650

651
impl From<InnerItemError> for InnerListError {
652
    fn from(value: InnerItemError) -> Self {
4✔
653
        Self {
4✔
654
            kind: ListErrorKind::Item(value),
4✔
655
        }
656
    }
4✔
657
}
658

659
impl From<quick_xml::Error> for InnerListError {
660
    fn from(value: quick_xml::Error) -> Self {
1✔
661
        Self {
1✔
662
            kind: ListErrorKind::Xml(Box::new(value)),
1✔
663
        }
664
    }
1✔
665
}
666

667
#[doc(hidden)]
668
#[derive(Debug)]
3✔
669
#[non_exhaustive]
670
enum ListErrorKind {
671
    #[non_exhaustive]
672
    Item(InnerItemError),
1✔
673

674
    #[non_exhaustive]
675
    Xml(Box<quick_xml::Error>),
2✔
676

677
    #[non_exhaustive]
678
    Custom(Box<dyn StdError + 'static>),
×
679

680
    InitItemFailed(bool),
×
681
}
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