Skip to main content

vk_parse/
parse.rs

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