aboutsummaryrefslogtreecommitdiff
path: root/src/tagged.rs
blob: 1fca4586bd7e397f6c7c905bd0e775d737b7821c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
//! Tagged element.

use std::borrow::Cow;
use std::str::Utf8Error;

use quick_xml::events::BytesStart;

use crate::attribute::{Attribute, Error as AttributeError, Iter as AttributeIter};

/// The start tag of a tagged element.
///
/// The `<xyz foo="bar">` in `<xyz foo="bar">Hello</xyz>`
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TagStart<'a>
{
    inner: BytesStart<'a>,
}

impl<'a> TagStart<'a>
{
    /// Returns a new `TagStart`.
    pub fn new(name: impl Into<Cow<'a, str>>) -> Self
    {
        Self {
            inner: BytesStart::new(name),
        }
    }

    /// Returns `Self` with the specified attributes.
    #[must_use]
    pub fn with_attributes<Attrs>(mut self, attrs: Attrs) -> Self
    where
        Attrs: IntoIterator<Item = Attribute<'a>>,
    {
        self.inner = self
            .inner
            .with_attributes(attrs.into_iter().map(Attribute::into_inner));

        self
    }

    /// Returns the name.
    ///
    /// # Errors
    /// Returns `Err` if the name is not valid UTF-8.
    pub fn name(&self) -> Result<&str, Utf8Error>
    {
        std::str::from_utf8(self.name_bytes())
    }

    /// Returns the name as bytes.
    #[must_use]
    pub fn name_bytes(&self) -> &[u8]
    {
        let name_length = self.inner.name().as_ref().len();

        &self.inner.as_ref()[..name_length]
    }

    /// Returns the tag attributes.
    #[must_use]
    pub fn attributes(&'a self) -> AttributeIter<'a>
    {
        AttributeIter::new(self.inner.attributes())
    }

    /// Returns a attribute.
    ///
    /// # Errors
    /// Returns `Err` if a invalid attribute is found.
    pub fn get_attribute(
        &self,
        attr_name: &str,
    ) -> Result<Option<Attribute>, TagStartError>
    {
        for attr_result in self.inner.attributes().with_checks(false) {
            let attr = attr_result.map_err(AttributeError::from)?;

            if attr.key.as_ref() == attr_name.as_bytes() {
                return Ok(Some(Attribute::from_inner(attr)));
            }
        }

        Ok(None)
    }
}

// Crate-local functions
impl<'a> TagStart<'a>
{
    pub(crate) fn from_inner(inner: BytesStart<'a>) -> Self
    {
        Self { inner }
    }
}

/// `TagStart` error.
#[derive(Debug, thiserror::Error)]
pub enum TagStartError
{
    /// Invalid attribute.
    #[error("Invalid attribute")]
    InvalidAttribute(#[from] AttributeError),
}