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