[go: up one dir, main page]

xml/
common.rs

1//! Contains common types and functions used throughout the library.
2
3use std::fmt;
4
5/// Represents a position inside some textual document.
6#[derive(Copy, Clone, PartialEq, Eq)]
7pub struct TextPosition {
8    #[doc(hidden)]
9    pub row: u64,
10
11    #[doc(hidden)]
12    pub column: u64,
13}
14
15impl TextPosition {
16    /// Creates a new position initialized to the beginning of the document
17    #[inline]
18    #[must_use]
19    pub const fn new() -> Self {
20        Self { row: 0, column: 0 }
21    }
22
23    /// Advances the position in a line
24    #[inline]
25    pub fn advance(&mut self, count: u8) {
26        self.column += u64::from(count);
27    }
28
29    #[doc(hidden)]
30    #[deprecated]
31    pub fn advance_to_tab(&mut self, width: u8) {
32        let width = u64::from(width);
33        self.column += width - self.column % width;
34    }
35
36    /// Advances the position to the beginning of the next line
37    #[inline]
38    pub fn new_line(&mut self) {
39        self.column = 0;
40        self.row += 1;
41    }
42
43    /// Row, counting from 0. Add 1 to display as users expect!
44    #[must_use]
45    pub fn row(&self) -> u64 {
46        self.row
47    }
48
49    /// Column, counting from 0. Add 1 to display as users expect!
50    #[must_use]
51    pub fn column(&self) -> u64 {
52        self.column
53    }
54}
55
56impl fmt::Debug for TextPosition {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        fmt::Display::fmt(self, f)
59    }
60}
61
62impl fmt::Display for TextPosition {
63    #[inline]
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        write!(f, "{}:{}", self.row + 1, self.column + 1)
66    }
67}
68
69/// Get the position in the document corresponding to the object
70///
71/// This trait is implemented by parsers, lexers and errors.
72pub trait Position {
73    /// Returns the current position or a position corresponding to the object.
74    fn position(&self) -> TextPosition;
75}
76
77impl Position for TextPosition {
78    #[inline]
79    fn position(&self) -> TextPosition {
80        *self
81    }
82}
83
84/// XML version enumeration.
85#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
86pub enum XmlVersion {
87    /// XML version 1.0.
88    Version10,
89
90    /// XML version 1.1.
91    Version11,
92}
93
94impl fmt::Display for XmlVersion {
95    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96        match *self {
97            Self::Version10 => "1.0",
98            Self::Version11 => "1.1",
99        }.fmt(f)
100    }
101}
102
103impl fmt::Debug for XmlVersion {
104    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105        fmt::Display::fmt(self, f)
106    }
107}
108
109/// Checks whether the given character is a white space character (`S`)
110/// as is defined by XML 1.1 specification, [section 2.3][1].
111///
112/// [1]: http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn
113#[must_use]
114#[inline]
115pub const fn is_whitespace_char(c: char) -> bool {
116    matches!(c, '\x20' | '\x0a' | '\x09' | '\x0d')
117}
118
119/// Checks whether the given string is compound only by white space
120/// characters (`S`) using the previous `is_whitespace_char` to check
121/// all characters of this string
122pub fn is_whitespace_str(s: &str) -> bool {
123    s.chars().all(is_whitespace_char)
124}
125
126/// Is it a valid character in XML 1.0
127#[must_use]
128pub const fn is_xml10_char(c: char) -> bool {
129    matches!(c, '\u{09}' | '\u{0A}' | '\u{0D}' | '\u{20}'..='\u{D7FF}' | '\u{E000}'..='\u{FFFD}' | '\u{10000}'..)
130}
131
132/// Is it a valid character in XML 1.1
133#[must_use]
134pub const fn is_xml11_char(c: char) -> bool {
135    matches!(c, '\u{01}'..='\u{D7FF}' | '\u{E000}'..='\u{FFFD}' | '\u{10000}'..)
136}
137
138/// Is it a valid character in XML 1.1 but not part of the restricted character set
139#[must_use]
140pub const fn is_xml11_char_not_restricted(c: char) -> bool {
141    is_xml11_char(c) &&
142        !matches!(c, '\u{01}'..='\u{08}' | '\u{0B}'..='\u{0C}' | '\u{0E}'..='\u{1F}' | '\u{7F}'..='\u{84}' | '\u{86}'..='\u{9F}')
143}
144
145/// Checks whether the given character is a name start character (`NameStartChar`)
146/// as is defined by XML 1.1 specification, [section 2.3][1].
147///
148/// [1]: http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn
149#[must_use]
150pub const fn is_name_start_char(c: char) -> bool {
151    matches!(c,
152        ':' | 'A'..='Z' | '_' | 'a'..='z' |
153        '\u{C0}'..='\u{D6}' | '\u{D8}'..='\u{F6}' | '\u{F8}'..='\u{2FF}' |
154        '\u{370}'..='\u{37D}' | '\u{37F}'..='\u{1FFF}' |
155        '\u{200C}'..='\u{200D}' | '\u{2070}'..='\u{218F}' |
156        '\u{2C00}'..='\u{2FEF}' | '\u{3001}'..='\u{D7FF}' |
157        '\u{F900}'..='\u{FDCF}' | '\u{FDF0}'..='\u{FFFD}' |
158        '\u{10000}'..='\u{EFFFF}'
159    )
160}
161
162/// Checks whether the given character is a name character (`NameChar`)
163/// as is defined by XML 1.1 specification, [section 2.3][1].
164///
165/// [1]: http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn
166#[must_use]
167pub const fn is_name_char(c: char) -> bool {
168    if is_name_start_char(c) {
169        return true;
170    }
171    matches!(c,
172        '-' | '.' | '0'..='9' | '\u{B7}' |
173        '\u{300}'..='\u{36F}' | '\u{203F}'..='\u{2040}'
174    )
175}