Skip to main content

vk_parse/
parse.rs

1extern crate xml;
2
3use std;
4use std::io::Read;
5use std::str::FromStr;
6use xml::reader::XmlEvent;
7
8use types::*;
9
10type XmlEvents<R> = xml::reader::Events<R>;
11type XmlAttribute = xml::attribute::OwnedAttribute;
12
13//--------------------------------------------------------------------------------------------------
14struct ParseCtx<R: Read> {
15    events: XmlEvents<R>,
16    xpath: String,
17    errors: Vec<Error>,
18}
19
20impl<R: Read> ParseCtx<R> {
21    fn push_element(&mut self, name: &str) {
22        self.xpath.push('/');
23        self.xpath.push_str(name);
24    }
25
26    fn pop_element(&mut self) {
27        if let Some(separator_pos) = self.xpath.rfind('/') {
28            self.xpath.truncate(separator_pos);
29        } else {
30            self.errors.push(Error::Internal {
31                desc: "ParseCtx push_element/pop_element mismatch.",
32            });
33        }
34    }
35}
36
37fn xpath_attribute(xpath: &str, attribute_name: &str) -> String {
38    let mut xpath = String::from(xpath);
39    xpath.push_str("[@");
40    xpath.push_str(attribute_name);
41    xpath.push(']');
42    xpath
43}
44
45//--------------------------------------------------------------------------------------------------
46macro_rules! unwrap_attribute (
47    ($ctx:expr, $element:ident, $attribute:ident) => {
48        let $attribute = match $attribute {
49            Some(val) => val,
50            None => {
51                $ctx.errors.push(Error::MissingAttribute {
52                    xpath: $ctx.xpath.clone(),
53                    name: String::from(stringify!($attribute)),
54                });
55                return None;
56            }
57        };
58    };
59
60    ($ctx:expr, $element:ident, $var:ident, $attribute_str:literal) => {
61        let $var = match $var {
62            Some(val) => val,
63            None => {
64                $ctx.errors.push(Error::MissingAttribute {
65                    xpath: $ctx.xpath.clone(),
66                    name: String::from($attribute_str),
67                });
68                return None;
69            }
70        };
71    };
72
73);
74
75macro_rules! match_attributes {
76    ($ctx:expr, $a:ident in $attributes:expr, $($p:pat => $e:expr),+ $(,)?) => {
77        for $a in $attributes {
78            let n = $a.name.local_name.as_str();
79            match n {
80                $(
81                    $p => $e,
82                )+
83                _ => $ctx.errors.push(Error::UnexpectedAttribute {
84                    xpath: $ctx.xpath.clone(),
85                    name: String::from(n),
86                })
87            }
88        }
89    };
90}
91
92macro_rules! match_elements {
93    ($ctx:expr, $($p:pat => $e:expr),+ $(,)?) => {
94        while let Some(Ok(e)) = $ctx.events.next() {
95            match e {
96                XmlEvent::StartElement { name, .. } => {
97                    let name = name.local_name.as_str();
98                    $ctx.push_element(name);
99                    match name {
100                        $(
101                            $p => $e,
102                        )+
103                        _ => {
104                            $ctx.errors.push(Error::UnexpectedElement {
105                                xpath: $ctx.xpath.clone(),
106                                name: String::from(name),
107                            });
108                            consume_current_element($ctx);
109                        }
110                    }
111                }
112                XmlEvent::EndElement { .. } => {
113                    $ctx.pop_element();
114                    break;
115                }
116                _ => {}
117            }
118        }
119    };
120
121    ( $ctx:expr, $attributes:ident, $($p:pat => $e:expr),+ $(,)?) => {
122        while let Some(Ok(e)) = $ctx.events.next() {
123            match e {
124                XmlEvent::StartElement { name, $attributes, .. } => {
125                    let name = name.local_name.as_str();
126                    $ctx.push_element(name);
127                    match name {
128                        $(
129                            $p => $e,
130                        )+
131                        _ => {
132                            $ctx.errors.push(Error::UnexpectedElement {
133                                xpath: $ctx.xpath.clone(),
134                                name: String::from(name),
135                            });
136                            consume_current_element($ctx);
137                        }
138                    }
139                }
140                XmlEvent::EndElement { .. } => {
141                    $ctx.pop_element();
142                    break;
143                }
144                _ => {}
145            }
146        }
147    };
148}
149
150macro_rules! match_elements_combine_text {
151    ( $ctx:expr, $buffer:ident, $($p:pat => $e:expr),+ $(,)?) => {
152        while let Some(Ok(e)) = $ctx.events.next() {
153            match e {
154                XmlEvent::Characters(text) => $buffer.push_str(&text),
155                XmlEvent::Whitespace(text) => $buffer.push_str(&text),
156                XmlEvent::StartElement { name, .. } => {
157                    let name = name.local_name.as_str();
158                    $ctx.push_element(name);
159                    match name {
160                        $(
161                            $p => $e,
162                        )+
163                        _ => {
164                            $ctx.errors.push(Error::UnexpectedElement {
165                                xpath: $ctx.xpath.clone(),
166                                name: String::from(name),
167                            });
168                            consume_current_element($ctx);
169                        }
170                    }
171                }
172                XmlEvent::EndElement { .. } => {
173                    $ctx.pop_element();
174                    break;
175                },
176                _ => {}
177            }
178        }
179    };
180
181    ( $ctx:expr, $attributes:ident, $buffer:ident, $($p:pat => $e:expr),+ $(,)?) => {
182        while let Some(Ok(e)) = $ctx.events.next() {
183            match e {
184                XmlEvent::Characters(text) => $buffer.push_str(&text),
185                XmlEvent::Whitespace(text) => $buffer.push_str(&text),
186                XmlEvent::StartElement { name, $attributes, .. } => {
187                    let name = name.local_name.as_str();
188                    $ctx.push_element(name);
189                    match name {
190                        $(
191                            $p => $e,
192                        )+
193                        _ => {
194                            $ctx.errors.push(Error::UnexpectedElement {
195                                xpath: $ctx.xpath.clone(),
196                                name: String::from(name),
197                            });
198                            consume_current_element($ctx);
199                        }
200                    }
201                }
202                XmlEvent::EndElement { .. } => {
203                    $ctx.pop_element();
204                    break;
205                }
206                _ => {}
207            }
208        }
209    };
210}
211
212//--------------------------------------------------------------------------------------------------
213/// Parses the Vulkan XML file into a Rust object.
214pub fn parse_file(path: &std::path::Path) -> Result<(Registry, Vec<Error>), FatalError> {
215    let file = std::io::BufReader::new(std::fs::File::open(path)?);
216    let parser = xml::reader::ParserConfig::new().create_reader(file);
217    parse_xml(parser.into_iter())
218}
219
220/// Parses the Vulkan XML file from stream into a Rust object.
221pub fn parse_stream<T: std::io::Read>(stream: T) -> Result<(Registry, Vec<Error>), FatalError> {
222    let parser = xml::reader::ParserConfig::new().create_reader(stream);
223    parse_xml(parser.into_iter())
224}
225
226fn parse_xml<R: Read>(events: XmlEvents<R>) -> Result<(Registry, Vec<Error>), FatalError> {
227    let mut ctx = ParseCtx {
228        events,
229        xpath: String::from(""),
230        errors: Vec::new(),
231    };
232
233    let mut result = Err(FatalError::MissingRegistryElement);
234
235    {
236        let ctx = &mut ctx;
237        match_elements! {ctx,
238            "registry" => result = parse_registry(ctx),
239        }
240    }
241
242    result.map(|r| (r, ctx.errors))
243}
244
245fn parse_registry<R: Read>(ctx: &mut ParseCtx<R>) -> Result<Registry, FatalError> {
246    let mut registry = Registry(Vec::new());
247
248    match_elements! {ctx, attributes,
249        "comment" => registry.0.push(RegistryChild::Comment(parse_text_element(ctx))),
250        "vendorids" => registry.0.push(parse_vendorids(ctx, attributes)),
251        "platforms" => {
252            let mut comment = None;
253            let mut children = Vec::new();
254
255            match_attributes!{ctx, a in attributes,
256                "comment" => comment = Some(a.value),
257            }
258
259            match_elements!{ctx, attributes,
260                "platform" => if let Some(v) = parse_platform(ctx, attributes) {
261                    children.push(v);
262                }
263            }
264
265            registry.0.push(RegistryChild::Platforms(Platforms { comment, children }));
266        },
267
268        "tags" => registry.0.push(parse_tags(ctx, attributes)),
269        "types" => {
270            let mut comment = None;
271            let mut children = Vec::new();
272            match_attributes!{ctx, a in attributes,
273                "comment" => comment = Some(a.value),
274            }
275            match_elements!{ctx, attributes,
276                "comment" => children.push(TypesChild::Comment(parse_text_element(ctx))),
277                "type" => children.push(parse_type(ctx, attributes))
278            }
279            registry.0.push(RegistryChild::Types(Types{
280                comment,
281                children
282            }));
283        },
284        "enums" => {
285            let mut name = None;
286            let mut kind = None;
287            let mut start = None;
288            let mut end = None;
289            let mut vendor = None;
290            let mut comment = None;
291            let mut bitwidth = None;
292            let mut children = Vec::new();
293            match_attributes!{ctx, a in attributes,
294                "name"     => name     = Some(a.value),
295                "type"     => kind     = Some(a.value),
296                "start"    => start    = Some(a.value),
297                "end"      => end      = Some(a.value),
298                "vendor"   => vendor   = Some(a.value),
299                "comment"  => comment  = Some(a.value),
300                "bitwidth" => bitwidth = Some(a.value),
301            }
302            match_elements!{ctx, attributes,
303                "enum" => if let Some(v) = parse_enum(ctx, attributes) {
304                    children.push(EnumsChild::Enum(v));
305                },
306                "unused" => if let Some(v) = parse_enums_child_unused(ctx, attributes) {
307                    children.push(v);
308                },
309                "comment" => children.push(EnumsChild::Comment(parse_text_element(ctx)))
310            }
311
312            let start = start.and_then(|val| parse_integer(ctx, &val));
313            let end = end.and_then(|val| parse_integer(ctx, &val));
314            let bitwidth = bitwidth.and_then(|val| parse_integer(ctx, &val)).map(|val| val as u32);
315
316            registry.0.push(RegistryChild::Enums(Enums{ name, kind, start, end, vendor, comment, children, bitwidth }));
317        },
318        "commands" => {
319            let mut comment = None;
320            let mut children = Vec::new();
321
322            match_attributes!{ctx, a in attributes,
323                "comment" => comment = Some(a.value),
324            }
325
326            match_elements!{ctx, attributes,
327                "command" => if let Some(v) = parse_command(ctx, attributes) {
328                    children.push(v);
329                }
330            }
331
332            registry.0.push(RegistryChild::Commands(Commands{comment, children}));
333        },
334        "feature" => if let Some(v) = parse_feature(ctx, attributes) {
335            registry.0.push(v);
336        },
337        "extensions" => registry.0.push(parse_extensions(ctx, attributes)),
338        "formats" => registry.0.push(parse_formats(ctx)),
339        "spirvextensions" => registry.0.push(parse_spirvextensions(ctx, attributes)),
340        "spirvcapabilities" => registry.0.push(parse_spirvcapabilities(ctx, attributes)),
341        "sync" => registry.0.push(parse_sync(ctx, attributes)),
342        "videocodecs" => registry.0.push(parse_videocodecs(ctx, attributes)),
343        "dynamicstates" => registry.0.push(parse_dynamicstates(ctx, attributes)),
344    }
345
346    Ok(registry)
347}
348
349fn parse_vendorids<R: Read>(ctx: &mut ParseCtx<R>, attributes: Vec<XmlAttribute>) -> RegistryChild {
350    let mut comment = None;
351    let mut children = Vec::new();
352
353    match_attributes! {ctx, a in attributes,
354        "comment" => comment = Some(a.value),
355    }
356
357    match_elements! {ctx, attributes,
358        "vendorid" => if let Some(v) = parse_vendorid(ctx, attributes) {
359            children.push(v);
360        },
361    }
362
363    RegistryChild::VendorIds(VendorIds { comment, children })
364}
365
366fn parse_vendorid<R: Read>(
367    ctx: &mut ParseCtx<R>,
368    attributes: Vec<XmlAttribute>,
369) -> Option<VendorId> {
370    let mut name = None;
371    let mut comment = None;
372    let mut id = None;
373
374    match_attributes! {ctx, a in attributes,
375        "name" => name = Some(a.value),
376        "comment" => comment = Some(a.value),
377        "id" => {
378            let mut v = None;
379            if a.value.starts_with("0x") {
380                v = u32::from_str_radix(&a.value.split_at(2).1, 16).ok();
381            }
382
383            if let Some(v) = v {
384                id = Some(v);
385            } else {
386                ctx.errors.push(Error::UnexpectedAttributeValue {
387                    xpath: ctx.xpath.clone(),
388                    name: String::from("id"),
389                    value: a.value.clone(),
390                });
391            }
392        },
393    }
394
395    consume_current_element(ctx);
396
397    unwrap_attribute!(ctx, vendorid, name);
398    unwrap_attribute!(ctx, vendorid, id);
399
400    Some(VendorId { name, comment, id })
401}
402
403fn parse_platform<R: Read>(
404    ctx: &mut ParseCtx<R>,
405    attributes: Vec<XmlAttribute>,
406) -> Option<Platform> {
407    let mut name = None;
408    let mut comment = None;
409    let mut protect = None;
410
411    match_attributes! {ctx, a in attributes,
412        "name"    => name    = Some(a.value),
413        "comment" => comment = Some(a.value),
414        "protect" => protect = Some(a.value),
415    }
416
417    consume_current_element(ctx);
418
419    unwrap_attribute!(ctx, platform, name);
420    unwrap_attribute!(ctx, platform, protect);
421
422    Some(Platform {
423        name,
424        comment,
425        protect,
426    })
427}
428
429fn parse_tags<R: Read>(ctx: &mut ParseCtx<R>, attributes: Vec<XmlAttribute>) -> RegistryChild {
430    let mut comment = None;
431    let mut children = Vec::new();
432
433    match_attributes! {ctx, a in attributes,
434        "comment" => comment = Some(a.value),
435    }
436
437    match_elements! {ctx, attributes,
438        "tag" => if let Some(v) = parse_tag(ctx, attributes) {
439            children.push(v);
440        },
441    }
442
443    RegistryChild::Tags(Tags { comment, children })
444}
445
446fn parse_tag<R: Read>(ctx: &mut ParseCtx<R>, attributes: Vec<XmlAttribute>) -> Option<Tag> {
447    let mut name = None;
448    let mut author = None;
449    let mut contact = None;
450
451    match_attributes! {ctx, a in attributes,
452        "name"    => name    = Some(a.value),
453        "author"  => author  = Some(a.value),
454        "contact" => contact = Some(a.value),
455    }
456
457    consume_current_element(ctx);
458
459    unwrap_attribute!(ctx, tag, name);
460    unwrap_attribute!(ctx, tag, author);
461    unwrap_attribute!(ctx, tag, contact);
462
463    Some(Tag {
464        name,
465        author,
466        contact,
467    })
468}
469
470fn parse_type<R: Read>(ctx: &mut ParseCtx<R>, attributes: Vec<XmlAttribute>) -> TypesChild {
471    let mut api = None;
472    let mut alias = None;
473    let mut requires = None;
474    let mut name = None;
475    let mut category = None;
476    let mut parent = None;
477    let mut returnedonly = None;
478    let mut structextends = None;
479    let mut allowduplicate = None;
480    let mut objtypeenum = None;
481    let mut requiredlimittype = None;
482    let mut bitvalues = None;
483    let mut comment = None;
484    let mut deprecated = None;
485
486    let mut code = String::new();
487    let mut markup = Vec::new();
488    let mut members = Vec::new();
489    let mut proto = None;
490    let mut params = Vec::new();
491
492    match_attributes! {ctx, a in attributes,
493        "api"            => api            = Some(a.value),
494        "alias"          => alias          = Some(a.value),
495        "requires"       => requires       = Some(a.value),
496        "name"           => name           = Some(a.value),
497        "category"       => category       = Some(a.value),
498        "parent"         => parent         = Some(a.value),
499        "returnedonly"   => returnedonly   = Some(a.value),
500        "structextends"  => structextends  = Some(a.value),
501        "allowduplicate" => allowduplicate = Some(a.value),
502        "objtypeenum"    => objtypeenum    = Some(a.value),
503        "requiredlimittype" => requiredlimittype = Some(a.value),
504        "bitvalues"      => bitvalues      = Some(a.value),
505        "comment"        => comment        = Some(a.value),
506        "deprecated"     => deprecated     = Some(a.value),
507    }
508
509    match_elements_combine_text! {ctx, attributes, code,
510        "member" => {
511            let mut len = None;
512            let mut altlen = None;
513            let mut externsync = None;
514            let mut optional = None;
515            let mut selector = None;
516            let mut selection = None;
517            let mut noautovalidity = None;
518            let mut validextensionstructs = None;
519            let mut values = None;
520            let mut limittype = None;
521            let mut objecttype = None;
522            let mut deprecated = None;
523            let mut api = None;
524            let mut code = String::new();
525            let mut markup = Vec::new();
526            let mut featurelink = None;
527            let mut flagsextend = None;
528            let mut flagsextendmember = None;
529            match_attributes!{ctx, a in attributes,
530                "len"                   => len                   = Some(a.value),
531                "altlen"                => altlen                = Some(a.value),
532                "externsync"            => externsync            = Some(a.value),
533                "optional"              => optional              = Some(a.value),
534                "selector"              => selector              = Some(a.value),
535                "selection"             => selection             = Some(a.value),
536                "noautovalidity"        => noautovalidity        = Some(a.value),
537                "validextensionstructs" => validextensionstructs = Some(a.value),
538                "values"                => values                = Some(a.value),
539                "limittype"             => limittype             = Some(a.value),
540                "objecttype"            => objecttype            = Some(a.value),
541                "deprecated"            => deprecated            = Some(a.value),
542                "api"                   => api                   = Some(a.value),
543                "featurelink"           => featurelink           = Some(a.value),
544                "flagsextend"           => flagsextend           = Some(a.value),
545                "flagsextendmember"     => flagsextendmember     = Some(a.value),
546            }
547            match_elements_combine_text!{ctx, code,
548                "type" => {
549                    let text = parse_text_element(ctx);
550                    code.push_str(&text);
551                    markup.push(TypeMemberMarkup::Type(text));
552                },
553                "name" => {
554                    let text = parse_text_element(ctx);
555                    code.push_str(&text);
556                    markup.push(TypeMemberMarkup::Name(text));
557                },
558                "enum" => {
559                    let text = parse_text_element(ctx);
560                    code.push_str(&text);
561                    markup.push(TypeMemberMarkup::Enum(text));
562                },
563                "comment" => {
564                    let text = parse_text_element(ctx);
565                    markup.push(TypeMemberMarkup::Comment(text));
566                },
567            }
568            members.push(TypeMember::Definition(TypeMemberDefinition {
569                len,
570                altlen,
571                externsync,
572                optional,
573                selector,
574                selection,
575                noautovalidity,
576                validextensionstructs,
577                values,
578                limittype,
579                objecttype,
580                deprecated,
581                api,
582                code,
583                markup,
584                featurelink,
585                flagsextend,
586                flagsextendmember,
587            }))
588        },
589        "comment" => members.push(TypeMember::Comment(parse_text_element(ctx))),
590        "name" => {
591            let text = parse_text_element(ctx);
592            code.push_str(&text);
593            markup.push(TypeCodeMarkup::Name(text));
594        },
595        "type" => {
596            let text = parse_text_element(ctx);
597            code.push_str(&text);
598            markup.push(TypeCodeMarkup::Type(text));
599        },
600        "apientry" => {
601            let text = parse_text_element(ctx);
602            code.push_str(&text);
603            markup.push(TypeCodeMarkup::ApiEntry(text));
604        },
605        "proto" => {
606            let mut name = None;
607            let mut type_name = None;
608            let mut code = String::new();
609            match_elements_combine_text! {ctx, code,
610                "type" => {
611                    let text = parse_text_element(ctx);
612                    code.push_str(&text);
613                    type_name = Some(text);
614                },
615                "name" => {
616                    let text = parse_text_element(ctx);
617                    code.push_str("(VKAPI_PTR *");
618                    code.push_str(&text);
619                    code.push_str(")");
620                    markup.push(TypeCodeMarkup::Name(text.clone())); // emulate pre-1.4.339 markup
621                    name = Some(text);
622                },
623            };
624            if let Some(name) = name {
625                proto = Some(FuncpointerProtoMarkup {
626                    type_name,
627                    name,
628                    code,
629                });
630            } else {
631                ctx.errors.push(Error::MissingElement {
632                    xpath: ctx.xpath.clone(),
633                    name: String::from("name"),
634                });
635            }
636        },
637        "param" => {
638            let mut param = String::new();
639            if let Some(p) = parse_name_with_type(ctx, &mut param) {
640                if let Some(ref t) = p.type_name {
641                    markup.push(TypeCodeMarkup::Type(t.clone())); // emulate pre-1.4.339 markup
642                }
643                params.push(p);
644            }
645        }
646    }
647
648    if let Some(ref proto) = proto {
649        // emulate pre-1.4.339 typedef
650        code.clear();
651        code.push_str("typedef ");
652        code.push_str(&proto.code);
653        code.push_str("(");
654        if params.is_empty() {
655            code.push_str("void");
656        } else {
657            let mut is_first = true;
658            for param in &params {
659                if is_first {
660                    is_first = false;
661                } else {
662                    code.push_str(", ");
663                }
664                code.push_str(&param.code);
665            }
666        }
667        code.push_str(");");
668    }
669
670    TypesChild::Type(Type {
671        api,
672        alias,
673        requires,
674        name,
675        category,
676        parent,
677        returnedonly,
678        structextends,
679        allowduplicate,
680        objtypeenum,
681        requiredlimittype,
682        bitvalues,
683        deprecated,
684        comment,
685        spec: if members.len() > 0 {
686            TypeSpec::Members(members)
687        } else if let Some(proto) = proto {
688            TypeSpec::Funcpointer(FuncpointerCode {
689                code,
690                markup,
691                proto,
692                params,
693            })
694        } else if code.len() > 0 {
695            TypeSpec::Code(TypeCode { code, markup })
696        } else {
697            TypeSpec::None
698        },
699    })
700}
701
702fn parse_command<R: Read>(ctx: &mut ParseCtx<R>, attributes: Vec<XmlAttribute>) -> Option<Command> {
703    let mut name = None;
704    let mut alias = None;
705    let mut tasks = None;
706    let mut queues = None;
707    let mut successcodes = None;
708    let mut errorcodes = None;
709    let mut renderpass = None;
710    let mut videocoding = None;
711    let mut conditionalrendering = None;
712    let mut cmdbufferlevel = None;
713    let mut allownoqueues = None;
714    let mut pipeline = None;
715    let mut comment = None;
716    let mut api = None;
717    let mut export = None;
718
719    match_attributes! {ctx, a in attributes,
720        "name" => name = Some(a.value),
721        "alias" => alias = Some(a.value),
722        "tasks" => tasks = Some(a.value),
723        "queues" => queues = Some(a.value),
724        "successcodes" => successcodes = Some(a.value),
725        "errorcodes" => errorcodes = Some(a.value),
726        "renderpass" => renderpass = Some(a.value),
727        "videocoding" => videocoding = Some(a.value),
728        "conditionalrendering" => conditionalrendering = Some(a.value),
729        "cmdbufferlevel" => cmdbufferlevel = Some(a.value),
730        "allownoqueues" => allownoqueues = Some(a.value),
731        "pipeline" => pipeline = Some(a.value),
732        "comment" => comment = Some(a.value),
733        "api" => api = Some(a.value),
734        "export" => export = Some(a.value),
735    }
736
737    if let Some(alias) = alias {
738        unwrap_attribute!(ctx, command, name);
739        consume_current_element(ctx);
740        Some(Command::Alias { alias, name })
741    } else {
742        let mut code = String::new();
743        let mut proto = None;
744        let mut params = Vec::new();
745        let mut description = None;
746        let mut implicitexternsyncparams = Vec::new();
747
748        match_elements! {ctx, attributes,
749            "proto" => {
750                proto = parse_name_with_type(ctx, &mut code);
751                code.push('(');
752            },
753
754            "param" => {
755                let mut len = None;
756                let mut altlen = None;
757                let mut externsync = None;
758                let mut optional = None;
759                let mut noautovalidity = None;
760                let mut objecttype = None;
761                let mut validstructs = None;
762                let mut stride = None;
763                let mut api = None;
764
765                match_attributes!{ctx, a in attributes,
766                    "len"            => len            = Some(a.value),
767                    "altlen"         => altlen         = Some(a.value),
768                    "externsync"     => externsync     = Some(a.value),
769                    "optional"       => optional       = Some(a.value),
770                    "noautovalidity" => noautovalidity = Some(a.value),
771                    "objecttype"     => objecttype     = Some(a.value),
772                    "validstructs"   => validstructs   = Some(a.value),
773                    "stride"         => stride         = Some(a.value),
774                    "api"            => api            = Some(a.value),
775                }
776
777                let validstructs = validstructs.map_or(
778                    Default::default(),
779                    |structs| structs.split(',').map(|s| s.to_owned()).collect()
780                );
781
782                if !params.is_empty() {
783                    code.push_str(", ");
784                }
785                if let Some(definition) = parse_name_with_type(ctx, &mut code) {
786                    params.push(CommandParam {
787                        len,
788                        altlen,
789                        externsync,
790                        optional,
791                        noautovalidity,
792                        objecttype,
793                        definition,
794                        validstructs,
795                        stride,
796                        api,
797                    });
798                }
799            },
800
801            "alias" => {
802                match_attributes!{ctx, a in attributes,
803                    "name" => alias = Some(a.value),
804                }
805                consume_current_element(ctx);
806            },
807
808            "description" => description = Some(parse_text_element(ctx)),
809            "implicitexternsyncparams" => {
810                match_elements!{ctx,
811                    "param" => implicitexternsyncparams.push(parse_text_element(ctx)),
812                }
813            }
814        }
815        code.push_str(");");
816
817        let proto = if let Some(v) = proto {
818            v
819        } else {
820            ctx.errors.push(Error::MissingElement {
821                xpath: ctx.xpath.clone(),
822                name: String::from("proto"),
823            });
824            return None;
825        };
826
827        let conditionalrendering = if let Some(v) = conditionalrendering {
828            match v.as_str() {
829                "true" => Some(true),
830                "false" => Some(false),
831                _ => {
832                    ctx.errors.push(Error::UnexpectedAttributeValue {
833                        xpath: ctx.xpath.clone(),
834                        name: String::from("conditionalrendering"),
835                        value: v,
836                    });
837                    return None;
838                }
839            }
840        } else {
841            None
842        };
843
844        Some(Command::Definition(CommandDefinition {
845            tasks,
846            queues,
847            successcodes,
848            errorcodes,
849            renderpass,
850            videocoding,
851            conditionalrendering,
852            cmdbufferlevel,
853            allownoqueues,
854            pipeline,
855            comment,
856            proto,
857            params,
858            alias,
859            description,
860            implicitexternsyncparams,
861            api,
862            export,
863            code,
864        }))
865    }
866}
867
868fn parse_enum<R: Read>(ctx: &mut ParseCtx<R>, attributes: Vec<XmlAttribute>) -> Option<Enum> {
869    let mut name = None;
870    let mut comment = None;
871    let mut type_suffix = None;
872    let mut api = None;
873    let mut extends = None;
874    let mut value = None;
875    let mut bitpos = None;
876    let mut extnumber = None;
877    let mut offset = None;
878    let mut positive = true;
879    let mut protect = None;
880    let mut alias = None;
881    let mut deprecated = None;
882
883    match_attributes! {ctx, a in attributes,
884        "name" => name = Some(a.value),
885        "comment" => comment = Some(a.value),
886        "type" => type_suffix = Some(a.value),
887        "api" => api = Some(a.value),
888        "extends" => extends = Some(a.value),
889        "value" => value = Some(a.value),
890        "offset" => offset = Some(a.value),
891        "dir" => {
892            if a.value.as_str() == "-" {
893                positive = false;
894            } else {
895                ctx.errors.push(Error::UnexpectedAttributeValue {
896                    xpath: ctx.xpath.clone(),
897                    name: String::from("dir"),
898                    value: a.value
899                });
900            }
901        },
902        "bitpos" => bitpos = Some(a.value),
903        "extnumber" => extnumber = Some(a.value),
904        "protect" => protect = Some(a.value),
905        "alias" => alias = Some(a.value),
906        "deprecated" => deprecated = Some(a.value),
907    }
908
909    unwrap_attribute!(ctx, enum, name);
910
911    let mut count = 0;
912    if offset.is_some() {
913        count += 1;
914    }
915    if bitpos.is_some() {
916        count += 1;
917    }
918    if value.is_some() {
919        count += 1;
920    }
921    if alias.is_some() {
922        count += 1;
923    }
924    if count > 1 {
925        ctx.errors.push(Error::SchemaViolation {
926            xpath: ctx.xpath.clone(),
927            desc: format!(
928                "Unable to determine correct specification of enum: offset={:?}, bitpos={:?}, value={:?}, alias={:?}",
929                offset, bitpos, value, alias
930            ),
931        });
932        consume_current_element(ctx);
933        return None;
934    }
935
936    let spec = if let Some(alias) = alias {
937        EnumSpec::Alias { alias, extends }
938    } else if let Some(offset) = offset {
939        let offset = match parse_integer(ctx, &offset) {
940            Some(v) => v,
941            None => {
942                consume_current_element(ctx);
943                return None;
944            }
945        };
946        if let Some(extends) = extends {
947            EnumSpec::Offset {
948                offset,
949                extends,
950                extnumber: match extnumber {
951                    Some(extnumber) => parse_integer(ctx, &extnumber),
952                    None => None,
953                },
954                dir: positive,
955            }
956        } else {
957            ctx.errors.push(Error::SchemaViolation {
958                xpath: ctx.xpath.clone(),
959                desc: String::from("Missing extends on enum with offset spec."),
960            });
961            consume_current_element(ctx);
962            return None;
963        }
964    } else if let Some(bitpos) = bitpos {
965        let bitpos = match parse_integer(ctx, &bitpos) {
966            Some(v) => v,
967            None => {
968                consume_current_element(ctx);
969                return None;
970            }
971        };
972        EnumSpec::Bitpos { bitpos, extends }
973    } else if let Some(value) = value {
974        EnumSpec::Value { value, extends }
975    } else {
976        EnumSpec::None
977    };
978
979    consume_current_element(ctx);
980
981    Some(Enum {
982        name,
983        comment,
984        type_suffix,
985        api,
986        protect,
987        deprecated,
988        spec,
989    })
990}
991
992fn parse_enums_child_unused<R: Read>(
993    ctx: &mut ParseCtx<R>,
994    attributes: Vec<XmlAttribute>,
995) -> Option<EnumsChild> {
996    let mut start = None;
997    let mut end = None;
998    let mut vendor = None;
999    let mut comment = None;
1000    match_attributes! {ctx, a in attributes,
1001        "start"   => start   = Some(a.value),
1002        "end"     => end     = Some(a.value),
1003        "vendor"  => vendor  = Some(a.value),
1004        "comment" => comment = Some(a.value),
1005    }
1006    consume_current_element(ctx);
1007    unwrap_attribute!(ctx, unused, start);
1008    let start = match parse_integer(ctx, &start) {
1009        Some(v) => v,
1010        None => return None,
1011    };
1012    let end = end.and_then(|val| parse_integer(ctx, &val));
1013    Some(EnumsChild::Unused(Unused {
1014        start,
1015        end,
1016        vendor,
1017        comment,
1018    }))
1019}
1020
1021fn parse_feature<R: Read>(
1022    ctx: &mut ParseCtx<R>,
1023    attributes: Vec<XmlAttribute>,
1024) -> Option<RegistryChild> {
1025    let mut api = None;
1026    let mut apitype = None;
1027    let mut name = None;
1028    let mut number = None;
1029    let mut depends = None;
1030    let mut protect = None;
1031    let mut comment = None;
1032    let mut children = Vec::new();
1033
1034    match_attributes! {ctx, a in attributes,
1035        "api"     => api     = Some(a.value),
1036        "apitype" => apitype = Some(a.value),
1037        "name"    => name    = Some(a.value),
1038        "number"  => number  = Some(a.value),
1039        "depends" => depends = Some(a.value),
1040        "protect" => protect = Some(a.value),
1041        "comment" => comment = Some(a.value),
1042    }
1043
1044    match_elements! {ctx, attributes,
1045        "require" => children.push(parse_extension_item_require(ctx, attributes)),
1046        "deprecate" => if let Some(child) = parse_extension_item_deprecate(ctx, attributes) { children.push(child) },
1047        "remove"  => children.push(parse_extension_item_remove(ctx, attributes)),
1048    }
1049
1050    unwrap_attribute!(ctx, feature, api);
1051    unwrap_attribute!(ctx, feature, name);
1052
1053    Some(RegistryChild::Feature(Feature {
1054        api,
1055        apitype,
1056        name,
1057        number,
1058        depends,
1059        protect,
1060        comment,
1061        children,
1062    }))
1063}
1064
1065fn parse_extensions<R: Read>(
1066    ctx: &mut ParseCtx<R>,
1067    attributes: Vec<XmlAttribute>,
1068) -> RegistryChild {
1069    let mut comment = None;
1070    let mut children = Vec::new();
1071
1072    match_attributes! {ctx, a in attributes,
1073        "comment" => comment = Some(a.value),
1074    }
1075
1076    match_elements! {ctx, attributes,
1077        "extension" => if let Some(v) = parse_extension(ctx, attributes) {
1078            children.push(v);
1079        },
1080    }
1081
1082    RegistryChild::Extensions(Extensions { comment, children })
1083}
1084
1085fn parse_extension<R: Read>(
1086    ctx: &mut ParseCtx<R>,
1087    attributes: Vec<XmlAttribute>,
1088) -> Option<Extension> {
1089    let mut name = None;
1090    let mut comment = None;
1091    let mut number = None;
1092    let mut protect = None;
1093    let mut platform = None;
1094    let mut author = None;
1095    let mut contact = None;
1096    let mut ext_type = None;
1097    let mut requires = None;
1098    let mut requires_core = None;
1099    let mut supported = None;
1100    let mut ratified = None;
1101    let mut deprecatedby = None;
1102    let mut promotedto = None;
1103    let mut obsoletedby = None;
1104    let mut provisional = None;
1105    let mut specialuse = None;
1106    let mut sortorder = None;
1107    let mut depends = None;
1108    let mut nofeatures = None;
1109    let mut children = Vec::new();
1110
1111    match_attributes! {ctx, a in attributes,
1112        "name"         => name          = Some(a.value),
1113        "comment"      => comment       = Some(a.value),
1114        "number"       => number        = Some(a.value),
1115        "protect"      => protect       = Some(a.value),
1116        "platform"     => platform      = Some(a.value),
1117        "author"       => author        = Some(a.value),
1118        "contact"      => contact       = Some(a.value),
1119        "type"         => ext_type      = Some(a.value),
1120        "requires"     => requires      = Some(a.value),
1121        "requiresCore" => requires_core = Some(a.value),
1122        "supported"    => supported     = Some(a.value),
1123        "ratified"     => ratified      = Some(a.value),
1124        "deprecatedby" => deprecatedby  = Some(a.value),
1125        "promotedto"   => promotedto    = Some(a.value),
1126        "provisional"  => provisional   = Some(a.value),
1127        "obsoletedby"  => obsoletedby   = Some(a.value),
1128        "specialuse"   => specialuse    = Some(a.value),
1129        "sortorder"    => sortorder     = Some(a.value),
1130        "depends"      => depends       = Some(a.value),
1131        "nofeatures"   => nofeatures    = Some(a.value),
1132    }
1133
1134    let number = match number {
1135        Some(text) => parse_integer(ctx, &text),
1136        None => None,
1137    };
1138
1139    let provisional = match provisional.as_deref() {
1140        Some("true") => true,
1141        Some("false") => false,
1142        Some(value) => {
1143            ctx.errors.push(Error::SchemaViolation {
1144                xpath: ctx.xpath.clone(),
1145                desc: format!("Unexpected value of 'provisional' attribute: {}", value),
1146            });
1147            false
1148        }
1149        None => false,
1150    };
1151    let nofeatures = match nofeatures.as_deref() {
1152        Some("true") => true,
1153        Some("false") => false,
1154        Some(value) => {
1155            ctx.errors.push(Error::SchemaViolation {
1156                xpath: ctx.xpath.clone(),
1157                desc: format!("Unexpected value of 'nofeatures' attribute: {}", value),
1158            });
1159            false
1160        }
1161        None => false,
1162    };
1163
1164    let sortorder = match sortorder {
1165        Some(text) => parse_integer(ctx, &text),
1166        None => None,
1167    };
1168
1169    unwrap_attribute!(ctx, extension, name);
1170
1171    match_elements! {ctx, attributes,
1172        "require" => children.push(parse_extension_item_require(ctx, attributes)),
1173        "deprecate" => if let Some(child) = parse_extension_item_deprecate(ctx, attributes) { children.push(child) },
1174        "remove" => children.push(parse_extension_item_remove(ctx, attributes)),
1175    }
1176
1177    Some(Extension {
1178        name,
1179        comment,
1180        number,
1181        protect,
1182        platform,
1183        author,
1184        contact,
1185        ext_type,
1186        requires,
1187        requires_core,
1188        supported,
1189        ratified,
1190        deprecatedby,
1191        promotedto,
1192        obsoletedby,
1193        provisional,
1194        specialuse,
1195        sortorder,
1196        depends,
1197        nofeatures,
1198        children,
1199    })
1200}
1201
1202fn parse_extension_item_require<R: Read>(
1203    ctx: &mut ParseCtx<R>,
1204    attributes: Vec<XmlAttribute>,
1205) -> ExtensionChild {
1206    let mut api = None;
1207    let mut profile = None;
1208    let mut extension = None;
1209    let mut feature = None;
1210    let mut comment = None;
1211    let mut depends = None;
1212    let mut items = Vec::new();
1213
1214    match_attributes! {ctx, a in attributes,
1215        "api"       => api       = Some(a.value),
1216        "profile"   => profile   = Some(a.value),
1217        "extension" => extension = Some(a.value),
1218        "feature"   => feature   = Some(a.value),
1219        "comment"   => comment   = Some(a.value),
1220        "depends"   => depends   = Some(a.value),
1221    }
1222
1223    while let Some(Ok(e)) = ctx.events.next() {
1224        match e {
1225            XmlEvent::StartElement {
1226                name, attributes, ..
1227            } => {
1228                let name = name.local_name.as_str();
1229                ctx.push_element(name);
1230                if let Some(v) = parse_interface_item(ctx, name, attributes) {
1231                    items.push(v);
1232                }
1233            }
1234            XmlEvent::EndElement { .. } => {
1235                ctx.pop_element();
1236                break;
1237            }
1238            _ => {}
1239        }
1240    }
1241
1242    ExtensionChild::Require {
1243        api,
1244        profile,
1245        extension,
1246        feature,
1247        comment,
1248        depends,
1249        items,
1250    }
1251}
1252
1253fn parse_extension_item_deprecate<R: Read>(
1254    ctx: &mut ParseCtx<R>,
1255    attributes: Vec<XmlAttribute>,
1256) -> Option<ExtensionChild> {
1257    let mut api = None;
1258    let mut profile = None;
1259    let mut comment = None;
1260    let mut explanationlink = None;
1261    let mut items = Vec::new();
1262
1263    match_attributes! {ctx, a in attributes,
1264        "api"             => api             = Some(a.value),
1265        "profile"         => profile         = Some(a.value),
1266        "comment"         => comment         = Some(a.value),
1267        "explanationlink" => explanationlink = Some(a.value),
1268    }
1269
1270    unwrap_attribute!(ctx, deprecate, explanationlink);
1271
1272    while let Some(Ok(e)) = ctx.events.next() {
1273        match e {
1274            XmlEvent::StartElement {
1275                name, attributes, ..
1276            } => {
1277                let name = name.local_name.as_str();
1278                ctx.push_element(name);
1279                if let Some(v) = parse_interface_item(ctx, name, attributes) {
1280                    items.push(v);
1281                }
1282            }
1283            XmlEvent::EndElement { .. } => {
1284                ctx.pop_element();
1285                break;
1286            }
1287            _ => {}
1288        }
1289    }
1290
1291    Some(ExtensionChild::Deprecate {
1292        api,
1293        profile,
1294        comment,
1295        explanationlink,
1296        items,
1297    })
1298}
1299
1300fn parse_extension_item_remove<R: Read>(
1301    ctx: &mut ParseCtx<R>,
1302    attributes: Vec<XmlAttribute>,
1303) -> ExtensionChild {
1304    let mut api = None;
1305    let mut profile = None;
1306    let mut comment = None;
1307    let mut reasonlink = None;
1308    let mut items = Vec::new();
1309
1310    match_attributes! {ctx, a in attributes,
1311        "api"        => api        = Some(a.value),
1312        "profile"    => profile    = Some(a.value),
1313        "comment"    => comment    = Some(a.value),
1314        "reasonlink" => reasonlink = Some(a.value),
1315    }
1316
1317    while let Some(Ok(e)) = ctx.events.next() {
1318        match e {
1319            XmlEvent::StartElement {
1320                name, attributes, ..
1321            } => {
1322                let name = name.local_name.as_str();
1323                ctx.push_element(name);
1324                if let Some(v) = parse_interface_item(ctx, name, attributes) {
1325                    items.push(v);
1326                }
1327            }
1328            XmlEvent::EndElement { .. } => {
1329                ctx.pop_element();
1330                break;
1331            }
1332            _ => {}
1333        }
1334    }
1335
1336    ExtensionChild::Remove {
1337        api,
1338        profile,
1339        comment,
1340        reasonlink,
1341        items,
1342    }
1343}
1344
1345fn parse_interface_item<R: Read>(
1346    ctx: &mut ParseCtx<R>,
1347    name: &str,
1348    attributes: Vec<XmlAttribute>,
1349) -> Option<InterfaceItem> {
1350    match name {
1351        "comment" => Some(InterfaceItem::Comment(parse_text_element(ctx))),
1352        "type" => {
1353            let mut name = None;
1354            let mut comment = None;
1355            let mut supersededby = None;
1356            match_attributes! {ctx, a in attributes,
1357                "name"    => name    = Some(a.value),
1358                "comment" => comment = Some(a.value),
1359                "supersededby" => supersededby = Some(a.value),
1360            }
1361            unwrap_attribute!(ctx, type, name);
1362            consume_current_element(ctx);
1363            Some(InterfaceItem::Type {
1364                name,
1365                comment,
1366                supersededby,
1367            })
1368        }
1369        "enum" => parse_enum(ctx, attributes).map(|v| InterfaceItem::Enum(v)),
1370        "command" => {
1371            let mut name = None;
1372            let mut comment = None;
1373            let mut supersededby = None;
1374            match_attributes! {ctx, a in attributes,
1375                "name"    => name    = Some(a.value),
1376                "comment" => comment = Some(a.value),
1377                "supersededby" => supersededby = Some(a.value),
1378            }
1379            unwrap_attribute!(ctx, type, name);
1380            consume_current_element(ctx);
1381            Some(InterfaceItem::Command {
1382                name,
1383                comment,
1384                supersededby,
1385            })
1386        }
1387        "feature" => {
1388            let mut name = None;
1389            let mut struct_ = None;
1390            let mut comment = None;
1391            match_attributes! {ctx, a in attributes,
1392                "name"    => name    = Some(a.value),
1393                "struct"  => struct_ = Some(a.value),
1394                "comment" => comment = Some(a.value),
1395            }
1396            unwrap_attribute!(ctx, type, name);
1397            unwrap_attribute!(ctx, type, struct_);
1398            consume_current_element(ctx);
1399            Some(InterfaceItem::Feature {
1400                name,
1401                struct_,
1402                comment,
1403            })
1404        }
1405        _ => {
1406            ctx.errors.push(Error::UnexpectedElement {
1407                xpath: ctx.xpath.clone(),
1408                name: String::from(name),
1409            });
1410            return None;
1411        }
1412    }
1413}
1414
1415fn parse_formats<R: Read>(ctx: &mut ParseCtx<R>) -> RegistryChild {
1416    let mut children = Vec::new();
1417
1418    match_elements! {ctx, attributes,
1419        "format" => if let Some(v) = parse_format(ctx, attributes) {
1420            children.push(v);
1421        },
1422    }
1423
1424    RegistryChild::Formats(Formats {
1425        comment: None,
1426        children,
1427    })
1428}
1429
1430#[allow(non_snake_case)]
1431fn parse_format<R: Read>(ctx: &mut ParseCtx<R>, attributes: Vec<XmlAttribute>) -> Option<Format> {
1432    let mut name = None;
1433    let mut class = None;
1434    let mut blockSize = None;
1435    let mut texelsPerBlock = None;
1436    let mut blockExtent = None;
1437    let mut packed = None;
1438    let mut compressed = None;
1439    let mut chroma = None;
1440    let mut children = Vec::new();
1441
1442    match_attributes! {ctx, a in attributes,
1443        "name"           => name           = Some(a.value),
1444        "class"          => class          = Some(a.value),
1445        "blockSize"      => blockSize      = Some(a.value),
1446        "texelsPerBlock" => texelsPerBlock = Some(a.value),
1447        "blockExtent"    => blockExtent    = Some(a.value),
1448        "packed"         => packed         = Some(a.value),
1449        "compressed"     => compressed     = Some(a.value),
1450        "chroma"         => chroma         = Some(a.value),
1451    }
1452
1453    unwrap_attribute!(ctx, extension, name);
1454    unwrap_attribute!(ctx, extension, class);
1455    unwrap_attribute!(ctx, extension, blockSize);
1456    unwrap_attribute!(ctx, extension, texelsPerBlock);
1457
1458    match_elements! {ctx, attributes,
1459        "component"        => if let Some(v) = parse_format_component(ctx, attributes) { children.push(v); },
1460        "plane"            => if let Some(v) = parse_format_plane(ctx, attributes) { children.push(v); },
1461        "spirvimageformat" => if let Some(v) = parse_format_spirvimageformat(ctx, attributes) { children.push(v); },
1462    }
1463
1464    let blockSize: Option<u8> = parse_int_attribute(ctx, blockSize, "blockSize");
1465    let texelsPerBlock: Option<u8> = parse_int_attribute(ctx, texelsPerBlock, "texelsPerBlock");
1466    let packed = packed.map(|v| -> Option<u8> { parse_int_attribute(ctx, v, "packed") });
1467
1468    let blockSize = match blockSize {
1469        Some(v) => v,
1470        None => return None,
1471    };
1472
1473    let texelsPerBlock = match texelsPerBlock {
1474        Some(v) => v,
1475        None => return None,
1476    };
1477
1478    let packed = match packed {
1479        Some(Some(v)) => Some(v),
1480        Some(None) => return None, // Attribute present, but parse error occurred.
1481        None => None,
1482    };
1483
1484    Some(Format {
1485        name,
1486        class,
1487        blockSize,
1488        texelsPerBlock,
1489        blockExtent,
1490        packed,
1491        compressed,
1492        chroma,
1493        children,
1494    })
1495}
1496
1497#[allow(non_snake_case)]
1498fn parse_format_component<R: Read>(
1499    ctx: &mut ParseCtx<R>,
1500    attributes: Vec<XmlAttribute>,
1501) -> Option<FormatChild> {
1502    let mut name = None;
1503    let mut bits = None;
1504    let mut numericFormat = None;
1505    let mut planeIndex = None;
1506
1507    match_attributes! {ctx, a in attributes,
1508        "name"          => name          = Some(a.value),
1509        "bits"          => bits          = Some(a.value),
1510        "numericFormat" => numericFormat = Some(a.value),
1511        "planeIndex"    => planeIndex    = Some(a.value),
1512    }
1513
1514    unwrap_attribute!(ctx, extension, name);
1515    unwrap_attribute!(ctx, extension, bits);
1516    unwrap_attribute!(ctx, extension, numericFormat);
1517
1518    consume_current_element(ctx);
1519
1520    let planeIndex =
1521        planeIndex.map(|v| -> Option<u8> { parse_int_attribute(ctx, v, "planeIndex") });
1522
1523    let planeIndex = match planeIndex {
1524        Some(Some(v)) => Some(v),
1525        Some(None) => return None, // Attribute present, but parse error occurred.
1526        None => None,
1527    };
1528
1529    Some(FormatChild::Component {
1530        name,
1531        bits,
1532        numericFormat,
1533        planeIndex,
1534    })
1535}
1536
1537#[allow(non_snake_case)]
1538fn parse_format_plane<R: Read>(
1539    ctx: &mut ParseCtx<R>,
1540    attributes: Vec<XmlAttribute>,
1541) -> Option<FormatChild> {
1542    let mut index = None;
1543    let mut widthDivisor = None;
1544    let mut heightDivisor = None;
1545    let mut compatible = None;
1546
1547    match_attributes! {ctx, a in attributes,
1548        "index"         => index         = Some(a.value),
1549        "widthDivisor"  => widthDivisor  = Some(a.value),
1550        "heightDivisor" => heightDivisor = Some(a.value),
1551        "compatible"    => compatible    = Some(a.value),
1552    }
1553
1554    unwrap_attribute!(ctx, extension, index);
1555    unwrap_attribute!(ctx, extension, widthDivisor);
1556    unwrap_attribute!(ctx, extension, heightDivisor);
1557    unwrap_attribute!(ctx, extension, compatible);
1558
1559    consume_current_element(ctx);
1560
1561    let index: Option<u8> = parse_int_attribute(ctx, index, "index");
1562    let widthDivisor: Option<u8> = parse_int_attribute(ctx, widthDivisor, "widthDivisor");
1563    let heightDivisor: Option<u8> = parse_int_attribute(ctx, heightDivisor, "heightDivisor");
1564
1565    let index = match index {
1566        Some(v) => v,
1567        None => return None,
1568    };
1569
1570    let widthDivisor = match widthDivisor {
1571        Some(v) => v,
1572        None => return None,
1573    };
1574
1575    let heightDivisor = match heightDivisor {
1576        Some(v) => v,
1577        None => return None,
1578    };
1579
1580    Some(FormatChild::Plane {
1581        index,
1582        widthDivisor,
1583        heightDivisor,
1584        compatible,
1585    })
1586}
1587
1588fn parse_format_spirvimageformat<R: Read>(
1589    ctx: &mut ParseCtx<R>,
1590    attributes: Vec<XmlAttribute>,
1591) -> Option<FormatChild> {
1592    let mut name = None;
1593
1594    match_attributes! {ctx, a in attributes,
1595        "name" => name = Some(a.value),
1596    }
1597
1598    unwrap_attribute!(ctx, extension, name);
1599
1600    consume_current_element(ctx);
1601
1602    Some(FormatChild::SpirvImageFormat { name })
1603}
1604
1605fn parse_spirvextensions<R: Read>(
1606    ctx: &mut ParseCtx<R>,
1607    attributes: Vec<XmlAttribute>,
1608) -> RegistryChild {
1609    let mut comment = None;
1610    let mut children = Vec::new();
1611
1612    match_attributes! {ctx, a in attributes,
1613        "comment" => comment = Some(a.value),
1614    }
1615
1616    match_elements! {ctx, attributes,
1617        "spirvextension" => if let Some(v) = parse_spirvextension(ctx, attributes) {
1618            children.push(v);
1619        },
1620    }
1621
1622    RegistryChild::SpirvExtensions(SpirvExtensions { comment, children })
1623}
1624
1625fn parse_spirvextension<R: Read>(
1626    ctx: &mut ParseCtx<R>,
1627    attributes: Vec<XmlAttribute>,
1628) -> Option<SpirvExtension> {
1629    let mut name = None;
1630    let mut enables = Vec::new();
1631
1632    match_attributes! {ctx, a in attributes,
1633        "name" => name = Some(a.value),
1634    }
1635
1636    match_elements! {ctx, attributes,
1637        "enable" => if let Some(v) = parse_enable(ctx, attributes) {
1638            enables.push(v);
1639        },
1640    }
1641
1642    unwrap_attribute!(ctx, spirvextension, name);
1643
1644    Some(SpirvExtension { name, enables })
1645}
1646
1647fn parse_spirvcapabilities<R: Read>(
1648    ctx: &mut ParseCtx<R>,
1649    attributes: Vec<XmlAttribute>,
1650) -> RegistryChild {
1651    let mut comment = None;
1652    let mut children = Vec::new();
1653
1654    match_attributes! {ctx, a in attributes,
1655        "comment" => comment = Some(a.value),
1656    }
1657
1658    match_elements! {ctx, attributes,
1659        "spirvcapability" => if let Some(v) = parse_spirvcapability(ctx, attributes) {
1660            children.push(v);
1661        },
1662    }
1663
1664    RegistryChild::SpirvCapabilities(SpirvCapabilities { comment, children })
1665}
1666
1667fn parse_spirvcapability<R: Read>(
1668    ctx: &mut ParseCtx<R>,
1669    attributes: Vec<XmlAttribute>,
1670) -> Option<SpirvCapability> {
1671    let mut name = None;
1672    let mut enables = Vec::new();
1673
1674    match_attributes! {ctx, a in attributes,
1675        "name" => name = Some(a.value),
1676    }
1677
1678    match_elements! {ctx, attributes,
1679        "enable" => if let Some(v) = parse_enable(ctx, attributes) {
1680            enables.push(v);
1681        },
1682    }
1683
1684    unwrap_attribute!(ctx, spirvcapability, name);
1685
1686    Some(SpirvCapability { name, enables })
1687}
1688
1689fn parse_enable<R: Read>(ctx: &mut ParseCtx<R>, attributes: Vec<XmlAttribute>) -> Option<Enable> {
1690    let mut version = None;
1691    let mut extension = None;
1692    let mut struct_ = None;
1693    let mut feature = None;
1694    let mut requires = None;
1695    let mut alias = None;
1696    let mut property = None;
1697    let mut member = None;
1698    let mut value = None;
1699
1700    match_attributes! {ctx, a in attributes,
1701        "version" => version = Some(a.value),
1702        "extension" => extension = Some(a.value),
1703        "struct" => struct_ = Some(a.value),
1704        "feature" => feature = Some(a.value),
1705        "requires" => requires = Some(a.value),
1706        "alias" => alias = Some(a.value),
1707        "property" => property = Some(a.value),
1708        "member" => member = Some(a.value),
1709        "value" => value = Some(a.value),
1710    }
1711
1712    consume_current_element(ctx);
1713
1714    if let Some(version) = version {
1715        Some(Enable::Version(version))
1716    } else if let Some(extension) = extension {
1717        Some(Enable::Extension(extension))
1718    } else if let Some(struct_) = struct_ {
1719        unwrap_attribute!(ctx, enable, feature);
1720        Some(Enable::Feature(FeatureEnable {
1721            struct_,
1722            feature,
1723            requires,
1724            alias,
1725        }))
1726    } else if let Some(property) = property {
1727        unwrap_attribute!(ctx, enable, member);
1728        unwrap_attribute!(ctx, enable, value);
1729        Some(Enable::Property(PropertyEnable {
1730            property,
1731            member,
1732            value,
1733            requires,
1734        }))
1735    } else {
1736        unimplemented!();
1737    }
1738}
1739
1740fn parse_sync<R: Read>(ctx: &mut ParseCtx<R>, attributes: Vec<XmlAttribute>) -> RegistryChild {
1741    let mut comment = None;
1742    let mut children = Vec::new();
1743
1744    match_attributes! {ctx, a in attributes,
1745        "comment" => comment = Some(a.value),
1746    }
1747
1748    match_elements! {ctx, attributes,
1749        "syncstage" => if let Some(v) = parse_syncstage(ctx, attributes) {
1750            children.push(v);
1751        },
1752        "syncaccess" => if let Some(v) = parse_syncaccess(ctx, attributes) {
1753            children.push(v);
1754        },
1755        "syncpipeline" => if let Some(v) = parse_syncpipeline(ctx, attributes) {
1756            children.push(v);
1757        },
1758    }
1759
1760    RegistryChild::Sync(Sync { comment, children })
1761}
1762
1763fn parse_syncsupport<R: Read>(
1764    ctx: &mut ParseCtx<R>,
1765    attributes: Vec<XmlAttribute>,
1766) -> Option<SyncSupport> {
1767    let mut queues = None;
1768    let mut stage = None;
1769    match_attributes! { ctx, a in attributes,
1770        "queues" => queues = Some(a.value),
1771        "stage" => stage = Some(a.value),
1772    }
1773    consume_current_element(ctx);
1774    Some(SyncSupport { queues, stage })
1775}
1776
1777fn parse_syncequivalent<R: Read>(
1778    ctx: &mut ParseCtx<R>,
1779    attributes: Vec<XmlAttribute>,
1780) -> Option<SyncEquivalent> {
1781    let mut stage = None;
1782    let mut access = None;
1783    match_attributes! { ctx, a in attributes,
1784        "stage" => stage = Some(a.value),
1785        "access" => access = Some(a.value),
1786    }
1787    consume_current_element(ctx);
1788    Some(SyncEquivalent { stage, access })
1789}
1790
1791fn parse_syncstage<R: Read>(
1792    ctx: &mut ParseCtx<R>,
1793    attributes: Vec<XmlAttribute>,
1794) -> Option<SyncChild> {
1795    let mut name = None;
1796    let mut alias = None;
1797    let mut syncsupport = None;
1798    let mut syncequivalent = None;
1799
1800    match_attributes! { ctx, a in attributes,
1801        "name" => name = Some(a.value),
1802        "alias" => alias = Some(a.value),
1803    }
1804
1805    match_elements! {ctx, attributes,
1806        "syncsupport" => syncsupport = parse_syncsupport(ctx, attributes),
1807        "syncequivalent" => syncequivalent = parse_syncequivalent(ctx, attributes),
1808    }
1809
1810    unwrap_attribute!(ctx, syncstage, name);
1811
1812    Some(SyncChild::Stage(SyncStage {
1813        name,
1814        alias,
1815        syncsupport,
1816        syncequivalent,
1817    }))
1818}
1819
1820fn parse_syncaccess<R: Read>(
1821    ctx: &mut ParseCtx<R>,
1822    attributes: Vec<XmlAttribute>,
1823) -> Option<SyncChild> {
1824    let mut name = None;
1825    let mut alias = None;
1826    let mut comment = None;
1827    let mut syncsupport = None;
1828    let mut syncequivalent = None;
1829
1830    match_attributes! { ctx, a in attributes,
1831        "name" => name = Some(a.value),
1832        "alias" => alias = Some(a.value),
1833    }
1834
1835    match_elements! { ctx, attributes,
1836        "comment" => comment = Some(parse_text_element(ctx)),
1837        "syncsupport" => syncsupport = parse_syncsupport(ctx, attributes),
1838        "syncequivalent" => syncequivalent = parse_syncequivalent(ctx, attributes),
1839    }
1840
1841    unwrap_attribute!(ctx, syncaccess, name);
1842
1843    Some(SyncChild::Access(SyncAccess {
1844        name,
1845        alias,
1846        comment,
1847        syncsupport,
1848        syncequivalent,
1849    }))
1850}
1851
1852fn parse_syncpipeline<R: Read>(
1853    ctx: &mut ParseCtx<R>,
1854    attributes: Vec<XmlAttribute>,
1855) -> Option<SyncChild> {
1856    let mut name = None;
1857    let mut depends = None;
1858    let mut children = Vec::new();
1859
1860    match_attributes! {ctx, a in attributes,
1861        "name" => name = Some(a.value),
1862        "depends" => depends = Some(a.value),
1863    }
1864
1865    match_elements! { ctx, attributes,
1866        "syncpipelinestage" => if let Some(v) = parse_syncpipelinestage(ctx, attributes) {
1867            children.push(v);
1868        },
1869    }
1870
1871    unwrap_attribute!(ctx, syncpipeline, name);
1872
1873    Some(SyncChild::Pipeline(SyncPipeline {
1874        name,
1875        depends,
1876        children,
1877    }))
1878}
1879
1880fn parse_syncpipelinestage<R: Read>(
1881    ctx: &mut ParseCtx<R>,
1882    attributes: Vec<XmlAttribute>,
1883) -> Option<SyncPipelineStage> {
1884    let mut order = None;
1885    let mut before = None;
1886    let mut after = None;
1887    match_attributes! {ctx, a in attributes,
1888        "order" => order = Some(a.value),
1889        "before" => before = Some(a.value),
1890        "after" => after = Some(a.value),
1891    }
1892
1893    let text = parse_text_element(ctx);
1894
1895    Some(SyncPipelineStage {
1896        order,
1897        before,
1898        after,
1899        text,
1900    })
1901}
1902
1903fn parse_videocodecs<R: Read>(
1904    ctx: &mut ParseCtx<R>,
1905    attributes: Vec<XmlAttribute>,
1906) -> RegistryChild {
1907    let mut comment = None;
1908    let mut children = Vec::new();
1909
1910    match_attributes! {ctx, a in attributes,
1911        "comment" => comment = Some(a.value),
1912    }
1913
1914    match_elements! {ctx, attributes,
1915        "videocodec" => if let Some(v) = parse_videocodec(ctx, attributes) {
1916            children.push(v);
1917        },
1918    }
1919
1920    RegistryChild::VideoCodecs(VideoCodecs { comment, children })
1921}
1922
1923fn parse_videocodec<R: Read>(
1924    ctx: &mut ParseCtx<R>,
1925    attributes: Vec<XmlAttribute>,
1926) -> Option<VideoCodec> {
1927    let mut comment = None;
1928    let mut name = None;
1929    let mut extend = None;
1930    let mut value = None;
1931    let mut children = Vec::new();
1932
1933    match_attributes! {ctx, a in attributes,
1934        "comment" => comment = Some(a.value),
1935        "name" => name = Some(a.value),
1936        "extend" => extend = Some(a.value),
1937        "value" => value = Some(a.value),
1938    }
1939
1940    match_elements! {ctx, attributes,
1941        "videoprofiles" => if let Some(v) = parse_videoprofiles(ctx, attributes) {
1942            children.push(VideoCodecChild::Profiles(v));
1943        },
1944        "videocapabilities" => if let Some(v) = parse_videocapabilities(ctx, attributes) {
1945            children.push(VideoCodecChild::Capabilities(v));
1946        },
1947        "videoformat" => if let Some(v) = parse_videoformat(ctx, attributes) {
1948            children.push(VideoCodecChild::Format(v));
1949        },
1950    }
1951
1952    unwrap_attribute!(ctx, videocodec, name);
1953
1954    Some(VideoCodec {
1955        comment,
1956        name,
1957        extend,
1958        value,
1959        children,
1960    })
1961}
1962
1963fn parse_videoprofiles<R: Read>(
1964    ctx: &mut ParseCtx<R>,
1965    attributes: Vec<XmlAttribute>,
1966) -> Option<VideoProfiles> {
1967    let mut comment = None;
1968    let mut struct_ = None;
1969    let mut children = Vec::new();
1970
1971    match_attributes! {ctx, a in attributes,
1972        "comment" => comment = Some(a.value),
1973        "struct" => struct_ = Some(a.value),
1974    }
1975
1976    match_elements! {ctx, attributes,
1977        "videoprofilemember" => if let Some(v) = parse_videoprofilemember(ctx, attributes) {
1978            children.push(v);
1979        },
1980    }
1981
1982    unwrap_attribute!(ctx, videoprofiles, struct_, "struct");
1983
1984    Some(VideoProfiles {
1985        comment,
1986        struct_,
1987        children,
1988    })
1989}
1990
1991fn parse_videoprofilemember<R: Read>(
1992    ctx: &mut ParseCtx<R>,
1993    attributes: Vec<XmlAttribute>,
1994) -> Option<VideoProfileMember> {
1995    let mut comment = None;
1996    let mut name = None;
1997    let mut children = Vec::new();
1998
1999    match_attributes! {ctx, a in attributes,
2000        "comment" => comment = Some(a.value),
2001        "name" => name = Some(a.value),
2002    }
2003
2004    match_elements! {ctx, attributes,
2005        "videoprofile" => if let Some(v) = parse_videoprofile(ctx, attributes) {
2006            children.push(v);
2007        },
2008    }
2009
2010    unwrap_attribute!(ctx, videoprofilemember, name);
2011
2012    Some(VideoProfileMember {
2013        comment,
2014        name,
2015        children,
2016    })
2017}
2018
2019fn parse_videoprofile<R: Read>(
2020    ctx: &mut ParseCtx<R>,
2021    attributes: Vec<XmlAttribute>,
2022) -> Option<VideoProfile> {
2023    let mut comment = None;
2024    let mut name = None;
2025    let mut value = None;
2026
2027    match_attributes! {ctx, a in attributes,
2028        "comment" => comment = Some(a.value),
2029        "name" => name = Some(a.value),
2030        "value" => value = Some(a.value),
2031    }
2032
2033    consume_current_element(ctx);
2034
2035    unwrap_attribute!(ctx, videoprofile, name);
2036    unwrap_attribute!(ctx, videoprofile, value);
2037
2038    Some(VideoProfile {
2039        comment,
2040        name,
2041        value,
2042    })
2043}
2044
2045fn parse_videocapabilities<R: Read>(
2046    ctx: &mut ParseCtx<R>,
2047    attributes: Vec<XmlAttribute>,
2048) -> Option<VideoCapabilities> {
2049    let mut comment = None;
2050    let mut struct_ = None;
2051
2052    match_attributes! {ctx, a in attributes,
2053        "comment" => comment = Some(a.value),
2054        "struct" => struct_ = Some(a.value),
2055    }
2056
2057    consume_current_element(ctx);
2058
2059    unwrap_attribute!(ctx, videocapabilities, struct_, "struct");
2060
2061    Some(VideoCapabilities { comment, struct_ })
2062}
2063
2064fn parse_videoformat<R: Read>(
2065    ctx: &mut ParseCtx<R>,
2066    attributes: Vec<XmlAttribute>,
2067) -> Option<VideoFormat> {
2068    let mut comment = None;
2069    let mut name = None;
2070    let mut usage = None;
2071    let mut extend = None;
2072    let mut children = Vec::new();
2073
2074    match_attributes! {ctx, a in attributes,
2075        "comment" => comment = Some(a.value),
2076        "name" => name = Some(a.value),
2077        "usage" => usage = Some(a.value),
2078        "extend" => extend = Some(a.value),
2079    }
2080
2081    match_elements! {ctx, attributes,
2082        "videorequirecapabilities" => if let Some(v) = parse_videorequirecapabilities(ctx, attributes) {
2083            children.push(VideoFormatChild::RequireCapabilities(v));
2084        },
2085        "videoformatproperties" => if let Some(v) = parse_videoformatproperties(ctx, attributes) {
2086            children.push(VideoFormatChild::FormatProperties(v));
2087        },
2088    }
2089
2090    Some(VideoFormat {
2091        comment,
2092        name,
2093        usage,
2094        extend,
2095        children,
2096    })
2097}
2098
2099fn parse_videoformatproperties<R: Read>(
2100    ctx: &mut ParseCtx<R>,
2101    attributes: Vec<XmlAttribute>,
2102) -> Option<VideoFormatProperties> {
2103    let mut comment = None;
2104    let mut struct_ = None;
2105
2106    match_attributes! {ctx, a in attributes,
2107        "comment" => comment = Some(a.value),
2108        "struct" => struct_ = Some(a.value),
2109    }
2110
2111    consume_current_element(ctx);
2112
2113    unwrap_attribute!(ctx, videoformatproperties, struct_, "struct");
2114
2115    Some(VideoFormatProperties { comment, struct_ })
2116}
2117
2118fn parse_videorequirecapabilities<R: Read>(
2119    ctx: &mut ParseCtx<R>,
2120    attributes: Vec<XmlAttribute>,
2121) -> Option<VideoRequireCapabilities> {
2122    let mut comment = None;
2123    let mut struct_ = None;
2124    let mut member = None;
2125    let mut value = None;
2126
2127    match_attributes! {ctx, a in attributes,
2128        "comment" => comment = Some(a.value),
2129        "struct" => struct_ = Some(a.value),
2130        "member" => member = Some(a.value),
2131        "value" => value = Some(a.value),
2132    }
2133
2134    consume_current_element(ctx);
2135
2136    unwrap_attribute!(ctx, videorequirecapabilities, struct_, "struct");
2137    unwrap_attribute!(ctx, videorequirecapabilities, member);
2138    unwrap_attribute!(ctx, videorequirecapabilities, value);
2139
2140    Some(VideoRequireCapabilities {
2141        comment,
2142        struct_,
2143        member,
2144        value,
2145    })
2146}
2147
2148fn parse_dynamicstates<R: Read>(
2149    ctx: &mut ParseCtx<R>,
2150    attributes: Vec<XmlAttribute>,
2151) -> RegistryChild {
2152    let mut children = Vec::new();
2153
2154    for a in attributes {
2155        ctx.errors.push(Error::UnexpectedAttribute {
2156            xpath: ctx.xpath.clone(),
2157            name: a.name.local_name.clone(),
2158        });
2159    }
2160
2161    match_elements! {ctx, attributes,
2162        "dynamicstate" => if let Some(v) = parse_dynamicstate(ctx, attributes) {
2163            children.push(v);
2164        },
2165    }
2166
2167    RegistryChild::DynamicStates(children)
2168}
2169
2170fn parse_dynamicstate<R: Read>(
2171    ctx: &mut ParseCtx<R>,
2172    attributes: Vec<XmlAttribute>,
2173) -> Option<DynamicState> {
2174    let mut name = None;
2175    let mut shaderstage = None;
2176    let mut pipelinesubstate = None;
2177    let mut requiresrasterization = None;
2178    let mut children = Vec::new();
2179
2180    match_attributes! {ctx, a in attributes,
2181        "name" => name = Some(a.value),
2182        "shaderstage" => shaderstage = Some(a.value),
2183        "pipelinesubstate" => pipelinesubstate = Some(a.value),
2184        "requiresrasterization" => requiresrasterization = Some(a.value),
2185    }
2186
2187    unwrap_attribute!(ctx, dynamicstate, name);
2188    unwrap_attribute!(ctx, dynamicstate, shaderstage);
2189
2190    match_elements! {ctx, attributes,
2191        "dynamicstatecmd" => if let Some(v) = parse_dynamicstatecmd(ctx, attributes) {
2192            children.push(DynamicStateChild::DynamicStateCmd(v));
2193        },
2194        "statecondition" => {
2195            children.push(DynamicStateChild::StateCondition(parse_statecondition(ctx, attributes)));
2196        },
2197        "enable" => if let Some(v) = parse_enable(ctx, attributes) {
2198            children.push(DynamicStateChild::Enable(v));
2199        },
2200    }
2201
2202    Some(DynamicState {
2203        name,
2204        shaderstage,
2205        pipelinesubstate,
2206        requiresrasterization,
2207        children,
2208    })
2209}
2210
2211fn parse_dynamicstatecmd<R: Read>(
2212    ctx: &mut ParseCtx<R>,
2213    attributes: Vec<XmlAttribute>,
2214) -> Option<DynamicStateCmd> {
2215    let mut name = None;
2216    let mut pipeline = None;
2217    let mut pipelineonly = None;
2218
2219    match_attributes! {ctx, a in attributes,
2220        "name" => name = Some(a.value),
2221        "pipeline" => pipeline = Some(a.value),
2222        "pipelineonly" => pipelineonly = Some(a.value),
2223    }
2224
2225    unwrap_attribute!(ctx, dynamicstatecmd, name);
2226    unwrap_attribute!(ctx, dynamicstatecmd, pipeline);
2227
2228    consume_current_element(ctx);
2229
2230    Some(DynamicStateCmd {
2231        name,
2232        pipeline,
2233        pipelineonly,
2234    })
2235}
2236
2237fn parse_statecondition<R: Read>(
2238    ctx: &mut ParseCtx<R>,
2239    attributes: Vec<XmlAttribute>,
2240) -> StateCondition {
2241    let mut state = None;
2242    let mut special = None;
2243
2244    match_attributes! {ctx, a in attributes,
2245        "state" => state = Some(a.value),
2246        "special" => special = Some(a.value),
2247    }
2248
2249    consume_current_element(ctx);
2250
2251    StateCondition { state, special }
2252}
2253
2254fn parse_name_with_type<R: Read>(
2255    ctx: &mut ParseCtx<R>,
2256    buffer: &mut String,
2257) -> Option<NameWithType> {
2258    let mut name = None;
2259    let mut type_name = None;
2260    let mut code = String::new();
2261    match_elements_combine_text! {ctx, code,
2262        "type" => {
2263            let text = parse_text_element(ctx);
2264            code.push_str(&text);
2265            type_name = Some(text);
2266        },
2267        "name" => {
2268            let text = parse_text_element(ctx);
2269            code.push_str(&text);
2270            name = Some(text);
2271        }
2272    }
2273    let name = if let Some(v) = name {
2274        v
2275    } else {
2276        ctx.errors.push(Error::MissingElement {
2277            xpath: ctx.xpath.clone(),
2278            name: String::from("name"),
2279        });
2280        return None;
2281    };
2282
2283    buffer.push_str(&code);
2284    Some(NameWithType {
2285        name,
2286        type_name,
2287        code,
2288    })
2289}
2290
2291fn parse_integer<R: Read>(ctx: &mut ParseCtx<R>, text: &str) -> Option<i64> {
2292    let parse_res = if text.starts_with("0x") {
2293        i64::from_str_radix(text.split_at(2).1, 16)
2294    } else {
2295        i64::from_str_radix(text, 10)
2296    };
2297
2298    if let Ok(v) = parse_res {
2299        Some(v)
2300    } else {
2301        ctx.errors.push(Error::SchemaViolation {
2302            xpath: ctx.xpath.clone(),
2303            desc: format!("Value '{}' is not valid base 10 or 16 integer.", text),
2304        });
2305        None
2306    }
2307}
2308
2309fn parse_int_attribute<I: FromStr<Err = std::num::ParseIntError>, R: Read>(
2310    ctx: &mut ParseCtx<R>,
2311    text: String,
2312    attribute_name: &str,
2313) -> Option<I> {
2314    match I::from_str(&text) {
2315        Ok(v) => Some(v),
2316        Err(e) => {
2317            ctx.errors.push(Error::ParseIntError {
2318                xpath: xpath_attribute(&ctx.xpath, attribute_name),
2319                text: text,
2320                error: e,
2321            });
2322            None
2323        }
2324    }
2325}
2326
2327fn consume_current_element<R: Read>(ctx: &mut ParseCtx<R>) {
2328    let mut depth = 1;
2329    while let Some(Ok(e)) = ctx.events.next() {
2330        match e {
2331            XmlEvent::StartElement { name, .. } => {
2332                ctx.push_element(name.local_name.as_str());
2333                depth += 1;
2334            }
2335            XmlEvent::EndElement { .. } => {
2336                depth -= 1;
2337                ctx.pop_element();
2338                if depth == 0 {
2339                    break;
2340                }
2341            }
2342            _ => (),
2343        }
2344    }
2345}
2346
2347fn parse_text_element<R: Read>(ctx: &mut ParseCtx<R>) -> String {
2348    let mut result = String::new();
2349    let mut depth = 1;
2350    while let Some(Ok(e)) = ctx.events.next() {
2351        match e {
2352            XmlEvent::StartElement { name, .. } => {
2353                ctx.push_element(name.local_name.as_str());
2354                depth += 1;
2355            }
2356            XmlEvent::Characters(text) => result.push_str(&text),
2357            XmlEvent::EndElement { .. } => {
2358                depth -= 1;
2359                ctx.pop_element();
2360                if depth == 0 {
2361                    break;
2362                }
2363            }
2364            _ => (),
2365        }
2366    }
2367    result
2368}