xml_string/names/
error.rs

1//! Name error.
2
3use core::fmt;
4
5/// Name error.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct NameError {
8    /// Target type.
9    target: TargetNameType,
10    /// The position of the first byte an error part starts.
11    valid_up_to: usize,
12}
13
14impl NameError {
15    /// Creates a new `NameError`.
16    #[inline]
17    #[must_use]
18    pub(super) fn new(target: TargetNameType, valid_up_to: usize) -> Self {
19        Self {
20            target,
21            valid_up_to,
22        }
23    }
24
25    /// Returns the index in the given string up to which valid name was verified.
26    ///
27    /// Note that `&source_str[..err.valid_up_to()]` might be invalid when `valid_up_to` is zero.
28    /// In other words, it depends on target type whether the empty string is valid or not.
29    /// This error type does not assume anything about it.
30    ///
31    /// # Examples
32    ///
33    /// ```
34    /// # use xml_string::names::NameError;
35    /// use xml_string::names::Ncname;
36    ///
37    /// let err_nonempty = Ncname::from_str("foo:bar").expect_err("NCName cannot have a colon");
38    /// assert_eq!(err_nonempty.valid_up_to(), 3);
39    /// assert!(Ncname::from_str("foo").is_ok());
40    ///
41    /// let err_empty = Ncname::from_str("").expect_err("NCName cannot be empty");
42    /// assert_eq!(err_empty.valid_up_to(), 0);
43    /// assert!(
44    ///     Ncname::from_str("").is_err(),
45    ///     "Note that `&s[..err.valid_up_to()]` is not always valid for the empty source string"
46    /// );
47    /// ```
48    #[inline]
49    #[must_use]
50    pub fn valid_up_to(&self) -> usize {
51        self.valid_up_to
52    }
53}
54
55impl fmt::Display for NameError {
56    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57        write!(
58            f,
59            "Failed to parse the string as {}: invalid from {} bytes",
60            self.target.name(),
61            self.valid_up_to
62        )
63    }
64}
65
66#[cfg(feature = "std")]
67impl std::error::Error for NameError {}
68
69/// Target name type of a conversion.
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
71#[non_exhaustive]
72pub(super) enum TargetNameType {
73    /// [`Eqname`].
74    ///
75    /// [`EQName`]: https://www.w3.org/TR/2017/REC-xpath-31-20170321/#prod-xpath31-EQName
76    Eqname,
77    /// [`Name`].
78    ///
79    /// [`Name`]: https://www.w3.org/TR/REC-xml/#NT-Name
80    Name,
81    /// [`NCName`].
82    ///
83    /// [`NCName`]: https://www.w3.org/TR/2009/REC-xml-names-20091208/#NT-NCName
84    Ncname,
85    /// [`Nmtoken`].
86    ///
87    /// [`Nmtoken`]: https://www.w3.org/TR/REC-xml/#NT-Nmtoken
88    Nmtoken,
89    /// [`QName`].
90    ///
91    /// [`QName`]: https://www.w3.org/TR/2009/REC-xml-names-20091208/#NT-QName
92    Qname,
93    /// [`URIQualifiedName`].
94    ///
95    /// [`URIQualifiedName`]:
96    ///     https://www.w3.org/TR/2017/REC-xpath-31-20170321/#prod-xpath31-URIQualifiedName
97    UriQualifiedName,
98}
99
100impl TargetNameType {
101    /// Returns the target name type name.
102    fn name(self) -> &'static str {
103        match self {
104            Self::Eqname => "EQName",
105            Self::Name => "Name",
106            Self::Ncname => "NCName",
107            Self::Nmtoken => "Nmtoken",
108            Self::Qname => "QName",
109            Self::UriQualifiedName => "URIQualifiedName",
110        }
111    }
112}