assembly_data/xml/common/
exact.rs

1//! # Functions to expect exactly one event
2use {
3    quick_xml::{
4        events::{BytesEnd as XmlBytesEnd, BytesStart as XmlBytesStart, Event as XmlEvent},
5        Error as XmlError, Reader as XmlReader,
6    },
7    std::{error::Error as StdError, io::BufRead, str::FromStr},
8};
9
10use assembly_core::displaydoc::Display;
11use thiserror::Error;
12
13/// The errors for this module
14#[derive(Debug, Display, Error)]
15pub enum Error {
16    /// Malformed XML
17    Xml(#[from] XmlError),
18    /// Generic
19    Generic(#[from] Box<dyn StdError + Send + Sync>),
20    /// Expected tag `{0}`, found `{1:?}`
21    ExpectedTag(String, String),
22    /// Expected tag `{0}`, found `{1:?}`
23    ExpectedEndTag(String, String),
24    /// Missing tag `{0}`
25    MissingTag(String),
26    /// Missing end tag `{0}`
27    MissingEndTag(String),
28    /// Missing text
29    MissingText,
30    /// Missing Attribute `{0}`
31    MissingAttribute(String),
32    /// Expected Attribute `{0}`, found `{1:?}`
33    ExpectedAttribute(String, String),
34}
35
36/// The result type for this module
37pub type Result<T> = std::result::Result<T, Error>;
38
39/// Expect an opening tag and return it
40pub fn expect_start<'a, 'b, 'c, B: BufRead>(
41    key: &'a str,
42    reader: &'b mut XmlReader<B>,
43    buf: &'c mut Vec<u8>,
44) -> Result<XmlBytesStart<'c>> {
45    if let Ok(XmlEvent::Start(e)) = reader.read_event(buf) {
46        if e.name() == key.as_bytes() {
47            Ok(e)
48        } else {
49            Err(Error::ExpectedTag(
50                key.to_owned(),
51                reader.decode(e.name()).into_owned(),
52            ))
53        }
54    } else {
55        Err(Error::MissingTag(key.to_owned()))
56    }
57}
58
59/// Expect a closing tag and return it
60pub fn expect_end<'a, 'b, 'c, B: BufRead>(
61    key: &'a str,
62    reader: &'b mut XmlReader<B>,
63    buf: &'c mut Vec<u8>,
64) -> Result<XmlBytesEnd<'c>> {
65    if let Ok(XmlEvent::End(e)) = reader.read_event(buf) {
66        if e.name() == key.as_bytes() {
67            Ok(e)
68        } else {
69            Err(Error::ExpectedEndTag(
70                key.to_owned(),
71                reader.decode(e.name()).into_owned(),
72            ))
73        }
74    } else {
75        Err(Error::MissingEndTag(key.to_owned()))
76    }
77}
78
79/// Expect some text and return it
80pub fn expect_text<B: BufRead>(
81    reader: &mut XmlReader<B>,
82    buf: &mut Vec<u8>,
83) -> Result<String> {
84    if let Ok(XmlEvent::Text(e)) = reader.read_event(buf) {
85        let text = e.unescape_and_decode(reader)?;
86        Ok(text)
87    } else {
88        Err(Error::MissingText)
89    }
90}
91
92/// Expect an attribute on an opening tag and return a parsed value
93pub fn expect_attribute<T: FromStr, B: BufRead>(
94    key: &str,
95    reader: &XmlReader<B>,
96    event: &XmlBytesStart,
97) -> Result<T>
98where
99    <T as FromStr>::Err: std::error::Error + Send + Sync + Sized + 'static,
100{
101    let attr = event
102        .attributes()
103        .next()
104        .ok_or_else(|| Error::MissingAttribute(key.to_owned()))??;
105
106    if attr.key == key.as_bytes() {
107        let attr_unesc = attr.unescaped_value()?;
108        let attr_str = reader.decode(&attr_unesc);
109        let value = attr_str.parse().map_err(|e| {
110            let b: Box<dyn StdError + Sync + Send> = Box::new(e);
111            b
112        })?;
113        Ok(value)
114    } else {
115        Err(Error::ExpectedAttribute(
116            key.to_owned(),
117            reader.decode(attr.key).into_owned(),
118        ))
119    }
120}