1 //! Contains common types and functions used throughout the library.
2 
3 use std::fmt;
4 
5 /// Represents a position inside some textual document.
6 #[derive(Copy, Clone, PartialEq, Eq)]
7 pub struct TextPosition {
8     /// Row, counting from 0
9     pub row: u64,
10     /// Column, counting from 0
11     pub column: u64,
12 }
13 
14 impl TextPosition {
15     /// Creates a new position initialized to the beginning of the document
16     #[inline]
new() -> TextPosition17     pub fn new() -> TextPosition {
18         TextPosition { row: 0, column: 0 }
19     }
20 
21     /// Advances the position in a line
22     #[inline]
advance(&mut self, count: u8)23     pub fn advance(&mut self, count: u8) {
24         self.column += count as u64;
25     }
26 
27     /// Advances the position in a line to the next tab position
28     #[inline]
advance_to_tab(&mut self, width: u8)29     pub fn advance_to_tab(&mut self, width: u8) {
30         let width = width as u64;
31         self.column += width - self.column % width
32     }
33 
34     /// Advances the position to the beginning of the next line
35     #[inline]
new_line(&mut self)36     pub fn new_line(&mut self) {
37         self.column = 0;
38         self.row += 1;
39     }
40 }
41 
42 impl fmt::Debug for TextPosition {
43     #[inline]
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result44     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45         write!(f, "{}:{}", self.row + 1, self.column + 1)
46     }
47 }
48 
49 impl fmt::Display for TextPosition {
50     #[inline]
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result51     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
52         write!(f, "{}:{}", self.row + 1, self.column + 1)
53     }
54 }
55 
56 /// Get the position in the document corresponding to the object
57 ///
58 /// This trait is implemented by parsers, lexers and errors.
59 pub trait Position {
60     /// Returns the current position or a position corresponding to the object.
position(&self) -> TextPosition61     fn position(&self) -> TextPosition;
62 }
63 
64 impl Position for TextPosition {
65     #[inline]
position(&self) -> TextPosition66     fn position(&self) -> TextPosition {
67         *self
68     }
69 }
70 
71 /// XML version enumeration.
72 #[derive(Copy, Clone, PartialEq, Eq)]
73 pub enum XmlVersion {
74     /// XML version 1.0.
75     Version10,
76 
77     /// XML version 1.1.
78     Version11
79 }
80 
81 impl fmt::Display for XmlVersion {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result82     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83         match *self {
84             XmlVersion::Version10 => write!(f, "1.0"),
85             XmlVersion::Version11 => write!(f, "1.1")
86         }
87     }
88 }
89 
90 impl fmt::Debug for XmlVersion {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result91     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92         fmt::Display::fmt(self, f)
93     }
94 }
95 
96 /// Checks whether the given character is a white space character (`S`)
97 /// as is defined by XML 1.1 specification, [section 2.3][1].
98 ///
99 /// [1]: http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn
is_whitespace_char(c: char) -> bool100 pub fn is_whitespace_char(c: char) -> bool {
101     match c {
102         '\x20' | '\x09' | '\x0d' | '\x0a' => true,
103         _ => false
104     }
105 }
106 
107 /// Checks whether the given string is compound only by white space
108 /// characters (`S`) using the previous is_whitespace_char to check
109 /// all characters of this string
is_whitespace_str(s: &str) -> bool110 pub fn is_whitespace_str(s: &str) -> bool {
111     s.chars().all(is_whitespace_char)
112 }
113 
114 /// Checks whether the given character is a name start character (`NameStartChar`)
115 /// as is defined by XML 1.1 specification, [section 2.3][1].
116 ///
117 /// [1]: http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn
is_name_start_char(c: char) -> bool118 pub fn is_name_start_char(c: char) -> bool {
119     match c {
120         ':' | 'A'...'Z' | '_' | 'a'...'z' |
121         '\u{C0}'...'\u{D6}' | '\u{D8}'...'\u{F6}' | '\u{F8}'...'\u{2FF}' |
122         '\u{370}'...'\u{37D}' | '\u{37F}'...'\u{1FFF}' |
123         '\u{200C}'...'\u{200D}' | '\u{2070}'...'\u{218F}' |
124         '\u{2C00}'...'\u{2FEF}' | '\u{3001}'...'\u{D7FF}' |
125         '\u{F900}'...'\u{FDCF}' | '\u{FDF0}'...'\u{FFFD}' |
126         '\u{10000}'...'\u{EFFFF}' => true,
127         _ => false
128     }
129 }
130 
131 /// Checks whether the given character is a name character (`NameChar`)
132 /// as is defined by XML 1.1 specification, [section 2.3][1].
133 ///
134 /// [1]: http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn
is_name_char(c: char) -> bool135 pub fn is_name_char(c: char) -> bool {
136     match c {
137         _ if is_name_start_char(c) => true,
138         '-' | '.' | '0'...'9' | '\u{B7}' |
139         '\u{300}'...'\u{36F}' | '\u{203F}'...'\u{2040}' => true,
140         _ => false
141     }
142 }
143