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