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