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

tu6ge / oss-rs / 5874371460

pending completion
5874371460

Pull #24

github

tu6ge
chore: add clippy deprecated_semver rule
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

88.61
/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
//!     let init_file = || MyFile {
75
//!         key: String::default(),
76
//!         other: "abc".to_string(),
77
//!     };
78
//!
79
//!     bucket.decode(xml, init_file)?;
80
//!
81
//!     assert!(bucket.name == "foo_bucket");
82
//!     assert!(bucket.files[0].key == "9AB932LY.jpeg");
83
//!
84
//!     Ok(())
85
//! }
86
//!
87
//! let res = get_with_xml();
88
//!
89
//! if let Err(err) = res {
90
//!     eprintln!("{}", err);
91
//! }
92
//! ```
93

94
use std::borrow::Cow;
95
use std::error::Error as StdError;
96
use std::fmt::Display;
97
use std::num::ParseIntError;
98

99
use quick_xml::{events::Event, Reader};
100

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

108
#[cfg(test)]
109
mod test;
110

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

126
const CREATION_DATE: &[u8] = b"CreationDate";
127
const EXTRANET_ENDPOINT: &[u8] = b"ExtranetEndpoint";
128
const INTRANET_ENDPOINT: &[u8] = b"IntranetEndpoint";
129
const LOCATION: &[u8] = b"Location";
130

131
const MARKER: &[u8] = b"Marker";
132
const NEXT_MARKER: &[u8] = b"NextMarker";
133
const ID: &[u8] = b"ID";
134
const DISPLAY_NAME: &[u8] = b"DisplayName";
135
const CONTENTS: &[u8] = b"Contents";
136

137
const TRUE: &str = "true";
138

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

276
        Ok(())
1✔
277
    }
1✔
278

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

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

333
        Ok(())
8✔
334
    }
11✔
335
}
336

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

344
    /// 提取 bucket 创建时间
345
    fn set_creation_date(&mut self, _creation_date: &str) -> Result<(), Error> {
346
        Ok(())
347
    }
348

349
    /// 提取 location
350
    fn set_location(&mut self, _location: &str) -> Result<(), Error> {
351
        Ok(())
352
    }
353

354
    /// 提取 extranet_endpoint
355
    fn set_extranet_endpoint(&mut self, _extranet_endpoint: &str) -> Result<(), Error> {
2✔
356
        Ok(())
2✔
357
    }
2✔
358

359
    /// 提取 intranet_endpoint
360
    fn set_intranet_endpoint(&mut self, _intranet_endpoint: &str) -> Result<(), Error> {
2✔
361
        Ok(())
2✔
362
    }
2✔
363

364
    /// 提取 storage_class
365
    fn set_storage_class(&mut self, _storage_class: &str) -> Result<(), Error> {
366
        Ok(())
367
    }
368

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

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

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

420
    /// 提取 marker
421
    fn set_marker(&mut self, _marker: &str) -> Result<(), Error> {
422
        Ok(())
423
    }
424

425
    /// 提取 max_keys
426
    fn set_max_keys(&mut self, _max_keys: &str) -> Result<(), Error> {
427
        Ok(())
428
    }
429

430
    /// 提取 is_truncated
431
    fn set_is_truncated(&mut self, _is_truncated: bool) -> Result<(), Error> {
432
        Ok(())
433
    }
434

435
    /// 提取 next_marker
436
    fn set_next_marker(&mut self, _next_marker: &str) -> Result<(), Error> {
437
        Ok(())
438
    }
439

440
    /// 提取 id
441
    fn set_id(&mut self, _id: &str) -> Result<(), Error> {
442
        Ok(())
443
    }
444

445
    /// 提取 display_name
446
    fn set_display_name(&mut self, _display_name: &str) -> Result<(), Error> {
447
        Ok(())
448
    }
449

450
    /// 提取 bucket 列表
451
    fn set_list(&mut self, _list: Vec<T>) -> Result<(), Error> {
1✔
452
        Ok(())
1✔
453
    }
1✔
454

455
    /// 解析 OSS 接口返回的 xml 数据
456
    fn decode<F>(&mut self, xml: &str, mut init_bucket: F) -> Result<(), InnerListError>
3✔
457
    where
458
        F: FnMut() -> T,
459
    {
460
        let mut result = Vec::new();
3✔
461
        let mut reader = Reader::from_str(xml);
3✔
462
        reader.trim_text(true);
3✔
463
        let mut buf = Vec::with_capacity(xml.len());
3✔
464

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

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

510
impl<T: StdError + 'static> From<T> for InnerItemError {
511
    fn from(err: T) -> Self {
2✔
512
        Self(Box::new(err))
2✔
513
    }
2✔
514
}
515

516
impl Display for InnerItemError {
517
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
1✔
518
        write!(fmt, "{}", self.0)
1✔
519
    }
1✔
520
}
521

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

534
        Self(Box::new(MyError {}))
9✔
535
    }
9✔
536

537
    pub fn get_source(&self) -> Option<&(dyn StdError + 'static)> {
5✔
538
        Some(self.0.as_ref())
5✔
539
    }
5✔
540
}
541

542
/// 当外部要实现 [`RefineObjectList`] 时,Error 类需要实现此 Trait
543
///
544
/// [`RefineObjectList`]: crate::decode::RefineObjectList
545
pub trait ListError: StdError + 'static {}
546

547
impl ListError for ParseIntError {}
548

549
impl ListError for InvalidEndPoint {}
550

551
#[cfg(feature = "core")]
552
impl ListError for InvalidObjectPath {}
553
#[cfg(feature = "core")]
554
impl ListError for InvalidObjectDir {}
555
#[cfg(feature = "core")]
556
impl ListError for chrono::ParseError {}
557
#[cfg(feature = "core")]
558
impl ListError for OssError {}
559

560
impl<T: ListError> From<T> for InnerListError {
561
    fn from(err: T) -> InnerListError {
3✔
562
        Self {
3✔
563
            kind: ListErrorKind::Custom(Box::new(err)),
3✔
564
        }
565
    }
3✔
566
}
567

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

579
impl Display for InnerListError {
580
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
6✔
581
        use ListErrorKind::*;
582
        match &self.kind {
6✔
583
            Item(item) => write!(fmt, "{}", item.0),
1✔
584
            Xml(xml) => write!(fmt, "{xml}"),
3✔
585
            Custom(out) => write!(fmt, "{out}"),
2✔
586
        }
587
    }
6✔
588
}
589

590
impl InnerListError {
591
    #[cfg(test)]
592
    #[allow(dead_code)]
593
    pub(crate) fn from_xml() -> Self {
5✔
594
        Self {
5✔
595
            kind: ListErrorKind::Xml(Box::new(quick_xml::Error::TextNotFound)),
5✔
596
        }
597
    }
5✔
598

599
    #[cfg(test)]
600
    #[allow(dead_code)]
601
    pub(crate) fn from_custom() -> Self {
1✔
602
        #[derive(Debug)]
×
603
        struct MyError;
604
        impl Display for MyError {
605
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1✔
606
                "custom".fmt(f)
1✔
607
            }
1✔
608
        }
609
        impl StdError for MyError {}
610
        Self {
1✔
611
            kind: ListErrorKind::Custom(Box::new(MyError {})),
1✔
612
        }
613
    }
1✔
614

615
    /// 获取更详细的错误信息
616
    pub fn get_source(&self) -> Option<&(dyn StdError + 'static)> {
8✔
617
        use ListErrorKind::*;
618
        match &self.kind {
8✔
619
            Item(item) => item.get_source(),
2✔
620
            Xml(xml) => Some(xml),
3✔
621
            Custom(out) => Some(out.as_ref()),
3✔
622
        }
623
    }
8✔
624
}
625

626
impl From<InnerItemError> for InnerListError {
627
    fn from(value: InnerItemError) -> Self {
4✔
628
        Self {
4✔
629
            kind: ListErrorKind::Item(value),
4✔
630
        }
631
    }
4✔
632
}
633

634
impl From<quick_xml::Error> for InnerListError {
635
    fn from(value: quick_xml::Error) -> Self {
1✔
636
        Self {
1✔
637
            kind: ListErrorKind::Xml(Box::new(value)),
1✔
638
        }
639
    }
1✔
640
}
641

642
#[doc(hidden)]
643
#[derive(Debug)]
3✔
644
#[non_exhaustive]
645
enum ListErrorKind {
646
    #[non_exhaustive]
647
    Item(InnerItemError),
1✔
648

649
    #[non_exhaustive]
650
    Xml(Box<quick_xml::Error>),
2✔
651

652
    #[non_exhaustive]
653
    Custom(Box<dyn StdError + 'static>),
×
654
}
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