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}