1use quick_xml::{events::Event, Reader};
4use thiserror::Error;
5
6#[derive(Debug, Error)]
8pub enum XmlError {
9 #[error("XML error: {0}")]
11 Parse(#[from] quick_xml::Error),
12 #[error("attribute error: {0}")]
14 Attr(#[from] quick_xml::events::attributes::AttrError),
15 #[error("non-UTF-8 folder name")]
17 Utf8(#[from] std::string::FromUtf8Error),
18}
19
20#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct FolderEntry {
23 name: String,
24}
25
26impl FolderEntry {
27 pub(crate) const fn new(name: String) -> Self {
28 Self { name }
29 }
30
31 #[must_use]
33 pub fn name(&self) -> &str {
34 &self.name
35 }
36}
37
38#[derive(Debug, Clone, PartialEq, Eq)]
40pub struct FolderListing {
41 folders: Vec<FolderEntry>,
42}
43
44impl FolderListing {
45 #[must_use]
47 pub fn folders(&self) -> &[FolderEntry] {
48 &self.folders
49 }
50
51 pub fn parse(xml: &[u8]) -> Result<Self, XmlError> {
57 let mut reader = Reader::from_reader(xml);
58 reader.config_mut().trim_text(true);
59 let mut folders = Vec::new();
60 let mut buf = Vec::new();
61 loop {
62 match reader.read_event_into(&mut buf)? {
63 Event::Empty(e) | Event::Start(e) if e.name().as_ref() == b"folder" => {
64 for attr in e.attributes() {
65 let a = attr?;
66 if a.key.as_ref() == b"name" {
67 folders.push(FolderEntry::new(
68 String::from_utf8(a.value.into_owned()).map_err(XmlError::Utf8)?,
69 ));
70 }
71 }
72 }
73 Event::Eof => break,
74 _ => {}
75 }
76 buf.clear();
77 }
78 Ok(Self { folders })
79 }
80}