1// Copyright 2015 Brendan Zabarauskas and the gl-rs developers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15extern crate khronos_api;
16
17use std::borrow::Cow;
18use std::collections::btree_map::Entry;
19use std::collections::{BTreeMap, BTreeSet};
20use std::io;
21use xml::attribute::OwnedAttribute;
22use xml::reader::XmlEvent;
23use xml::EventReader as XmlEventReader;
24
25use registry::{Binding, Cmd, Enum, GlxOpcode, Group, Registry};
26use {Api, Fallbacks, Profile};
27
28pub fn from_xml<R: io::Read>(
29 src: R,
30 filter: &Filter,
31 require_feature: bool,
32) -> Registry {
33 XmlEventReaderimpl Iterator::new(source:src)
34 .into_iter()
35 .map(Result::unwrap)
36 .filter_map(ParseEvent::from_xml)
37 .parse(filter, require_feature)
38}
39
40#[derive(Debug, PartialEq, Eq)]
41struct Attribute {
42 key: String,
43 value: String,
44}
45
46impl Attribute {
47 fn new<Key, Value>(key: Key, value: Value) -> Attribute
48 where
49 Key: ToString,
50 Value: ToString,
51 {
52 Attribute {
53 key: key.to_string(),
54 value: value.to_string(),
55 }
56 }
57}
58
59impl From<OwnedAttribute> for Attribute {
60 fn from(attribute: OwnedAttribute) -> Attribute {
61 Attribute::new(key:attribute.name.local_name, attribute.value)
62 }
63}
64
65#[derive(Debug, PartialEq, Eq)]
66enum ParseEvent {
67 Start(String, Vec<Attribute>),
68 End(String),
69 Text(String),
70}
71
72impl ParseEvent {
73 fn from_xml(event: XmlEvent) -> Option<ParseEvent> {
74 match event {
75 XmlEvent::StartDocument { .. } => None,
76 XmlEvent::EndDocument => None,
77 XmlEvent::StartElement {
78 name: OwnedName, attributes: Vec, ..
79 } => {
80 let attributes: Vec = attributes.into_iter().map(Attribute::from).collect();
81 Some(ParseEvent::Start(name.local_name, attributes))
82 },
83 XmlEvent::EndElement { name: OwnedName } => Some(ParseEvent::End(name.local_name)),
84 XmlEvent::Characters(chars: String) => Some(ParseEvent::Text(chars)),
85 XmlEvent::ProcessingInstruction { .. } => None,
86 XmlEvent::CData(_) => None,
87 XmlEvent::Comment(_) => None,
88 XmlEvent::Whitespace(_) => None,
89 }
90 }
91}
92
93fn api_from_str(src: &str) -> Result<Option<Api>, ()> {
94 match src {
95 "gl" => Ok(Some(Api::Gl)),
96 "glx" => Ok(Some(Api::Glx)),
97 "wgl" => Ok(Some(Api::Wgl)),
98 "egl" => Ok(Some(Api::Egl)),
99 "glcore" => Ok(Some(Api::GlCore)),
100 "gles1" => Ok(Some(Api::Gles1)),
101 "gles2" => Ok(Some(Api::Gles2)),
102 "glsc2" => Ok(Some(Api::Glsc2)),
103 "disabled" => Ok(None),
104 _ => Err(()),
105 }
106}
107
108fn profile_from_str(src: &str) -> Result<Profile, ()> {
109 match src {
110 "core" => Ok(Profile::Core),
111 "compatibility" => Ok(Profile::Compatibility),
112 _ => Err(()),
113 }
114}
115
116fn underscore_numeric_prefix(src: &str) -> String {
117 match src.chars().next() {
118 Some(c: char) if c.is_numeric() => format!("_{}", src),
119 Some(_) | None => src.to_string(),
120 }
121}
122
123fn underscore_keyword(ident: String) -> String {
124 match ident.as_ref() {
125 "in" => "in_".to_string(),
126 "ref" => "ref_".to_string(),
127 "type" => "type_".to_string(),
128 _ => ident,
129 }
130}
131
132fn trim_str<'a>(s: &'a str, trim: &str) -> &'a str {
133 if s.starts_with(trim) {
134 &s[trim.len()..]
135 } else {
136 s
137 }
138}
139
140fn trim_enum_prefix(ident: &str, api: Api) -> String {
141 let ident: &str = match api {
142 Api::Gl | Api::GlCore | Api::Gles1 | Api::Gles2 | Api::Glsc2 => trim_str(s:ident, trim:"GL_"),
143 Api::Glx => trim_str(s:ident, trim:"GLX_"),
144 Api::Wgl => trim_str(s:ident, trim:"WGL_"),
145 Api::Egl => trim_str(s:ident, trim:"EGL_"),
146 };
147 underscore_numeric_prefix(src:ident)
148}
149
150fn make_enum(ident: String, ty: Option<String>, value: String, alias: Option<String>) -> Enum {
151 let (ty, value, cast) = {
152 if value.starts_with("((") && value.ends_with(")") {
153 // Some enums have a value of the form `'((' type ')' expr ')'`.
154
155 // nothing to see here....
156 // just brute forcing some paren matching... (ノ ◕ ◡ ◕)ノ *:・゚✧
157 let working = &value[2..value.len() - 1];
158 if let Some((i, _)) = working.match_indices(")").next() {
159 let ty = working[..i].to_string();
160 let value = working[i + 1..].to_string();
161
162 (Cow::Owned(ty), value, true)
163 } else {
164 panic!("Unexpected value format: {}", value)
165 }
166 } else {
167 let ty = match ty {
168 Some(ref ty) if ty == "u" => "GLuint",
169 Some(ref ty) if ty == "ull" => "GLuint64",
170 Some(ty) => panic!("Unhandled enum type: {}", ty),
171 None if value.starts_with("\"") => "&'static str",
172 None if ident == "TRUE" || ident == "FALSE" => "GLboolean",
173 None => "GLenum",
174 };
175 (Cow::Borrowed(ty), value, false)
176 }
177 };
178
179 Enum {
180 ident: ident,
181 value: value,
182 cast: cast,
183 alias: alias,
184 ty: ty,
185 }
186}
187
188fn make_egl_enum(ident: String, ty: Option<String>, value: String, alias: Option<String>) -> Enum {
189 let (ty, value, cast) = {
190 if value.starts_with("EGL_CAST(") && value.ends_with(")") {
191 // Handling "SpecialNumbers" in the egl.xml file
192 // The values for these enums has the form `'EGL_CAST(' type ',' expr ')'`.
193 let working = &value[9..value.len() - 1];
194 if let Some((i, _)) = working.match_indices(",").next() {
195 let ty = working[..i].to_string();
196 let value = working[i + 1..].to_string();
197
198 (Cow::Owned(ty), value, true)
199 } else {
200 panic!("Unexpected value format: {}", value)
201 }
202 } else {
203 match value.chars().next() {
204 Some('-') | Some('0'..='9') => (),
205 _ => panic!("Unexpected value format: {}", value),
206 }
207
208 let ty = match ty {
209 Some(ref ty) if ty == "ull" => "EGLuint64KHR",
210 Some(ty) => panic!("Unhandled enum type: {}", ty),
211 None if value.starts_with('-') => "EGLint",
212 None if ident == "TRUE" || ident == "FALSE" => "EGLBoolean",
213 None => "EGLenum",
214 };
215 (Cow::Borrowed(ty), value, false)
216 }
217 };
218
219 Enum {
220 ident: ident,
221 value: value,
222 cast: cast,
223 alias: alias,
224 ty: ty,
225 }
226}
227
228fn trim_cmd_prefix(ident: &str, api: Api) -> &str {
229 match api {
230 Api::Gl | Api::GlCore | Api::Gles1 | Api::Gles2 | Api::Glsc2 => trim_str(s:ident, trim:"gl"),
231 Api::Glx => trim_str(s:ident, trim:"glX"),
232 Api::Wgl => trim_str(s:ident, trim:"wgl"),
233 Api::Egl => trim_str(s:ident, trim:"egl"),
234 }
235}
236
237fn merge_map(a: &mut BTreeMap<String, Vec<String>>, b: BTreeMap<String, Vec<String>>) {
238 for (k: String, v: Vec) in b {
239 match a.entry(key:k) {
240 Entry::Occupied(mut ent: OccupiedEntry<'_, String, …>) => {
241 ent.get_mut().extend(iter:v);
242 },
243 Entry::Vacant(ent: VacantEntry<'_, String, Vec<…>>) => {
244 ent.insert(v);
245 },
246 }
247 }
248}
249
250#[derive(Clone)]
251struct Feature {
252 pub api: Api,
253 pub name: String,
254 pub number: String,
255 pub requires: Vec<Require>,
256 pub removes: Vec<Remove>,
257}
258
259#[derive(Clone)]
260struct Require {
261 /// A reference to the earlier types, by name
262 pub enums: Vec<String>,
263 /// A reference to the earlier types, by name
264 pub commands: Vec<String>,
265}
266
267#[derive(Clone)]
268struct Remove {
269 // always Core, for now
270 pub profile: Profile,
271 /// A reference to the earlier types, by name
272 pub enums: Vec<String>,
273 /// A reference to the earlier types, by name
274 pub commands: Vec<String>,
275}
276
277#[derive(Clone)]
278struct Extension {
279 pub name: String,
280 /// which apis this extension is defined for (see Feature.api)
281 pub supported: Vec<Api>,
282 pub requires: Vec<Require>,
283}
284
285pub struct Filter {
286 pub api: Api,
287 pub fallbacks: Fallbacks,
288 pub extensions: BTreeSet<String>,
289 pub profile: Profile,
290 pub version: String,
291}
292
293trait Parse: Sized + Iterator<Item = ParseEvent> {
294 fn parse(mut self, filter: &Filter, require_feature: bool) -> Registry {
295 self.consume_start_element("registry");
296
297 let mut enums = Vec::new();
298 let mut cmds = Vec::new();
299 let mut features = Vec::new();
300 let mut extensions = Vec::new();
301 let mut aliases = BTreeMap::new();
302 let mut groups: BTreeMap<String, Group> = BTreeMap::new();
303
304 while let Some(event) = self.next() {
305 match event {
306 // ignores
307 ParseEvent::Text(_) => (),
308 ParseEvent::Start(ref name, _) if name == "comment" => self.skip_to_end("comment"),
309 ParseEvent::Start(ref name, _) if name == "types" => self.skip_to_end("types"),
310
311 // add group namespace
312 ParseEvent::Start(ref name, _) if name == "groups" => {
313 groups.extend(self.consume_groups(filter.api));
314 },
315
316 // add enum namespace
317 ParseEvent::Start(ref name, ref attributes) if name == "enums" => {
318 enums.extend(self.consume_enums(filter.api));
319 let enums_group = get_attribute(&attributes, "group");
320 let enums_type = get_attribute(&attributes, "type");
321 if let Some(group) = enums_group.and_then(|name| groups.get_mut(&name)) {
322 group.enums_type = enums_type;
323 }
324 },
325
326 // add command namespace
327 ParseEvent::Start(ref name, _) if name == "commands" => {
328 let (new_cmds, new_aliases) = self.consume_cmds(filter.api);
329 cmds.extend(new_cmds);
330 merge_map(&mut aliases, new_aliases);
331 },
332
333 ParseEvent::Start(ref name, ref attributes) if name == "feature" => {
334 debug!("Parsing feature: {:?}", attributes);
335 features.push(Feature::convert(&mut self, &attributes));
336 },
337
338 ParseEvent::Start(ref name, _) if name == "extensions" => loop {
339 match self.next().unwrap() {
340 ParseEvent::Start(ref name, ref attributes) if name == "extension" => {
341 extensions.push(Extension::convert(&mut self, &attributes));
342 },
343 ParseEvent::End(ref name) if name == "extensions" => break,
344 event => panic!("Unexpected message {:?}", event),
345 }
346 },
347
348 // finished building the registry
349 ParseEvent::End(ref name) if name == "registry" => break,
350
351 // error handling
352 event => panic!("Expected </registry>, found: {:?}", event),
353 }
354 }
355
356 let mut desired_enums = BTreeSet::new();
357 let mut desired_cmds = BTreeSet::new();
358
359 // find the features we want
360 let mut found_feature = false;
361 for feature in &features {
362 // XXX: verify that the string comparison with <= actually works as desired
363 if feature.api == filter.api && feature.number <= filter.version {
364 for require in &feature.requires {
365 desired_enums.extend(require.enums.iter().map(|x| x.clone()));
366 desired_cmds.extend(require.commands.iter().map(|x| x.clone()));
367 }
368
369 for remove in &feature.removes {
370 if remove.profile == filter.profile {
371 for enm in &remove.enums {
372 debug!("Removing {}", enm);
373 desired_enums.remove(enm);
374 }
375 for cmd in &remove.commands {
376 debug!("Removing {}", cmd);
377 desired_cmds.remove(cmd);
378 }
379 }
380 }
381 }
382 if feature.number == filter.version {
383 found_feature = true;
384 }
385 }
386
387 if !found_feature && require_feature {
388 panic!("Did not find version {} in the registry", filter.version);
389 }
390
391 for extension in &extensions {
392 if filter.extensions.contains(&extension.name) {
393 if !extension.supported.contains(&filter.api) {
394 panic!(
395 "Requested {}, which doesn't support the {} API",
396 extension.name, filter.api
397 );
398 }
399 for require in &extension.requires {
400 desired_enums.extend(require.enums.iter().map(|x| x.clone()));
401 desired_cmds.extend(require.commands.iter().map(|x| x.clone()));
402 }
403 }
404 }
405
406 let is_desired_enum = |e: &Enum| {
407 desired_enums.contains(&("GL_".to_string() + &e.ident))
408 || desired_enums.contains(&("WGL_".to_string() + &e.ident))
409 || desired_enums.contains(&("GLX_".to_string() + &e.ident))
410 || desired_enums.contains(&("EGL_".to_string() + &e.ident))
411 };
412
413 let is_desired_cmd = |c: &Cmd| {
414 desired_cmds.contains(&("gl".to_string() + &c.proto.ident))
415 || desired_cmds.contains(&("wgl".to_string() + &c.proto.ident))
416 || desired_cmds.contains(&("glX".to_string() + &c.proto.ident))
417 || desired_cmds.contains(&("egl".to_string() + &c.proto.ident))
418 };
419
420 Registry {
421 api: filter.api,
422 enums: enums.into_iter().filter(is_desired_enum).collect(),
423 cmds: cmds.into_iter().filter(is_desired_cmd).collect(),
424 aliases: if filter.fallbacks == Fallbacks::None {
425 BTreeMap::new()
426 } else {
427 aliases
428 },
429 groups,
430 }
431 }
432
433 fn consume_characters(&mut self) -> String {
434 match self.next().unwrap() {
435 ParseEvent::Text(ch) => ch,
436 event => panic!("Expected characters, found: {:?}", event),
437 }
438 }
439
440 fn consume_start_element(&mut self, expected_name: &str) -> Vec<Attribute> {
441 match self.next().unwrap() {
442 ParseEvent::Start(name, attributes) => {
443 if expected_name == name {
444 attributes
445 } else {
446 panic!("Expected <{}>, found: <{}>", expected_name, name)
447 }
448 },
449 event => panic!("Expected <{}>, found: {:?}", expected_name, event),
450 }
451 }
452
453 fn consume_end_element(&mut self, expected_name: &str) {
454 match self.next().unwrap() {
455 ParseEvent::End(ref name) if expected_name == name => (),
456 event => panic!("Expected </{}>, found: {:?}", expected_name, event),
457 }
458 }
459
460 fn skip_to_end(&mut self, expected_name: &str) {
461 loop {
462 match self.next().unwrap() {
463 ParseEvent::End(ref name) if expected_name == name => break,
464 _ => {},
465 }
466 }
467 }
468
469 fn consume_two<'a, T: FromXml, U: FromXml>(
470 &mut self,
471 one: &'a str,
472 two: &'a str,
473 end: &'a str,
474 ) -> (Vec<T>, Vec<U>) {
475 debug!("consume_two: looking for {} and {} until {}", one, two, end);
476
477 let mut ones = Vec::new();
478 let mut twos = Vec::new();
479
480 loop {
481 match self.next().unwrap() {
482 ParseEvent::Start(ref name, ref attributes) => {
483 debug!("Found start element <{:?} {:?}>", name, attributes);
484 debug!("one and two are {} and {}", one, two);
485
486 let n = name.clone();
487
488 if one == n {
489 ones.push(FromXml::convert(self, &attributes));
490 } else if "type" == n {
491 // XXX: GL1.1 contains types, which we never care about anyway.
492 // Make sure consume_two doesn't get used for things which *do*
493 // care about type.
494 warn!("Ignoring type!");
495 continue;
496 } else if two == n {
497 twos.push(FromXml::convert(self, &attributes));
498 } else {
499 panic!("Unexpected element: <{:?} {:?}>", n, &attributes);
500 }
501 },
502 ParseEvent::End(ref name) => {
503 debug!("Found end element </{:?}>", name);
504
505 if one == name || two == name {
506 continue;
507 } else if "type" == name {
508 // XXX: GL1.1 contains types, which we never care about anyway.
509 // Make sure consume_two doesn't get used for things which *do*
510 // care about type.
511 warn!("Ignoring type!");
512 continue;
513 } else if end == name {
514 return (ones, twos);
515 } else {
516 panic!("Unexpected end element {:?}", name);
517 }
518 },
519 event => panic!("Unexpected message {:?}", event),
520 }
521 }
522 }
523
524 fn consume_enums(&mut self, api: Api) -> Vec<Enum> {
525 let mut enums = Vec::new();
526 loop {
527 match self.next().unwrap() {
528 // ignores
529 ParseEvent::Text(_) => {},
530 ParseEvent::Start(ref name, _) if name == "unused" => self.skip_to_end("unused"),
531
532 // add enum definition
533 ParseEvent::Start(ref name, ref attributes) if name == "enum" => {
534 enums.push(self.consume_enum(api, attributes));
535 },
536
537 // finished building the namespace
538 ParseEvent::End(ref name) if name == "enums" => break,
539 // error handling
540 event => panic!("Expected </enums>, found: {:?}", event),
541 }
542 }
543 enums
544 }
545
546 fn consume_enum(&mut self, api: Api, attributes: &[Attribute]) -> Enum {
547 let ident = trim_enum_prefix(&get_attribute(&attributes, "name").unwrap(), api).to_string();
548 let value = get_attribute(&attributes, "value").unwrap();
549 let alias = get_attribute(&attributes, "alias");
550 let ty = get_attribute(&attributes, "type");
551 self.consume_end_element("enum");
552
553 match api {
554 Api::Egl => make_egl_enum(ident, ty, value, alias),
555 _ => make_enum(ident, ty, value, alias),
556 }
557 }
558
559 fn consume_groups(&mut self, api: Api) -> BTreeMap<String, Group> {
560 let mut groups = BTreeMap::new();
561 loop {
562 match self.next().unwrap() {
563 ParseEvent::Start(ref name, ref attributes) if name == "group" => {
564 let ident = get_attribute(&attributes, "name").unwrap();
565 let group = Group {
566 ident: ident.clone(),
567 enums_type: None,
568 enums: self.consume_group_enums(api)
569 };
570 groups.insert(ident, group);
571 },
572 ParseEvent::End(ref name) if name == "groups" => break,
573 event => panic!("Expected </groups>, found: {:?}", event),
574 }
575 }
576 groups
577 }
578
579 fn consume_group_enums(&mut self, api: Api) -> Vec<String> {
580 let mut enums = Vec::new();
581 loop {
582 match self.next().unwrap() {
583 ParseEvent::Start(ref name, ref attributes) if name == "enum" => {
584 let enum_name = get_attribute(&attributes, "name");
585 enums.push(trim_enum_prefix(&enum_name.unwrap(), api));
586 self.consume_end_element("enum");
587 },
588 ParseEvent::End(ref name) if name == "group" => break,
589 event => panic!("Expected </group>, found: {:?}", event),
590 }
591 }
592 enums
593 }
594
595 fn consume_cmds(&mut self, api: Api) -> (Vec<Cmd>, BTreeMap<String, Vec<String>>) {
596 let mut cmds = Vec::new();
597 let mut aliases: BTreeMap<String, Vec<String>> = BTreeMap::new();
598 loop {
599 match self.next().unwrap() {
600 // add command definition
601 ParseEvent::Start(ref name, _) if name == "command" => {
602 let new = self.consume_cmd(api);
603 if let Some(ref v) = new.alias {
604 match aliases.entry(v.clone()) {
605 Entry::Occupied(mut ent) => {
606 ent.get_mut().push(new.proto.ident.clone());
607 },
608 Entry::Vacant(ent) => {
609 ent.insert(vec![new.proto.ident.clone()]);
610 },
611 }
612 }
613 cmds.push(new);
614 },
615 // finished building the namespace
616 ParseEvent::End(ref name) if name == "commands" => break,
617 // error handling
618 event => panic!("Expected </commands>, found: {:?}", event),
619 }
620 }
621 (cmds, aliases)
622 }
623
624 fn consume_cmd(&mut self, api: Api) -> Cmd {
625 // consume command prototype
626 self.consume_start_element("proto");
627 let mut proto = self.consume_binding("proto", &[]);
628 proto.ident = trim_cmd_prefix(&proto.ident, api).to_string();
629
630 let mut params = Vec::new();
631 let mut alias = None;
632 let mut vecequiv = None;
633 let mut glx = None;
634 loop {
635 match self.next().unwrap() {
636 ParseEvent::Start(ref name, ref attributes) if name == "param" => {
637 params.push(self.consume_binding("param", attributes));
638 },
639 ParseEvent::Start(ref name, ref attributes) if name == "alias" => {
640 alias = get_attribute(&attributes, "name");
641 alias = alias.map(|t| trim_cmd_prefix(&t, api).to_string());
642 self.consume_end_element("alias");
643 },
644 ParseEvent::Start(ref name, ref attributes) if name == "vecequiv" => {
645 vecequiv = get_attribute(&attributes, "vecequiv");
646 self.consume_end_element("vecequiv");
647 },
648 ParseEvent::Start(ref name, ref attributes) if name == "glx" => {
649 glx = Some(GlxOpcode {
650 opcode: get_attribute(&attributes, "opcode").unwrap(),
651 name: get_attribute(&attributes, "name"),
652 });
653 self.consume_end_element("glx");
654 },
655 ParseEvent::End(ref name) if name == "command" => break,
656 event => panic!("Expected </command>, found: {:?}", event),
657 }
658 }
659
660 Cmd {
661 proto: proto,
662 params: params,
663 alias: alias,
664 vecequiv: vecequiv,
665 glx: glx,
666 }
667 }
668
669 fn consume_binding(&mut self, outside_tag: &str, attributes: &[Attribute]) -> Binding {
670 // consume type
671 let mut ty = String::new();
672 loop {
673 match self.next().unwrap() {
674 ParseEvent::Text(text) => ty.push_str(&text),
675 ParseEvent::Start(ref name, _) if name == "ptype" => (),
676 ParseEvent::End(ref name) if name == "ptype" => (),
677 ParseEvent::Start(ref name, _) if name == "name" => break,
678 event => panic!("Expected binding, found: {:?}", event),
679 }
680 }
681
682 // consume identifier
683 let ident = underscore_keyword(self.consume_characters());
684 self.consume_end_element("name");
685
686 // consume the type suffix
687 loop {
688 match self.next().unwrap() {
689 ParseEvent::Text(text) => ty.push_str(&text),
690 ParseEvent::End(ref name) if name == outside_tag => break,
691 event => panic!("Expected binding, found: {:?}", event),
692 }
693 }
694
695 Binding {
696 ident: ident,
697 ty: to_rust_ty(ty),
698 group: get_attribute(&attributes, "group"),
699 }
700 }
701}
702
703impl<T> Parse for T where T: Sized + Iterator<Item = ParseEvent> {}
704
705fn get_attribute(attribs: &[Attribute], key: &str) -> Option<String> {
706 attribsOption<&Attribute>
707 .iter()
708 .find(|attrib: &&Attribute| attrib.key == key)
709 .map(|attrib: &Attribute| attrib.value.clone())
710}
711
712trait FromXml {
713 fn convert<P: Parse>(parser: &mut P, a: &[Attribute]) -> Self;
714}
715
716impl FromXml for Require {
717 fn convert<P: Parse>(parser: &mut P, _: &[Attribute]) -> Require {
718 debug!("Doing a FromXml on Require");
719 let (enums: Vec, commands: Vec) = parser.consume_two(one:"enum", two:"command", end:"require");
720 Require {
721 enums: enums,
722 commands: commands,
723 }
724 }
725}
726
727impl FromXml for Remove {
728 fn convert<P: Parse>(parser: &mut P, a: &[Attribute]) -> Remove {
729 debug!("Doing a FromXml on Remove");
730 let profile: String = get_attribute(attribs:a, key:"profile").unwrap();
731 let profile: Profile = profile_from_str(&profile).unwrap();
732 let (enums: Vec, commands: Vec) = parser.consume_two(one:"enum", two:"command", end:"remove");
733
734 Remove {
735 profile: profile,
736 enums: enums,
737 commands: commands,
738 }
739 }
740}
741
742impl FromXml for Feature {
743 fn convert<P: Parse>(parser: &mut P, a: &[Attribute]) -> Feature {
744 debug!("Doing a FromXml on Feature");
745 let api: String = get_attribute(attribs:a, key:"api").unwrap();
746 let api: Api = api_from_str(&api).unwrap().unwrap();
747 let name: String = get_attribute(attribs:a, key:"name").unwrap();
748 let number: String = get_attribute(attribs:a, key:"number").unwrap();
749
750 debug!("Found api = {}, name = {}, number = {}", api, name, number);
751
752 let (require: Vec, remove: Vec) = parser.consume_two(one:"require", two:"remove", end:"feature");
753
754 Feature {
755 api: api,
756 name: name,
757 number: number,
758 requires: require,
759 removes: remove,
760 }
761 }
762}
763
764impl FromXml for Extension {
765 fn convert<P: Parse>(parser: &mut P, a: &[Attribute]) -> Extension {
766 debug!("Doing a FromXml on Extension");
767 let name = get_attribute(a, "name").unwrap();
768 let supported = get_attribute(a, "supported")
769 .unwrap()
770 .split('|')
771 .filter_map(|api| {
772 api_from_str(api).unwrap_or_else(|()| panic!("unsupported API `{}`", api))
773 })
774 .collect::<Vec<_>>();
775 let mut require = Vec::new();
776 loop {
777 match parser.next().unwrap() {
778 ParseEvent::Start(ref name, ref attributes) if name == "require" => {
779 require.push(FromXml::convert(parser, &attributes));
780 },
781 ParseEvent::End(ref name) if name == "extension" => break,
782 event => panic!("Unexpected message {:?}", event),
783 }
784 }
785
786 Extension {
787 name: name,
788 supported: supported,
789 requires: require,
790 }
791 }
792}
793
794impl FromXml for String {
795 fn convert<P: Parse>(_: &mut P, a: &[Attribute]) -> String {
796 get_attribute(attribs:a, key:"name").unwrap()
797 }
798}
799
800/// Converts a C style type definition to the Rust equivalent
801pub fn to_rust_ty<T: AsRef<str>>(ty: T) -> Cow<'static, str> {
802 let ty = match ty.as_ref().trim() {
803 // gl.xml types
804 "GLDEBUGPROC" => "types::GLDEBUGPROC",
805 "GLDEBUGPROCAMD" => "types::GLDEBUGPROCAMD",
806 "GLDEBUGPROCARB" => "types::GLDEBUGPROCARB",
807 "GLDEBUGPROCKHR" => "types::GLDEBUGPROCKHR",
808 "GLbitfield" => "types::GLbitfield",
809 "GLboolean" => "types::GLboolean",
810 "GLbyte" => "types::GLbyte",
811 "GLclampd" => "types::GLclampd",
812 "GLclampf" => "types::GLclampf",
813 "GLclampx" => "types::GLclampx",
814 "GLdouble" => "types::GLdouble",
815 "GLeglImageOES" => "types::GLeglImageOES",
816 "GLenum" => "types::GLenum",
817 "GLfixed" => "types::GLfixed",
818 "GLfloat" => "types::GLfloat",
819 "GLhalfNV" => "types::GLhalfNV",
820 "GLhandleARB" => "types::GLhandleARB",
821 "GLint" => "types::GLint",
822 "GLint64" => "types::GLint64",
823 "GLint64EXT" => "types::GLint64EXT",
824 "GLintptr" => "types::GLintptr",
825 "GLintptrARB" => "types::GLintptrARB",
826 "GLshort" => "types::GLshort",
827 "GLsizei" => "types::GLsizei",
828 "GLsizeiptr" => "types::GLsizeiptr",
829 "GLsizeiptrARB" => "types::GLsizeiptrARB",
830 "GLsync" => "types::GLsync",
831 "GLubyte" => "types::GLubyte",
832 "GLuint" => "types::GLuint",
833 "GLuint64" => "types::GLuint64",
834 "GLuint64EXT" => "types::GLuint64EXT",
835 "GLushort" => "types::GLushort",
836 "GLvdpauSurfaceNV" => "types::GLvdpauSurfaceNV",
837 "void" => "()",
838 "GLboolean *" => "*mut types::GLboolean",
839 "GLchar *" => "*mut types::GLchar",
840 "const GLchar*" => "*const types::GLchar",
841 "GLcharARB *" => "*mut types::GLcharARB",
842 "GLdouble *" => "*mut types::GLdouble",
843 "GLenum *" => "*mut types::GLenum",
844 "GLfixed *" => "*mut types::GLfixed",
845 "GLfloat *" => "*mut types::GLfloat",
846 "GLhandleARB *" => "*mut types::GLhandleARB",
847 "GLint *" => "*mut types::GLint",
848 "GLint64 *" => "*mut types::GLint64",
849 "GLint64EXT *" => "*mut types::GLint64EXT",
850 "GLsizei *" => "*mut types::GLsizei",
851 "GLubyte *" => "*mut types::GLubyte",
852 "GLuint *" => "*mut types::GLuint",
853 "GLuint [2]" => "*mut [types::GLuint; 2]",
854 "GLuint64 *" => "*mut types::GLuint64",
855 "GLuint64EXT *" => "*mut types::GLuint64EXT",
856 "GLushort *" => "*mut types::GLushort",
857 "GLvoid *" => "*mut types::GLvoid",
858 "GLvoid **" => "*const *mut types::GLvoid",
859 "void *" => "*mut __gl_imports::raw::c_void",
860 "void **" => "*const *mut __gl_imports::raw::c_void",
861 "const GLboolean *" => "*const types::GLboolean",
862 "const GLbyte *" => "*const types::GLbyte",
863 "const GLchar *" => "*const types::GLchar",
864 "const GLcharARB *" => "*const types::GLcharARB",
865 "const GLclampf *" => "*const types::GLclampf",
866 "const GLdouble *" => "*const types::GLdouble",
867 "const GLenum *" => "*const types::GLenum",
868 "const GLfixed *" => "*const types::GLfixed",
869 "const GLfloat" => "types::GLfloat",
870 "const GLfloat *" => "*const types::GLfloat",
871 "const GLhalfNV *" => "*const types::GLhalfNV",
872 "const GLint *" => "*const types::GLint",
873 "const GLint*" => "*const types::GLint",
874 "const GLint64 *" => "*const types::GLint64",
875 "const GLint64EXT *" => "*const types::GLint64EXT",
876 "const GLintptr *" => "*const types::GLintptr",
877 "const GLshort *" => "*const types::GLshort",
878 "const GLsizei*" |
879 "const GLsizei *" => "*const types::GLsizei",
880 "const GLsizeiptr *" => "*const types::GLsizeiptr",
881 "const GLubyte *" => "*const types::GLubyte",
882 "const GLuint *" => "*const types::GLuint",
883 "const GLuint64 *" => "*const types::GLuint64",
884 "const GLuint64EXT *" => "*const types::GLuint64EXT",
885 "const GLushort *" => "*const types::GLushort",
886 "const GLvdpauSurfaceNV *" => "*const types::GLvdpauSurfaceNV",
887 "const GLvoid *" => "*const types::GLvoid",
888 "const void*" |
889 "const void *" => "*const __gl_imports::raw::c_void",
890 "const void **" => "*const *const __gl_imports::raw::c_void",
891 "const void *const*" => "*const *const __gl_imports::raw::c_void",
892 "const GLboolean **" => "*const *const types::GLboolean",
893 "const GLchar **" => "*const *const types::GLchar",
894 "const GLcharARB **" => "*const *const types::GLcharARB",
895 "const GLvoid **" => "*const *const types::GLvoid",
896 "const GLchar *const*" => "*const *const types::GLchar",
897 "const GLvoid *const*" => "*const *const types::GLvoid",
898 "struct _cl_context *" => "*const types::_cl_context",
899 "struct _cl_event *" => "*const types::_cl_event",
900 "GLuint[2]" => "[Gluint; 2]",
901
902 // glx.xml types
903 "Bool" => "types::Bool",
904 "Colormap" => "types::Colormap",
905 "DMbuffer" => "types::DMbuffer",
906 "Font" => "types::Font",
907 "GLXContext" => "types::GLXContext",
908 "GLXContextID" => "types::GLXContextID",
909 "GLXDrawable" => "types::GLXDrawable",
910 "GLXFBConfig" => "types::GLXFBConfig",
911 "GLXFBConfigSGIX" => "types::GLXFBConfigSGIX",
912 "GLXPbuffer" => "types::GLXPbuffer",
913 "GLXPbufferSGIX" => "types::GLXPbufferSGIX",
914 "GLXPixmap" => "types::GLXPixmap",
915 "GLXVideoCaptureDeviceNV" => "types::GLXVideoCaptureDeviceNV",
916 "GLXVideoDeviceNV" => "types::GLXVideoDeviceNV",
917 "GLXVideoSourceSGIX" => "types::GLXVideoSourceSGIX",
918 "GLXWindow" => "types::GLXWindow",
919 // "GLboolean" => "types::GLboolean",
920 // "GLenum" => "types::GLenum",
921 // "GLint" => "types::GLint",
922 // "GLsizei" => "types::GLsizei",
923 // "GLuint" => "types::GLuint",
924 "Pixmap" => "types::Pixmap",
925 "Status" => "types::Status",
926 "VLNode" => "types::VLNode",
927 "VLPath" => "types::VLPath",
928 "VLServer" => "types::VLServer",
929 "Window" => "types::Window",
930 "__GLXextFuncPtr" => "types::__GLXextFuncPtr",
931 "const GLXContext" => "const types::GLXContext",
932 "float" => "__gl_imports::raw::c_float",
933 "int" => "__gl_imports::raw::c_int",
934 "int64_t" => "i64",
935 "unsigned int" => "__gl_imports::raw::c_uint",
936 "unsigned long" => "__gl_imports::raw::c_ulong",
937 // "void " => "()",
938 "DMparams *" => "*mut types::DMparams",
939 "Display *" => "*mut types::Display",
940 "GLXFBConfig *" => "*mut types::GLXFBConfig",
941 "GLXFBConfigSGIX *" => "*mut types::GLXFBConfigSGIX",
942 "GLXHyperpipeConfigSGIX *" => "*mut types::GLXHyperpipeConfigSGIX",
943 "GLXHyperpipeNetworkSGIX *" => "*mut types::GLXHyperpipeNetworkSGIX",
944 "GLXVideoCaptureDeviceNV *" => "*mut types::GLXVideoCaptureDeviceNV",
945 "GLXVideoDeviceNV *" => "*mut types::GLXVideoDeviceNV",
946 // "GLuint *" => "*mut types::GLuint",
947 "XVisualInfo *" => "*mut types::XVisualInfo",
948 // "const GLubyte *" => "*GLubyte",
949 "const char *" => "*const __gl_imports::raw::c_char",
950 "const int *" => "*const __gl_imports::raw::c_int",
951 // "const void *" => "*const __gl_imports::raw::c_void",
952 "int *" => "*mut __gl_imports::raw::c_int",
953 "int32_t *" => "*mut i32",
954 "int64_t *" => "*mut i64",
955 "long *" => "*mut __gl_imports::raw::c_long",
956 "unsigned int *" => "*mut __gl_imports::raw::c_uint",
957 "unsigned long *" => "*mut __gl_imports::raw::c_ulong",
958 // "void *" => "*mut __gl_imports::raw::c_void",
959
960 // wgl.xml types
961 "BOOL" => "types::BOOL",
962 "DWORD" => "types::DWORD",
963 "FLOAT" => "types::FLOAT",
964 // "GLbitfield" => "types::GLbitfield",
965 // "GLboolean" => "types::GLboolean",
966 // "GLenum" => "types::GLenum",
967 // "GLfloat" => "types::GLfloat",
968 // "GLint" => "types::GLint",
969 // "GLsizei" => "types::GLsizei",
970 // "GLuint" => "types::GLuint",
971 // "GLushort" => "types::GLushort",
972 "HANDLE" => "types::HANDLE",
973 "HDC" => "types::HDC",
974 "HENHMETAFILE" => "types::HENHMETAFILE",
975 "HGLRC" => "types::HGLRC",
976 "HGPUNV" => "types::HGPUNV",
977 "HPBUFFERARB" => "types::HPBUFFERARB",
978 "HPBUFFEREXT" => "types::HPBUFFEREXT",
979 "HPVIDEODEV" => "types::HPVIDEODEV",
980 "HVIDEOINPUTDEVICENV" => "types::HVIDEOINPUTDEVICENV",
981 "HVIDEOOUTPUTDEVICENV" => "types::HVIDEOOUTPUTDEVICENV",
982 "INT" => "types::INT",
983 "INT64" => "types::INT64",
984 "LPCSTR" => "types::LPCSTR",
985 "LPGLYPHMETRICSFLOAT" => "types::LPGLYPHMETRICSFLOAT",
986 "LPVOID" => "types::LPVOID",
987 "PGPU_DEVICE" => "types::PGPU_DEVICE",
988 "PROC" => "types::PROC",
989 "UINT" => "types::UINT",
990 "VOID" => "types::VOID",
991 // "int " => "__gl_imports::raw::c_int",
992 // "unsigned int " => "__gl_imports::raw::c_uint",
993 // "void " => "()",
994 "BOOL *" => "*mut types::BOOL",
995 "DWORD *" => "*mut types::DWORD",
996 "FLOAT *" => "*mut types::FLOAT",
997 // "GLuint *" => "*mut types::GLuint",
998 "HANDLE *" => "*mut types::HANDLE",
999 "HGPUNV *" => "*mut types::HGPUNV",
1000 "HPVIDEODEV *" => "*mut types::HPVIDEODEV",
1001 "HVIDEOINPUTDEVICENV *" => "*mut types::HVIDEOINPUTDEVICENV",
1002 "HVIDEOOUTPUTDEVICENV *" => "*mut types::HVIDEOOUTPUTDEVICENV",
1003 "INT32 *" => "*mut types::INT32",
1004 "INT64 *" => "*mut types::INT64",
1005 "UINT *" => "*mut types::UINT",
1006 "USHORT *" => "*mut types::USHORT",
1007 "const COLORREF *" => "*const types::COLORREF",
1008 "const DWORD *" => "*const types::DWORD",
1009 "const FLOAT *" => "*const types::FLOAT",
1010 // "const GLushort *" => "*const types::GLushort",
1011 "const HANDLE *" => "*const types::HANDLE",
1012 "const HGPUNV *" => "*const types::HGPUNV",
1013 "const LAYERPLANEDESCRIPTOR *" => "*const types::LAYERPLANEDESCRIPTOR",
1014 "const LPVOID *" => "*const types::LPVOID",
1015 "const PIXELFORMATDESCRIPTOR *" => "*const types::IXELFORMATDESCRIPTOR",
1016 "const USHORT *" => "*const types::USHORT",
1017 // "const char *" => "*const __gl_imports::raw::c_char",
1018 // "const int *" => "*const __gl_imports::raw::c_int",
1019 "float *" => "*mut __gl_imports::raw::c_float",
1020 // "int *" => "*mut __gl_imports::raw::c_int",
1021 // "unsigned long *" => "*mut __gl_imports::raw::c_ulong",
1022 // "void *" => "*mut __gl_imports::raw::c_void",
1023
1024 // elx.xml types
1025 "khronos_utime_nanoseconds_t" => "types::khronos_utime_nanoseconds_t",
1026 "khronos_uint64_t" => "types::khronos_uint64_t",
1027 "khronos_ssize_t" => "types::khronos_ssize_t",
1028 "EGLNativeDisplayType" => "types::EGLNativeDisplayType",
1029 "EGLNativePixmapType" => "types::EGLNativePixmapType",
1030 "EGLNativeWindowType" => "types::EGLNativeWindowType",
1031 "EGLint" => "types::EGLint",
1032 "EGLint *" => "*mut types::EGLint",
1033 "const EGLint *" => "*const types::EGLint",
1034 "NativeDisplayType" => "types::NativeDisplayType",
1035 "NativePixmapType" => "types::NativePixmapType",
1036 "NativeWindowType" => "types::NativeWindowType",
1037 //"Bool" => "types::Bool",
1038 "EGLBoolean" => "types::EGLBoolean",
1039 "EGLenum" => "types::EGLenum",
1040 "EGLAttribKHR" => "types::EGLAttribKHR",
1041 "EGLAttrib" => "types::EGLAttrib",
1042 "EGLAttrib *" => "*mut types::EGLAttrib",
1043 "const EGLAttrib *" => "*const types::EGLAttrib",
1044 "const EGLattrib *" => "*const types::EGLAttrib", // Due to a typo in khronos_api/api_angle/scripts/egl_angle_ext.xml - see brendanzab/gl-rs#491
1045 "EGLConfig" => "types::EGLConfig",
1046 "EGLConfig *" => "*mut types::EGLConfig",
1047 "EGLContext" => "types::EGLContext",
1048 "EGLDeviceEXT" => "types::EGLDeviceEXT",
1049 "EGLDisplay" => "types::EGLDisplay",
1050 "EGLSurface" => "types::EGLSurface",
1051 "EGLClientBuffer" => "types::EGLClientBuffer",
1052 "__eglMustCastToProperFunctionPointerType" => {
1053 "types::__eglMustCastToProperFunctionPointerType"
1054 },
1055 "EGLImageKHR" => "types::EGLImageKHR",
1056 "EGLImage" => "types::EGLImage",
1057 "EGLOutputLayerEXT" => "types::EGLOutputLayerEXT",
1058 "EGLOutputPortEXT" => "types::EGLOutputPortEXT",
1059 "EGLSyncKHR" => "types::EGLSyncKHR",
1060 "EGLSync" => "types::EGLSync",
1061 "EGLTimeKHR" => "types::EGLTimeKHR",
1062 "EGLTime" => "types::EGLTime",
1063 "EGLSyncNV" => "types::EGLSyncNV",
1064 "EGLTimeNV" => "types::EGLTimeNV",
1065 "EGLuint64NV" => "types::EGLuint64NV",
1066 "EGLStreamKHR" => "types::EGLStreamKHR",
1067 "EGLuint64KHR" => "types::EGLuint64KHR",
1068 "EGLNativeFileDescriptorKHR" => "types::EGLNativeFileDescriptorKHR",
1069 "EGLsizeiANDROID" => "types::EGLsizeiANDROID",
1070 "EGLSetBlobFuncANDROID" => "types::EGLSetBlobFuncANDROID",
1071 "EGLGetBlobFuncANDROID" => "types::EGLGetBlobFuncANDROID",
1072 "EGLClientPixmapHI" => "types::EGLClientPixmapHI",
1073 "struct EGLClientPixmapHI *" => "*const types::EGLClientPixmapHI",
1074 "const EGLAttribKHR *" => "*const types::EGLAttribKHR",
1075 "const EGLuint64KHR *" => "*const types::EGLuint64KHR",
1076 "EGLAttribKHR *" => "*mut types::EGLAttribKHR",
1077 "EGLDeviceEXT *" => "*mut types::EGLDeviceEXT",
1078 "EGLNativeDisplayType *" => "*mut types::EGLNativeDisplayType",
1079 "EGLNativePixmapType *" => "*mut types::EGLNativePixmapType",
1080 "EGLNativeWindowType *" => "*mut types::EGLNativeWindowType",
1081 "EGLOutputLayerEXT *" => "*mut types::EGLOutputLayerEXT",
1082 "EGLTimeKHR *" => "*mut types::EGLTimeKHR",
1083 "EGLOutputPortEXT *" => "*mut types::EGLOutputPortEXT",
1084 "EGLuint64KHR *" => "*mut types::EGLuint64KHR",
1085 "const struct AHardwareBuffer *" => "*const __gl_imports::raw::c_void", // humm
1086
1087 "GLeglClientBufferEXT" => "types::GLeglClientBufferEXT",
1088 "GLVULKANPROCNV" => "types::GLVULKANPROCNV",
1089 "EGLDEBUGPROCKHR" => "types::EGLDEBUGPROCKHR",
1090 "EGLObjectKHR" => "types::EGLObjectKHR",
1091 "EGLLabelKHR" => "types::EGLLabelKHR",
1092 "EGLnsecsANDROID" => "types::EGLnsecsANDROID",
1093 "EGLnsecsANDROID *" => "*mut types::EGLnsecsANDROID",
1094 "EGLBoolean *" => "*mut types::EGLBoolean",
1095
1096 // failure
1097 _ => panic!("Type conversion not implemented for `{}`", ty.as_ref()),
1098 };
1099
1100 Cow::Borrowed(ty)
1101}
1102
1103#[cfg(test)]
1104mod tests {
1105 mod underscore_numeric_prefix {
1106 use registry::parse;
1107
1108 #[test]
1109 fn test_numeric_prefix() {
1110 assert_eq!(parse::underscore_numeric_prefix("3"), "_3");
1111 assert_eq!(parse::underscore_numeric_prefix("123_FOO"), "_123_FOO");
1112 }
1113
1114 #[test]
1115 fn test_non_numeric_prefix() {
1116 assert_eq!(parse::underscore_numeric_prefix(""), "");
1117 assert_eq!(parse::underscore_numeric_prefix("A"), "A");
1118 assert_eq!(parse::underscore_numeric_prefix("FOO"), "FOO");
1119 }
1120 }
1121
1122 mod underscore_keyword {
1123 use registry::parse;
1124
1125 #[test]
1126 fn test_keyword() {
1127 assert_eq!(parse::underscore_keyword("in".to_string()), "in_");
1128 assert_eq!(parse::underscore_keyword("ref".to_string()), "ref_");
1129 assert_eq!(parse::underscore_keyword("type".to_string()), "type_");
1130 }
1131
1132 #[test]
1133 fn test_non_keyword() {
1134 assert_eq!(parse::underscore_keyword("foo".to_string()), "foo");
1135 assert_eq!(parse::underscore_keyword("bar".to_string()), "bar");
1136 }
1137 }
1138 mod make_enum {
1139 use registry::parse;
1140
1141 #[test]
1142 fn test_cast_0() {
1143 let e = parse::make_enum(
1144 "FOO".to_string(),
1145 None,
1146 "((EGLint)-1)".to_string(),
1147 Some("BAR".to_string()),
1148 );
1149 assert_eq!(e.ident, "FOO");
1150 assert_eq!((&*e.ty, &*e.value), ("EGLint", "-1"));
1151 assert_eq!(e.alias, Some("BAR".to_string()));
1152 }
1153
1154 #[test]
1155 fn test_cast_1() {
1156 let e = parse::make_enum(
1157 "FOO".to_string(),
1158 None,
1159 "((EGLint)(-1))".to_string(),
1160 Some("BAR".to_string()),
1161 );
1162 assert_eq!(e.ident, "FOO");
1163 assert_eq!((&*e.ty, &*e.value), ("EGLint", "(-1)"));
1164 assert_eq!(e.alias, Some("BAR".to_string()));
1165 }
1166
1167 #[test]
1168 fn test_no_type() {
1169 let e = parse::make_enum(
1170 "FOO".to_string(),
1171 None,
1172 "value".to_string(),
1173 Some("BAR".to_string()),
1174 );
1175 assert_eq!(e.ident, "FOO");
1176 assert_eq!(e.value, "value");
1177 assert_eq!(e.alias, Some("BAR".to_string()));
1178 assert_eq!(e.ty, "GLenum");
1179 assert_eq!(e.cast, false);
1180 }
1181
1182 #[test]
1183 fn test_u() {
1184 let e = parse::make_enum(
1185 "FOO".to_string(),
1186 Some("u".to_string()),
1187 String::new(),
1188 None,
1189 );
1190 assert_eq!(e.ty, "GLuint");
1191 }
1192
1193 #[test]
1194 fn test_ull() {
1195 let e = parse::make_enum(
1196 "FOO".to_string(),
1197 Some("ull".to_string()),
1198 String::new(),
1199 None,
1200 );
1201 assert_eq!(e.ty, "GLuint64");
1202 }
1203
1204 #[test]
1205 #[should_panic]
1206 fn test_unknown_type() {
1207 parse::make_enum(
1208 "FOO".to_string(),
1209 Some("blargh".to_string()),
1210 String::new(),
1211 None,
1212 );
1213 }
1214
1215 #[test]
1216 fn test_value_str() {
1217 let e = parse::make_enum("FOO".to_string(), None, "\"hi\"".to_string(), None);
1218 assert_eq!(e.ty, "&'static str");
1219 }
1220
1221 #[test]
1222 fn test_ident_true() {
1223 let e = parse::make_enum("TRUE".to_string(), None, String::new(), None);
1224 assert_eq!(e.ty, "GLboolean");
1225 }
1226
1227 #[test]
1228 fn test_ident_false() {
1229 let e = parse::make_enum("FALSE".to_string(), None, String::new(), None);
1230 assert_eq!(e.ty, "GLboolean");
1231 }
1232 }
1233
1234 mod make_egl_enum {
1235 use registry::parse;
1236
1237 #[test]
1238 fn test_cast_egl() {
1239 let e = parse::make_egl_enum(
1240 "FOO".to_string(),
1241 None,
1242 "EGL_CAST(EGLint,-1)".to_string(),
1243 Some("BAR".to_string()),
1244 );
1245 assert_eq!(e.ident, "FOO");
1246 assert_eq!((&*e.ty, &*e.value), ("EGLint", "-1"));
1247 assert_eq!(e.alias, Some("BAR".to_string()));
1248 }
1249
1250 #[test]
1251 fn test_ident_true() {
1252 let e = parse::make_egl_enum("TRUE".to_string(), None, "1234".to_string(), None);
1253 assert_eq!(e.ty, "EGLBoolean");
1254 }
1255
1256 #[test]
1257 fn test_ident_false() {
1258 let e = parse::make_egl_enum("FALSE".to_string(), None, "1234".to_string(), None);
1259 assert_eq!(e.ty, "EGLBoolean");
1260 }
1261
1262 #[test]
1263 fn test_ull() {
1264 let e = parse::make_egl_enum(
1265 "FOO".to_string(),
1266 Some("ull".to_string()),
1267 "1234".to_string(),
1268 None,
1269 );
1270 assert_eq!(e.ty, "EGLuint64KHR");
1271 }
1272
1273 #[test]
1274 fn test_negative_value() {
1275 let e = parse::make_egl_enum("FOO".to_string(), None, "-1".to_string(), None);
1276 assert_eq!(e.ty, "EGLint");
1277 }
1278
1279 #[test]
1280 #[should_panic]
1281 fn test_unknown_type() {
1282 parse::make_egl_enum(
1283 "FOO".to_string(),
1284 Some("blargh".to_string()),
1285 String::new(),
1286 None,
1287 );
1288 }
1289
1290 #[test]
1291 #[should_panic]
1292 fn test_unknown_value() {
1293 parse::make_egl_enum("FOO".to_string(), None, "a".to_string(), None);
1294 }
1295
1296 #[test]
1297 #[should_panic]
1298 fn test_empty_value() {
1299 parse::make_egl_enum("FOO".to_string(), None, String::new(), None);
1300 }
1301 }
1302
1303 mod parse_event {
1304 mod from_xml {
1305 use xml::attribute::OwnedAttribute;
1306 use xml::common::XmlVersion;
1307 use xml::name::OwnedName;
1308 use xml::namespace::Namespace;
1309 use xml::reader::XmlEvent;
1310
1311 use registry::parse::{Attribute, ParseEvent};
1312
1313 #[test]
1314 fn test_start_event() {
1315 let given = XmlEvent::StartElement {
1316 name: OwnedName::local("element"),
1317 attributes: vec![
1318 OwnedAttribute::new(OwnedName::local("attr1"), "val1"),
1319 OwnedAttribute::new(OwnedName::local("attr2"), "val2"),
1320 ],
1321 namespace: Namespace::empty(),
1322 };
1323 let expected = ParseEvent::Start(
1324 "element".to_string(),
1325 vec![
1326 Attribute::new("attr1", "val1"),
1327 Attribute::new("attr2", "val2"),
1328 ],
1329 );
1330 assert_eq!(ParseEvent::from_xml(given), Some(expected));
1331 }
1332
1333 #[test]
1334 fn test_end_element() {
1335 let given = XmlEvent::EndElement {
1336 name: OwnedName::local("element"),
1337 };
1338 let expected = ParseEvent::End("element".to_string());
1339 assert_eq!(ParseEvent::from_xml(given), Some(expected));
1340 }
1341
1342 #[test]
1343 fn test_characters() {
1344 let given = XmlEvent::Characters("text".to_string());
1345 let expected = ParseEvent::Text("text".to_string());
1346 assert_eq!(ParseEvent::from_xml(given), Some(expected));
1347 }
1348
1349 #[test]
1350 fn test_start_document() {
1351 let given = XmlEvent::StartDocument {
1352 version: XmlVersion::Version10,
1353 encoding: "".to_string(),
1354 standalone: None,
1355 };
1356 assert_eq!(ParseEvent::from_xml(given), None);
1357 }
1358
1359 #[test]
1360 fn test_end_document() {
1361 let given = XmlEvent::EndDocument;
1362 assert_eq!(ParseEvent::from_xml(given), None);
1363 }
1364
1365 #[test]
1366 fn test_processing_instruction() {
1367 let given = XmlEvent::ProcessingInstruction {
1368 name: "".to_string(),
1369 data: None,
1370 };
1371 assert_eq!(ParseEvent::from_xml(given), None);
1372 }
1373
1374 #[test]
1375 fn test_cdata() {
1376 let given = XmlEvent::CData("CData".to_string());
1377 assert_eq!(ParseEvent::from_xml(given), None);
1378 }
1379
1380 #[test]
1381 fn test_comment() {
1382 let given = XmlEvent::Comment("Comment".to_string());
1383 assert_eq!(ParseEvent::from_xml(given), None);
1384 }
1385
1386 #[test]
1387 fn test_whitespace() {
1388 let given = XmlEvent::Whitespace("Whitespace".to_string());
1389 assert_eq!(ParseEvent::from_xml(given), None);
1390 }
1391 }
1392 }
1393}
1394