assembly_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 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>(reader: &mut XmlReader<B>, buf: &mut Vec<u8>) -> Result<String> {
81    if let Ok(XmlEvent::Text(e)) = reader.read_event(buf) {
82        let text = e.unescape_and_decode(reader)?;
83        Ok(text)
84    } else {
85        Err(Error::MissingText)
86    }
87}
88
89/// Expect an attribute on an opening tag and return a parsed value
90pub fn expect_attribute<T: FromStr, B: BufRead>(
91    key: &str,
92    reader: &XmlReader<B>,
93    event: &XmlBytesStart,
94) -> Result<T>
95where
96    <T as FromStr>::Err: std::error::Error + Send + Sync + Sized + 'static,
97{
98    let attr = event
99        .attributes()
100        .next()
101        .ok_or_else(|| Error::MissingAttribute(key.to_owned()))??;
102
103    if attr.key == key.as_bytes() {
104        let attr_unesc = attr.unescaped_value()?;
105        let attr_str = reader.decode(&attr_unesc);
106        let value = attr_str.parse().map_err(|e| {
107            let b: Box<dyn StdError + Sync + Send> = Box::new(e);
108            b
109        })?;
110        Ok(value)
111    } else {
112        Err(Error::ExpectedAttribute(
113            key.to_owned(),
114            reader.decode(attr.key).into_owned(),
115        ))
116    }
117}