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