1use xml::reader::{EventReader, XmlEvent};
6
7use std::io::Read;
8use std::str::{FromStr, ParseBoolError};
9use std::{error, fmt};
10
11#[derive(Debug, PartialEq)]
12pub enum ArgKind {
13 Int,
14 Uint,
15 Fixed,
16 Object,
17 NewId,
18 String,
19 Array,
20 Fd,
21}
22
23impl ArgKind {
24 fn from_str(s: &str) -> Option<ArgKind> {
25 match s {
26 "int" => Some(ArgKind::Int),
27 "uint" => Some(ArgKind::Uint),
28 "fixed" => Some(ArgKind::Fixed),
29 "string" => Some(ArgKind::String),
30 "object" => Some(ArgKind::Object),
31 "new_id" => Some(ArgKind::NewId),
32 "array" => Some(ArgKind::Array),
33 "fd" => Some(ArgKind::Fd),
34 _ => None,
35 }
36 }
37}
38
39#[derive(Debug)]
40pub enum ParseElement {
41 Protocol {
42 name: String,
43 },
44 Copyright,
45 Interface {
46 name: String,
47 version: u32,
48 },
49 Description {
50 summary: String,
51 },
52 Request {
53 name: String,
54 since: u32,
55 request_type: Option<String>,
56 },
57 Event {
58 name: String,
59 since: u32,
60 },
61 Arg {
62 name: String,
63 kind: ArgKind,
64 summary: Option<String>,
65 interface: Option<String>,
66 nullable: bool,
67 enum_type: Option<String>,
68 },
69 Enum {
70 name: String,
71 since: u32,
72 bitfield: bool,
73 },
74 EnumEntry {
75 name: String,
76 value: i64,
77 summary: Option<String>,
78 since: u32,
79 },
80}
81
82#[derive(Debug)]
83pub struct ParseNode {
84 pub element: ParseElement,
85 pub body: Option<String>,
86 pub children: Vec<ParseNode>,
87}
88
89pub struct Parser<R: Read> {
90 xml: xml::reader::EventReader<R>,
91}
92
93#[derive(Debug, Clone)]
94pub struct ParseError {
95 msg: String,
96}
97
98impl ParseError {
99 fn new(msg: String) -> Self {
100 ParseError { msg }
101 }
102}
103
104impl fmt::Display for ParseError {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 write!(f, "{}", self.msg)
107 }
108}
109
110impl error::Error for ParseError {
111 fn description(&self) -> &str {
112 &self.msg
113 }
114
115 fn cause(&self) -> Option<&dyn error::Error> {
116 None
117 }
118}
119
120impl From<ParseBoolError> for ParseError {
121 fn from(e: ParseBoolError) -> Self {
122 ParseError::new(format!("Failed to parse boolean {}", e))
123 }
124}
125
126pub type ParseResult<T> = Result<T, ParseError>;
127
128fn parse_int<T: FromStr + num::Num>(s: &str) -> ParseResult<T> {
131 if s.starts_with("0x") {
132 T::from_str_radix(&s[2..], 16)
133 .map_err(|_| ParseError::new(format!("Failed to parse int {}", s)))
134 } else {
135 s.parse::<T>().map_err(|_| ParseError::new(format!("Failed to parse int {}", s)))
136 }
137}
138
139trait XmlAttr
140where
141 Self: Sized,
142{
143 fn default() -> Self;
144
145 fn from_xml_attr(attr: xml::attribute::OwnedAttribute) -> ParseResult<Self>;
146}
147
148impl<T> XmlAttr for Option<T>
149where
150 T: XmlAttr,
151{
152 fn default() -> Self {
153 None
154 }
155
156 fn from_xml_attr(attr: xml::attribute::OwnedAttribute) -> ParseResult<Self> {
157 T::from_xml_attr(attr).map(|t| Some(t))
158 }
159}
160
161macro_rules! impl_xml_attr {
162 ($type:ty, $default:expr, $attr:ident => $from_attr:expr) => {
163 impl XmlAttr for $type {
164 fn default() -> Self {
165 $default
166 }
167
168 fn from_xml_attr($attr: xml::attribute::OwnedAttribute) -> ParseResult<Self> {
169 $from_attr
170 }
171 }
172 };
173}
174
175impl_xml_attr!(u32, 0, attr => parse_int::<Self>(&attr.value));
176impl_xml_attr!(i64, 0, attr => parse_int::<Self>(&attr.value));
177impl_xml_attr!(bool, false, attr => Ok(attr.value.parse::<bool>()?));
178impl_xml_attr!(String, "".to_owned(), attr => Ok(attr.value));
179impl_xml_attr!(Option<ArgKind>, None, attr => Ok(ArgKind::from_str(&attr.value)));
180
181macro_rules! map_xml_attrs {
195 ($attributes:expr, ($($xml_name:expr => $field_name:ident : $field_type:ty),*) => { $body:expr }) => {
196 {
197 $(
198 let mut $field_name : $field_type = XmlAttr::default();
199 )*
200 for attr in $attributes {
201 match attr.name.local_name.as_ref() {
202 $(
203 $xml_name => $field_name = XmlAttr::from_xml_attr(attr)?,
204 )*
205 _ => {
206 return Err(ParseError::new(format!(
207 "Unsupported attribute {}",
208 attr.name.local_name
209 )));
210 }
211 }
212 }
213 $body
214 }
215 }
216}
217
218impl<R: Read> Parser<R> {
219 pub fn read_document(&mut self) -> ParseResult<ParseNode> {
222 if let Ok(XmlEvent::StartDocument { .. }) = self.xml.next() {
223 self.read_node()
224 } else {
225 Err(ParseError::new("Missing StartDocument".to_owned()))
226 }
227 }
228
229 fn read_node(&mut self) -> ParseResult<ParseNode> {
230 match self.xml.next() {
231 Ok(XmlEvent::StartElement { name, attributes, .. }) => {
232 let element = self.element_from_xml(name.local_name.as_ref(), attributes)?;
233 self.populate_node(element, name.local_name.as_ref())
234 }
235 node => Err(ParseError::new(format!("Not Implemented {:?}", node))),
236 }
237 }
238
239 fn populate_node(&mut self, element: ParseElement, xml_name: &str) -> ParseResult<ParseNode> {
240 let mut children: Vec<ParseNode> = Vec::new();
241 let mut body: Option<String> = None;
242 loop {
243 match self.xml.next() {
244 Ok(XmlEvent::EndElement { name }) => {
245 if name.local_name == xml_name {
246 return Ok(ParseNode { element, children, body });
247 }
248 return Err(ParseError::new("Unexpected EndElement".to_owned()));
249 }
250 Ok(XmlEvent::StartElement { name, attributes, .. }) => {
251 let element = self.element_from_xml(name.local_name.as_ref(), attributes)?;
252 let node = self.populate_node(element, name.local_name.as_ref())?;
253 children.push(node);
254 }
255 Ok(XmlEvent::CData(text)) | Ok(XmlEvent::Characters(text)) => {
256 body = Some(text);
257 }
258 Ok(XmlEvent::Whitespace(_)) | Ok(XmlEvent::Comment(_)) => continue,
259 event => {
260 return Err(ParseError::new(format!("Unhandled event {:?}", event)));
261 }
262 }
263 }
264 }
265
266 fn element_from_xml(
267 &self,
268 element_name: &str,
269 attributes: Vec<xml::attribute::OwnedAttribute>,
270 ) -> ParseResult<ParseElement> {
271 match element_name {
272 "protocol" => map_xml_attrs!(attributes,
273 ("name" => name: Option<String>) => {
274 Ok(ParseElement::Protocol {
275 name: name
276 .ok_or_else(|| ParseError::new("Missing 'name' attribute".to_owned()))?,
277 })
278 }),
279 "copyright" => Ok(ParseElement::Copyright),
280 "interface" => map_xml_attrs!(attributes,
281 ("name" => name: Option<String>,
282 "version" => version: u32) => {
283 Ok(ParseElement::Interface {
284 name: name
285 .ok_or_else(|| ParseError::new("Missing 'name' attribute".to_owned()))?,
286 version,
287 })
288
289 }),
290 "request" => map_xml_attrs!(attributes,
291 ("name" => name: Option<String>,
292 "type" => request_type: Option<String>,
293 "since" => since: u32) => {
294
295 Ok(ParseElement::Request {
296 name: name
297 .ok_or_else(|| ParseError::new("Missing 'name' attribute".to_owned()))?,
298 request_type,
299 since,
300 })
301 }),
302 "event" => map_xml_attrs!(attributes,
303 ("name" => name: Option<String>,
304 "since" => since: u32) => {
305 Ok(ParseElement::Event {
306 name: name
307 .ok_or_else(|| ParseError::new("Missing 'name' attribute".to_owned()))?,
308 since,
309 })
310 }),
311 "enum" => map_xml_attrs!(attributes,
312 ("name" => name: Option<String>,
313 "since" => since: u32,
314 "bitfield" => bitfield: bool) => {
315 Ok(ParseElement::Enum {
316 name: name
317 .ok_or_else(|| ParseError::new("Missing 'name' attribute".to_owned()))?,
318 since,
319 bitfield,
320 })
321 }),
322 "entry" => map_xml_attrs!(attributes,
323 ("name" => name: Option<String>,
324 "value" => value: Option<i64>,
325 "since" => since: u32,
326 "summary" => summary: Option<String>) => {
327 Ok(ParseElement::EnumEntry {
328 name: name
329 .ok_or_else(|| ParseError::new("Missing 'name' attribute".to_owned()))?,
330 value: value
331 .ok_or_else(|| ParseError::new("Missing 'value' attribute".to_owned()))?,
332 since,
333 summary,
334 })
335 }),
336 "arg" => map_xml_attrs!(attributes,
337 ("name" => name: Option<String>,
338 "type" => kind: Option<ArgKind>,
339 "summary" => summary: Option<String>,
340 "interface" => interface: Option<String>,
341 "allow-null" => nullable: bool,
342 "enum" => enum_type: Option<String>) => {
343
344 Ok(ParseElement::Arg {
345 name: name.ok_or_else(|| {
346 ParseError::new("Missing 'name' attributue on argument".to_owned())
347 })?,
348 kind: kind.ok_or_else(|| {
349 ParseError::new("Missing 'type' attributue on argument".to_owned())
350 })?,
351 summary,
352 interface,
353 nullable,
354 enum_type,
355 })
356 }),
357 "description" => map_xml_attrs!(attributes,
358 ("summary" => summary: Option<String>) => {
359 Ok(ParseElement::Description {
360 summary: summary.ok_or_else(|| {
361 ParseError::new("Missing 'summary' attributue on argument".to_owned())
362 })?,
363 })
364 }),
365 tag => Err(ParseError::new(format!("Tag not implemented {}", tag))),
366 }
367 }
368}
369
370impl<R: Read> Parser<R> {
371 pub fn new(source: R) -> Parser<R> {
372 Parser { xml: EventReader::new(source) }
373 }
374}
375
376impl<'a> Parser<&'a [u8]> {
377 pub fn from_str(protocol: &str) -> Parser<&[u8]> {
378 Parser { xml: EventReader::from_str(protocol) }
379 }
380}