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