summaryrefslogtreecommitdiffstats
path: root/third_party/rust/gl_generator/registry/parse.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/gl_generator/registry/parse.rs
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/gl_generator/registry/parse.rs')
-rw-r--r--third_party/rust/gl_generator/registry/parse.rs1393
1 files changed, 1393 insertions, 0 deletions
diff --git a/third_party/rust/gl_generator/registry/parse.rs b/third_party/rust/gl_generator/registry/parse.rs
new file mode 100644
index 0000000000..c1a11a6c5f
--- /dev/null
+++ b/third_party/rust/gl_generator/registry/parse.rs
@@ -0,0 +1,1393 @@
+// Copyright 2015 Brendan Zabarauskas and the gl-rs developers
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+extern crate khronos_api;
+
+use std::borrow::Cow;
+use std::collections::btree_map::Entry;
+use std::collections::{BTreeMap, BTreeSet};
+use std::io;
+use xml::attribute::OwnedAttribute;
+use xml::reader::XmlEvent;
+use xml::EventReader as XmlEventReader;
+
+use registry::{Binding, Cmd, Enum, GlxOpcode, Group, Registry};
+use {Api, Fallbacks, Profile};
+
+pub fn from_xml<R: io::Read>(
+ src: R,
+ filter: &Filter,
+ require_feature: bool,
+) -> Registry {
+ XmlEventReader::new(src)
+ .into_iter()
+ .map(Result::unwrap)
+ .filter_map(ParseEvent::from_xml)
+ .parse(filter, require_feature)
+}
+
+#[derive(Debug, PartialEq, Eq)]
+struct Attribute {
+ key: String,
+ value: String,
+}
+
+impl Attribute {
+ fn new<Key, Value>(key: Key, value: Value) -> Attribute
+ where
+ Key: ToString,
+ Value: ToString,
+ {
+ Attribute {
+ key: key.to_string(),
+ value: value.to_string(),
+ }
+ }
+}
+
+impl From<OwnedAttribute> for Attribute {
+ fn from(attribute: OwnedAttribute) -> Attribute {
+ Attribute::new(attribute.name.local_name, attribute.value)
+ }
+}
+
+#[derive(Debug, PartialEq, Eq)]
+enum ParseEvent {
+ Start(String, Vec<Attribute>),
+ End(String),
+ Text(String),
+}
+
+impl ParseEvent {
+ fn from_xml(event: XmlEvent) -> Option<ParseEvent> {
+ match event {
+ XmlEvent::StartDocument { .. } => None,
+ XmlEvent::EndDocument => None,
+ XmlEvent::StartElement {
+ name, attributes, ..
+ } => {
+ let attributes = attributes.into_iter().map(Attribute::from).collect();
+ Some(ParseEvent::Start(name.local_name, attributes))
+ },
+ XmlEvent::EndElement { name } => Some(ParseEvent::End(name.local_name)),
+ XmlEvent::Characters(chars) => Some(ParseEvent::Text(chars)),
+ XmlEvent::ProcessingInstruction { .. } => None,
+ XmlEvent::CData(_) => None,
+ XmlEvent::Comment(_) => None,
+ XmlEvent::Whitespace(_) => None,
+ }
+ }
+}
+
+fn api_from_str(src: &str) -> Result<Option<Api>, ()> {
+ match src {
+ "gl" => Ok(Some(Api::Gl)),
+ "glx" => Ok(Some(Api::Glx)),
+ "wgl" => Ok(Some(Api::Wgl)),
+ "egl" => Ok(Some(Api::Egl)),
+ "glcore" => Ok(Some(Api::GlCore)),
+ "gles1" => Ok(Some(Api::Gles1)),
+ "gles2" => Ok(Some(Api::Gles2)),
+ "glsc2" => Ok(Some(Api::Glsc2)),
+ "disabled" => Ok(None),
+ _ => Err(()),
+ }
+}
+
+fn profile_from_str(src: &str) -> Result<Profile, ()> {
+ match src {
+ "core" => Ok(Profile::Core),
+ "compatibility" => Ok(Profile::Compatibility),
+ _ => Err(()),
+ }
+}
+
+fn underscore_numeric_prefix(src: &str) -> String {
+ match src.chars().next() {
+ Some(c) if c.is_numeric() => format!("_{}", src),
+ Some(_) | None => src.to_string(),
+ }
+}
+
+fn underscore_keyword(ident: String) -> String {
+ match ident.as_ref() {
+ "in" => "in_".to_string(),
+ "ref" => "ref_".to_string(),
+ "type" => "type_".to_string(),
+ _ => ident,
+ }
+}
+
+fn trim_str<'a>(s: &'a str, trim: &str) -> &'a str {
+ if s.starts_with(trim) {
+ &s[trim.len()..]
+ } else {
+ s
+ }
+}
+
+fn trim_enum_prefix(ident: &str, api: Api) -> String {
+ let ident = match api {
+ Api::Gl | Api::GlCore | Api::Gles1 | Api::Gles2 | Api::Glsc2 => trim_str(ident, "GL_"),
+ Api::Glx => trim_str(ident, "GLX_"),
+ Api::Wgl => trim_str(ident, "WGL_"),
+ Api::Egl => trim_str(ident, "EGL_"),
+ };
+ underscore_numeric_prefix(ident)
+}
+
+fn make_enum(ident: String, ty: Option<String>, value: String, alias: Option<String>) -> Enum {
+ let (ty, value, cast) = {
+ if value.starts_with("((") && value.ends_with(")") {
+ // Some enums have a value of the form `'((' type ')' expr ')'`.
+
+ // nothing to see here....
+ // just brute forcing some paren matching... (ノ ◕ ◡ ◕)ノ *:・゚✧
+ let working = &value[2..value.len() - 1];
+ if let Some((i, _)) = working.match_indices(")").next() {
+ let ty = working[..i].to_string();
+ let value = working[i + 1..].to_string();
+
+ (Cow::Owned(ty), value, true)
+ } else {
+ panic!("Unexpected value format: {}", value)
+ }
+ } else {
+ let ty = match ty {
+ Some(ref ty) if ty == "u" => "GLuint",
+ Some(ref ty) if ty == "ull" => "GLuint64",
+ Some(ty) => panic!("Unhandled enum type: {}", ty),
+ None if value.starts_with("\"") => "&'static str",
+ None if ident == "TRUE" || ident == "FALSE" => "GLboolean",
+ None => "GLenum",
+ };
+ (Cow::Borrowed(ty), value, false)
+ }
+ };
+
+ Enum {
+ ident: ident,
+ value: value,
+ cast: cast,
+ alias: alias,
+ ty: ty,
+ }
+}
+
+fn make_egl_enum(ident: String, ty: Option<String>, value: String, alias: Option<String>) -> Enum {
+ let (ty, value, cast) = {
+ if value.starts_with("EGL_CAST(") && value.ends_with(")") {
+ // Handling "SpecialNumbers" in the egl.xml file
+ // The values for these enums has the form `'EGL_CAST(' type ',' expr ')'`.
+ let working = &value[9..value.len() - 1];
+ if let Some((i, _)) = working.match_indices(",").next() {
+ let ty = working[..i].to_string();
+ let value = working[i + 1..].to_string();
+
+ (Cow::Owned(ty), value, true)
+ } else {
+ panic!("Unexpected value format: {}", value)
+ }
+ } else {
+ match value.chars().next() {
+ Some('-') | Some('0'..='9') => (),
+ _ => panic!("Unexpected value format: {}", value),
+ }
+
+ let ty = match ty {
+ Some(ref ty) if ty == "ull" => "EGLuint64KHR",
+ Some(ty) => panic!("Unhandled enum type: {}", ty),
+ None if value.starts_with('-') => "EGLint",
+ None if ident == "TRUE" || ident == "FALSE" => "EGLBoolean",
+ None => "EGLenum",
+ };
+ (Cow::Borrowed(ty), value, false)
+ }
+ };
+
+ Enum {
+ ident: ident,
+ value: value,
+ cast: cast,
+ alias: alias,
+ ty: ty,
+ }
+}
+
+fn trim_cmd_prefix(ident: &str, api: Api) -> &str {
+ match api {
+ Api::Gl | Api::GlCore | Api::Gles1 | Api::Gles2 | Api::Glsc2 => trim_str(ident, "gl"),
+ Api::Glx => trim_str(ident, "glX"),
+ Api::Wgl => trim_str(ident, "wgl"),
+ Api::Egl => trim_str(ident, "egl"),
+ }
+}
+
+fn merge_map(a: &mut BTreeMap<String, Vec<String>>, b: BTreeMap<String, Vec<String>>) {
+ for (k, v) in b {
+ match a.entry(k) {
+ Entry::Occupied(mut ent) => {
+ ent.get_mut().extend(v);
+ },
+ Entry::Vacant(ent) => {
+ ent.insert(v);
+ },
+ }
+ }
+}
+
+#[derive(Clone)]
+struct Feature {
+ pub api: Api,
+ pub name: String,
+ pub number: String,
+ pub requires: Vec<Require>,
+ pub removes: Vec<Remove>,
+}
+
+#[derive(Clone)]
+struct Require {
+ /// A reference to the earlier types, by name
+ pub enums: Vec<String>,
+ /// A reference to the earlier types, by name
+ pub commands: Vec<String>,
+}
+
+#[derive(Clone)]
+struct Remove {
+ // always Core, for now
+ pub profile: Profile,
+ /// A reference to the earlier types, by name
+ pub enums: Vec<String>,
+ /// A reference to the earlier types, by name
+ pub commands: Vec<String>,
+}
+
+#[derive(Clone)]
+struct Extension {
+ pub name: String,
+ /// which apis this extension is defined for (see Feature.api)
+ pub supported: Vec<Api>,
+ pub requires: Vec<Require>,
+}
+
+pub struct Filter {
+ pub api: Api,
+ pub fallbacks: Fallbacks,
+ pub extensions: BTreeSet<String>,
+ pub profile: Profile,
+ pub version: String,
+}
+
+trait Parse: Sized + Iterator<Item = ParseEvent> {
+ fn parse(mut self, filter: &Filter, require_feature: bool) -> Registry {
+ self.consume_start_element("registry");
+
+ let mut enums = Vec::new();
+ let mut cmds = Vec::new();
+ let mut features = Vec::new();
+ let mut extensions = Vec::new();
+ let mut aliases = BTreeMap::new();
+ let mut groups: BTreeMap<String, Group> = BTreeMap::new();
+
+ while let Some(event) = self.next() {
+ match event {
+ // ignores
+ ParseEvent::Text(_) => (),
+ ParseEvent::Start(ref name, _) if name == "comment" => self.skip_to_end("comment"),
+ ParseEvent::Start(ref name, _) if name == "types" => self.skip_to_end("types"),
+
+ // add group namespace
+ ParseEvent::Start(ref name, _) if name == "groups" => {
+ groups.extend(self.consume_groups(filter.api));
+ },
+
+ // add enum namespace
+ ParseEvent::Start(ref name, ref attributes) if name == "enums" => {
+ enums.extend(self.consume_enums(filter.api));
+ let enums_group = get_attribute(&attributes, "group");
+ let enums_type = get_attribute(&attributes, "type");
+ if let Some(group) = enums_group.and_then(|name| groups.get_mut(&name)) {
+ group.enums_type = enums_type;
+ }
+ },
+
+ // add command namespace
+ ParseEvent::Start(ref name, _) if name == "commands" => {
+ let (new_cmds, new_aliases) = self.consume_cmds(filter.api);
+ cmds.extend(new_cmds);
+ merge_map(&mut aliases, new_aliases);
+ },
+
+ ParseEvent::Start(ref name, ref attributes) if name == "feature" => {
+ debug!("Parsing feature: {:?}", attributes);
+ features.push(Feature::convert(&mut self, &attributes));
+ },
+
+ ParseEvent::Start(ref name, _) if name == "extensions" => loop {
+ match self.next().unwrap() {
+ ParseEvent::Start(ref name, ref attributes) if name == "extension" => {
+ extensions.push(Extension::convert(&mut self, &attributes));
+ },
+ ParseEvent::End(ref name) if name == "extensions" => break,
+ event => panic!("Unexpected message {:?}", event),
+ }
+ },
+
+ // finished building the registry
+ ParseEvent::End(ref name) if name == "registry" => break,
+
+ // error handling
+ event => panic!("Expected </registry>, found: {:?}", event),
+ }
+ }
+
+ let mut desired_enums = BTreeSet::new();
+ let mut desired_cmds = BTreeSet::new();
+
+ // find the features we want
+ let mut found_feature = false;
+ for feature in &features {
+ // XXX: verify that the string comparison with <= actually works as desired
+ if feature.api == filter.api && feature.number <= filter.version {
+ for require in &feature.requires {
+ desired_enums.extend(require.enums.iter().map(|x| x.clone()));
+ desired_cmds.extend(require.commands.iter().map(|x| x.clone()));
+ }
+
+ for remove in &feature.removes {
+ if remove.profile == filter.profile {
+ for enm in &remove.enums {
+ debug!("Removing {}", enm);
+ desired_enums.remove(enm);
+ }
+ for cmd in &remove.commands {
+ debug!("Removing {}", cmd);
+ desired_cmds.remove(cmd);
+ }
+ }
+ }
+ }
+ if feature.number == filter.version {
+ found_feature = true;
+ }
+ }
+
+ if !found_feature && require_feature {
+ panic!("Did not find version {} in the registry", filter.version);
+ }
+
+ for extension in &extensions {
+ if filter.extensions.contains(&extension.name) {
+ if !extension.supported.contains(&filter.api) {
+ panic!(
+ "Requested {}, which doesn't support the {} API",
+ extension.name, filter.api
+ );
+ }
+ for require in &extension.requires {
+ desired_enums.extend(require.enums.iter().map(|x| x.clone()));
+ desired_cmds.extend(require.commands.iter().map(|x| x.clone()));
+ }
+ }
+ }
+
+ let is_desired_enum = |e: &Enum| {
+ desired_enums.contains(&("GL_".to_string() + &e.ident))
+ || desired_enums.contains(&("WGL_".to_string() + &e.ident))
+ || desired_enums.contains(&("GLX_".to_string() + &e.ident))
+ || desired_enums.contains(&("EGL_".to_string() + &e.ident))
+ };
+
+ let is_desired_cmd = |c: &Cmd| {
+ desired_cmds.contains(&("gl".to_string() + &c.proto.ident))
+ || desired_cmds.contains(&("wgl".to_string() + &c.proto.ident))
+ || desired_cmds.contains(&("glX".to_string() + &c.proto.ident))
+ || desired_cmds.contains(&("egl".to_string() + &c.proto.ident))
+ };
+
+ Registry {
+ api: filter.api,
+ enums: enums.into_iter().filter(is_desired_enum).collect(),
+ cmds: cmds.into_iter().filter(is_desired_cmd).collect(),
+ aliases: if filter.fallbacks == Fallbacks::None {
+ BTreeMap::new()
+ } else {
+ aliases
+ },
+ groups,
+ }
+ }
+
+ fn consume_characters(&mut self) -> String {
+ match self.next().unwrap() {
+ ParseEvent::Text(ch) => ch,
+ event => panic!("Expected characters, found: {:?}", event),
+ }
+ }
+
+ fn consume_start_element(&mut self, expected_name: &str) -> Vec<Attribute> {
+ match self.next().unwrap() {
+ ParseEvent::Start(name, attributes) => {
+ if expected_name == name {
+ attributes
+ } else {
+ panic!("Expected <{}>, found: <{}>", expected_name, name)
+ }
+ },
+ event => panic!("Expected <{}>, found: {:?}", expected_name, event),
+ }
+ }
+
+ fn consume_end_element(&mut self, expected_name: &str) {
+ match self.next().unwrap() {
+ ParseEvent::End(ref name) if expected_name == name => (),
+ event => panic!("Expected </{}>, found: {:?}", expected_name, event),
+ }
+ }
+
+ fn skip_to_end(&mut self, expected_name: &str) {
+ loop {
+ match self.next().unwrap() {
+ ParseEvent::End(ref name) if expected_name == name => break,
+ _ => {},
+ }
+ }
+ }
+
+ fn consume_two<'a, T: FromXml, U: FromXml>(
+ &mut self,
+ one: &'a str,
+ two: &'a str,
+ end: &'a str,
+ ) -> (Vec<T>, Vec<U>) {
+ debug!("consume_two: looking for {} and {} until {}", one, two, end);
+
+ let mut ones = Vec::new();
+ let mut twos = Vec::new();
+
+ loop {
+ match self.next().unwrap() {
+ ParseEvent::Start(ref name, ref attributes) => {
+ debug!("Found start element <{:?} {:?}>", name, attributes);
+ debug!("one and two are {} and {}", one, two);
+
+ let n = name.clone();
+
+ if one == n {
+ ones.push(FromXml::convert(self, &attributes));
+ } else if "type" == n {
+ // XXX: GL1.1 contains types, which we never care about anyway.
+ // Make sure consume_two doesn't get used for things which *do*
+ // care about type.
+ warn!("Ignoring type!");
+ continue;
+ } else if two == n {
+ twos.push(FromXml::convert(self, &attributes));
+ } else {
+ panic!("Unexpected element: <{:?} {:?}>", n, &attributes);
+ }
+ },
+ ParseEvent::End(ref name) => {
+ debug!("Found end element </{:?}>", name);
+
+ if one == name || two == name {
+ continue;
+ } else if "type" == name {
+ // XXX: GL1.1 contains types, which we never care about anyway.
+ // Make sure consume_two doesn't get used for things which *do*
+ // care about type.
+ warn!("Ignoring type!");
+ continue;
+ } else if end == name {
+ return (ones, twos);
+ } else {
+ panic!("Unexpected end element {:?}", name);
+ }
+ },
+ event => panic!("Unexpected message {:?}", event),
+ }
+ }
+ }
+
+ fn consume_enums(&mut self, api: Api) -> Vec<Enum> {
+ let mut enums = Vec::new();
+ loop {
+ match self.next().unwrap() {
+ // ignores
+ ParseEvent::Text(_) => {},
+ ParseEvent::Start(ref name, _) if name == "unused" => self.skip_to_end("unused"),
+
+ // add enum definition
+ ParseEvent::Start(ref name, ref attributes) if name == "enum" => {
+ enums.push(self.consume_enum(api, attributes));
+ },
+
+ // finished building the namespace
+ ParseEvent::End(ref name) if name == "enums" => break,
+ // error handling
+ event => panic!("Expected </enums>, found: {:?}", event),
+ }
+ }
+ enums
+ }
+
+ fn consume_enum(&mut self, api: Api, attributes: &[Attribute]) -> Enum {
+ let ident = trim_enum_prefix(&get_attribute(&attributes, "name").unwrap(), api).to_string();
+ let value = get_attribute(&attributes, "value").unwrap();
+ let alias = get_attribute(&attributes, "alias");
+ let ty = get_attribute(&attributes, "type");
+ self.consume_end_element("enum");
+
+ match api {
+ Api::Egl => make_egl_enum(ident, ty, value, alias),
+ _ => make_enum(ident, ty, value, alias),
+ }
+ }
+
+ fn consume_groups(&mut self, api: Api) -> BTreeMap<String, Group> {
+ let mut groups = BTreeMap::new();
+ loop {
+ match self.next().unwrap() {
+ ParseEvent::Start(ref name, ref attributes) if name == "group" => {
+ let ident = get_attribute(&attributes, "name").unwrap();
+ let group = Group {
+ ident: ident.clone(),
+ enums_type: None,
+ enums: self.consume_group_enums(api)
+ };
+ groups.insert(ident, group);
+ },
+ ParseEvent::End(ref name) if name == "groups" => break,
+ event => panic!("Expected </groups>, found: {:?}", event),
+ }
+ }
+ groups
+ }
+
+ fn consume_group_enums(&mut self, api: Api) -> Vec<String> {
+ let mut enums = Vec::new();
+ loop {
+ match self.next().unwrap() {
+ ParseEvent::Start(ref name, ref attributes) if name == "enum" => {
+ let enum_name = get_attribute(&attributes, "name");
+ enums.push(trim_enum_prefix(&enum_name.unwrap(), api));
+ self.consume_end_element("enum");
+ },
+ ParseEvent::End(ref name) if name == "group" => break,
+ event => panic!("Expected </group>, found: {:?}", event),
+ }
+ }
+ enums
+ }
+
+ fn consume_cmds(&mut self, api: Api) -> (Vec<Cmd>, BTreeMap<String, Vec<String>>) {
+ let mut cmds = Vec::new();
+ let mut aliases: BTreeMap<String, Vec<String>> = BTreeMap::new();
+ loop {
+ match self.next().unwrap() {
+ // add command definition
+ ParseEvent::Start(ref name, _) if name == "command" => {
+ let new = self.consume_cmd(api);
+ if let Some(ref v) = new.alias {
+ match aliases.entry(v.clone()) {
+ Entry::Occupied(mut ent) => {
+ ent.get_mut().push(new.proto.ident.clone());
+ },
+ Entry::Vacant(ent) => {
+ ent.insert(vec![new.proto.ident.clone()]);
+ },
+ }
+ }
+ cmds.push(new);
+ },
+ // finished building the namespace
+ ParseEvent::End(ref name) if name == "commands" => break,
+ // error handling
+ event => panic!("Expected </commands>, found: {:?}", event),
+ }
+ }
+ (cmds, aliases)
+ }
+
+ fn consume_cmd(&mut self, api: Api) -> Cmd {
+ // consume command prototype
+ self.consume_start_element("proto");
+ let mut proto = self.consume_binding("proto", &[]);
+ proto.ident = trim_cmd_prefix(&proto.ident, api).to_string();
+
+ let mut params = Vec::new();
+ let mut alias = None;
+ let mut vecequiv = None;
+ let mut glx = None;
+ loop {
+ match self.next().unwrap() {
+ ParseEvent::Start(ref name, ref attributes) if name == "param" => {
+ params.push(self.consume_binding("param", attributes));
+ },
+ ParseEvent::Start(ref name, ref attributes) if name == "alias" => {
+ alias = get_attribute(&attributes, "name");
+ alias = alias.map(|t| trim_cmd_prefix(&t, api).to_string());
+ self.consume_end_element("alias");
+ },
+ ParseEvent::Start(ref name, ref attributes) if name == "vecequiv" => {
+ vecequiv = get_attribute(&attributes, "vecequiv");
+ self.consume_end_element("vecequiv");
+ },
+ ParseEvent::Start(ref name, ref attributes) if name == "glx" => {
+ glx = Some(GlxOpcode {
+ opcode: get_attribute(&attributes, "opcode").unwrap(),
+ name: get_attribute(&attributes, "name"),
+ });
+ self.consume_end_element("glx");
+ },
+ ParseEvent::End(ref name) if name == "command" => break,
+ event => panic!("Expected </command>, found: {:?}", event),
+ }
+ }
+
+ Cmd {
+ proto: proto,
+ params: params,
+ alias: alias,
+ vecequiv: vecequiv,
+ glx: glx,
+ }
+ }
+
+ fn consume_binding(&mut self, outside_tag: &str, attributes: &[Attribute]) -> Binding {
+ // consume type
+ let mut ty = String::new();
+ loop {
+ match self.next().unwrap() {
+ ParseEvent::Text(text) => ty.push_str(&text),
+ ParseEvent::Start(ref name, _) if name == "ptype" => (),
+ ParseEvent::End(ref name) if name == "ptype" => (),
+ ParseEvent::Start(ref name, _) if name == "name" => break,
+ event => panic!("Expected binding, found: {:?}", event),
+ }
+ }
+
+ // consume identifier
+ let ident = underscore_keyword(self.consume_characters());
+ self.consume_end_element("name");
+
+ // consume the type suffix
+ loop {
+ match self.next().unwrap() {
+ ParseEvent::Text(text) => ty.push_str(&text),
+ ParseEvent::End(ref name) if name == outside_tag => break,
+ event => panic!("Expected binding, found: {:?}", event),
+ }
+ }
+
+ Binding {
+ ident: ident,
+ ty: to_rust_ty(ty),
+ group: get_attribute(&attributes, "group"),
+ }
+ }
+}
+
+impl<T> Parse for T where T: Sized + Iterator<Item = ParseEvent> {}
+
+fn get_attribute(attribs: &[Attribute], key: &str) -> Option<String> {
+ attribs
+ .iter()
+ .find(|attrib| attrib.key == key)
+ .map(|attrib| attrib.value.clone())
+}
+
+trait FromXml {
+ fn convert<P: Parse>(parser: &mut P, a: &[Attribute]) -> Self;
+}
+
+impl FromXml for Require {
+ fn convert<P: Parse>(parser: &mut P, _: &[Attribute]) -> Require {
+ debug!("Doing a FromXml on Require");
+ let (enums, commands) = parser.consume_two("enum", "command", "require");
+ Require {
+ enums: enums,
+ commands: commands,
+ }
+ }
+}
+
+impl FromXml for Remove {
+ fn convert<P: Parse>(parser: &mut P, a: &[Attribute]) -> Remove {
+ debug!("Doing a FromXml on Remove");
+ let profile = get_attribute(a, "profile").unwrap();
+ let profile = profile_from_str(&profile).unwrap();
+ let (enums, commands) = parser.consume_two("enum", "command", "remove");
+
+ Remove {
+ profile: profile,
+ enums: enums,
+ commands: commands,
+ }
+ }
+}
+
+impl FromXml for Feature {
+ fn convert<P: Parse>(parser: &mut P, a: &[Attribute]) -> Feature {
+ debug!("Doing a FromXml on Feature");
+ let api = get_attribute(a, "api").unwrap();
+ let api = api_from_str(&api).unwrap().unwrap();
+ let name = get_attribute(a, "name").unwrap();
+ let number = get_attribute(a, "number").unwrap();
+
+ debug!("Found api = {}, name = {}, number = {}", api, name, number);
+
+ let (require, remove) = parser.consume_two("require", "remove", "feature");
+
+ Feature {
+ api: api,
+ name: name,
+ number: number,
+ requires: require,
+ removes: remove,
+ }
+ }
+}
+
+impl FromXml for Extension {
+ fn convert<P: Parse>(parser: &mut P, a: &[Attribute]) -> Extension {
+ debug!("Doing a FromXml on Extension");
+ let name = get_attribute(a, "name").unwrap();
+ let supported = get_attribute(a, "supported")
+ .unwrap()
+ .split('|')
+ .filter_map(|api| {
+ api_from_str(api).unwrap_or_else(|()| panic!("unsupported API `{}`", api))
+ })
+ .collect::<Vec<_>>();
+ let mut require = Vec::new();
+ loop {
+ match parser.next().unwrap() {
+ ParseEvent::Start(ref name, ref attributes) if name == "require" => {
+ require.push(FromXml::convert(parser, &attributes));
+ },
+ ParseEvent::End(ref name) if name == "extension" => break,
+ event => panic!("Unexpected message {:?}", event),
+ }
+ }
+
+ Extension {
+ name: name,
+ supported: supported,
+ requires: require,
+ }
+ }
+}
+
+impl FromXml for String {
+ fn convert<P: Parse>(_: &mut P, a: &[Attribute]) -> String {
+ get_attribute(a, "name").unwrap()
+ }
+}
+
+/// Converts a C style type definition to the Rust equivalent
+pub fn to_rust_ty<T: AsRef<str>>(ty: T) -> Cow<'static, str> {
+ let ty = match ty.as_ref().trim() {
+ // gl.xml types
+ "GLDEBUGPROC" => "types::GLDEBUGPROC",
+ "GLDEBUGPROCAMD" => "types::GLDEBUGPROCAMD",
+ "GLDEBUGPROCARB" => "types::GLDEBUGPROCARB",
+ "GLDEBUGPROCKHR" => "types::GLDEBUGPROCKHR",
+ "GLbitfield" => "types::GLbitfield",
+ "GLboolean" => "types::GLboolean",
+ "GLbyte" => "types::GLbyte",
+ "GLclampd" => "types::GLclampd",
+ "GLclampf" => "types::GLclampf",
+ "GLclampx" => "types::GLclampx",
+ "GLdouble" => "types::GLdouble",
+ "GLeglImageOES" => "types::GLeglImageOES",
+ "GLenum" => "types::GLenum",
+ "GLfixed" => "types::GLfixed",
+ "GLfloat" => "types::GLfloat",
+ "GLhalfNV" => "types::GLhalfNV",
+ "GLhandleARB" => "types::GLhandleARB",
+ "GLint" => "types::GLint",
+ "GLint64" => "types::GLint64",
+ "GLint64EXT" => "types::GLint64EXT",
+ "GLintptr" => "types::GLintptr",
+ "GLintptrARB" => "types::GLintptrARB",
+ "GLshort" => "types::GLshort",
+ "GLsizei" => "types::GLsizei",
+ "GLsizeiptr" => "types::GLsizeiptr",
+ "GLsizeiptrARB" => "types::GLsizeiptrARB",
+ "GLsync" => "types::GLsync",
+ "GLubyte" => "types::GLubyte",
+ "GLuint" => "types::GLuint",
+ "GLuint64" => "types::GLuint64",
+ "GLuint64EXT" => "types::GLuint64EXT",
+ "GLushort" => "types::GLushort",
+ "GLvdpauSurfaceNV" => "types::GLvdpauSurfaceNV",
+ "void" => "()",
+ "GLboolean *" => "*mut types::GLboolean",
+ "GLchar *" => "*mut types::GLchar",
+ "const GLchar*" => "*const types::GLchar",
+ "GLcharARB *" => "*mut types::GLcharARB",
+ "GLdouble *" => "*mut types::GLdouble",
+ "GLenum *" => "*mut types::GLenum",
+ "GLfixed *" => "*mut types::GLfixed",
+ "GLfloat *" => "*mut types::GLfloat",
+ "GLhandleARB *" => "*mut types::GLhandleARB",
+ "GLint *" => "*mut types::GLint",
+ "GLint64 *" => "*mut types::GLint64",
+ "GLint64EXT *" => "*mut types::GLint64EXT",
+ "GLsizei *" => "*mut types::GLsizei",
+ "GLubyte *" => "*mut types::GLubyte",
+ "GLuint *" => "*mut types::GLuint",
+ "GLuint [2]" => "*mut [types::GLuint; 2]",
+ "GLuint64 *" => "*mut types::GLuint64",
+ "GLuint64EXT *" => "*mut types::GLuint64EXT",
+ "GLushort *" => "*mut types::GLushort",
+ "GLvoid *" => "*mut types::GLvoid",
+ "GLvoid **" => "*const *mut types::GLvoid",
+ "void *" => "*mut __gl_imports::raw::c_void",
+ "void **" => "*const *mut __gl_imports::raw::c_void",
+ "const GLboolean *" => "*const types::GLboolean",
+ "const GLbyte *" => "*const types::GLbyte",
+ "const GLchar *" => "*const types::GLchar",
+ "const GLcharARB *" => "*const types::GLcharARB",
+ "const GLclampf *" => "*const types::GLclampf",
+ "const GLdouble *" => "*const types::GLdouble",
+ "const GLenum *" => "*const types::GLenum",
+ "const GLfixed *" => "*const types::GLfixed",
+ "const GLfloat" => "types::GLfloat",
+ "const GLfloat *" => "*const types::GLfloat",
+ "const GLhalfNV *" => "*const types::GLhalfNV",
+ "const GLint *" => "*const types::GLint",
+ "const GLint*" => "*const types::GLint",
+ "const GLint64 *" => "*const types::GLint64",
+ "const GLint64EXT *" => "*const types::GLint64EXT",
+ "const GLintptr *" => "*const types::GLintptr",
+ "const GLshort *" => "*const types::GLshort",
+ "const GLsizei*" |
+ "const GLsizei *" => "*const types::GLsizei",
+ "const GLsizeiptr *" => "*const types::GLsizeiptr",
+ "const GLubyte *" => "*const types::GLubyte",
+ "const GLuint *" => "*const types::GLuint",
+ "const GLuint64 *" => "*const types::GLuint64",
+ "const GLuint64EXT *" => "*const types::GLuint64EXT",
+ "const GLushort *" => "*const types::GLushort",
+ "const GLvdpauSurfaceNV *" => "*const types::GLvdpauSurfaceNV",
+ "const GLvoid *" => "*const types::GLvoid",
+ "const void*" |
+ "const void *" => "*const __gl_imports::raw::c_void",
+ "const void **" => "*const *const __gl_imports::raw::c_void",
+ "const void *const*" => "*const *const __gl_imports::raw::c_void",
+ "const GLboolean **" => "*const *const types::GLboolean",
+ "const GLchar **" => "*const *const types::GLchar",
+ "const GLcharARB **" => "*const *const types::GLcharARB",
+ "const GLvoid **" => "*const *const types::GLvoid",
+ "const GLchar *const*" => "*const *const types::GLchar",
+ "const GLvoid *const*" => "*const *const types::GLvoid",
+ "struct _cl_context *" => "*const types::_cl_context",
+ "struct _cl_event *" => "*const types::_cl_event",
+ "GLuint[2]" => "[Gluint; 2]",
+
+ // glx.xml types
+ "Bool" => "types::Bool",
+ "Colormap" => "types::Colormap",
+ "DMbuffer" => "types::DMbuffer",
+ "Font" => "types::Font",
+ "GLXContext" => "types::GLXContext",
+ "GLXContextID" => "types::GLXContextID",
+ "GLXDrawable" => "types::GLXDrawable",
+ "GLXFBConfig" => "types::GLXFBConfig",
+ "GLXFBConfigSGIX" => "types::GLXFBConfigSGIX",
+ "GLXPbuffer" => "types::GLXPbuffer",
+ "GLXPbufferSGIX" => "types::GLXPbufferSGIX",
+ "GLXPixmap" => "types::GLXPixmap",
+ "GLXVideoCaptureDeviceNV" => "types::GLXVideoCaptureDeviceNV",
+ "GLXVideoDeviceNV" => "types::GLXVideoDeviceNV",
+ "GLXVideoSourceSGIX" => "types::GLXVideoSourceSGIX",
+ "GLXWindow" => "types::GLXWindow",
+ // "GLboolean" => "types::GLboolean",
+ // "GLenum" => "types::GLenum",
+ // "GLint" => "types::GLint",
+ // "GLsizei" => "types::GLsizei",
+ // "GLuint" => "types::GLuint",
+ "Pixmap" => "types::Pixmap",
+ "Status" => "types::Status",
+ "VLNode" => "types::VLNode",
+ "VLPath" => "types::VLPath",
+ "VLServer" => "types::VLServer",
+ "Window" => "types::Window",
+ "__GLXextFuncPtr" => "types::__GLXextFuncPtr",
+ "const GLXContext" => "const types::GLXContext",
+ "float" => "__gl_imports::raw::c_float",
+ "int" => "__gl_imports::raw::c_int",
+ "int64_t" => "i64",
+ "unsigned int" => "__gl_imports::raw::c_uint",
+ "unsigned long" => "__gl_imports::raw::c_ulong",
+ // "void " => "()",
+ "DMparams *" => "*mut types::DMparams",
+ "Display *" => "*mut types::Display",
+ "GLXFBConfig *" => "*mut types::GLXFBConfig",
+ "GLXFBConfigSGIX *" => "*mut types::GLXFBConfigSGIX",
+ "GLXHyperpipeConfigSGIX *" => "*mut types::GLXHyperpipeConfigSGIX",
+ "GLXHyperpipeNetworkSGIX *" => "*mut types::GLXHyperpipeNetworkSGIX",
+ "GLXVideoCaptureDeviceNV *" => "*mut types::GLXVideoCaptureDeviceNV",
+ "GLXVideoDeviceNV *" => "*mut types::GLXVideoDeviceNV",
+ // "GLuint *" => "*mut types::GLuint",
+ "XVisualInfo *" => "*mut types::XVisualInfo",
+ // "const GLubyte *" => "*GLubyte",
+ "const char *" => "*const __gl_imports::raw::c_char",
+ "const int *" => "*const __gl_imports::raw::c_int",
+ // "const void *" => "*const __gl_imports::raw::c_void",
+ "int *" => "*mut __gl_imports::raw::c_int",
+ "int32_t *" => "*mut i32",
+ "int64_t *" => "*mut i64",
+ "long *" => "*mut __gl_imports::raw::c_long",
+ "unsigned int *" => "*mut __gl_imports::raw::c_uint",
+ "unsigned long *" => "*mut __gl_imports::raw::c_ulong",
+ // "void *" => "*mut __gl_imports::raw::c_void",
+
+ // wgl.xml types
+ "BOOL" => "types::BOOL",
+ "DWORD" => "types::DWORD",
+ "FLOAT" => "types::FLOAT",
+ // "GLbitfield" => "types::GLbitfield",
+ // "GLboolean" => "types::GLboolean",
+ // "GLenum" => "types::GLenum",
+ // "GLfloat" => "types::GLfloat",
+ // "GLint" => "types::GLint",
+ // "GLsizei" => "types::GLsizei",
+ // "GLuint" => "types::GLuint",
+ // "GLushort" => "types::GLushort",
+ "HANDLE" => "types::HANDLE",
+ "HDC" => "types::HDC",
+ "HENHMETAFILE" => "types::HENHMETAFILE",
+ "HGLRC" => "types::HGLRC",
+ "HGPUNV" => "types::HGPUNV",
+ "HPBUFFERARB" => "types::HPBUFFERARB",
+ "HPBUFFEREXT" => "types::HPBUFFEREXT",
+ "HPVIDEODEV" => "types::HPVIDEODEV",
+ "HVIDEOINPUTDEVICENV" => "types::HVIDEOINPUTDEVICENV",
+ "HVIDEOOUTPUTDEVICENV" => "types::HVIDEOOUTPUTDEVICENV",
+ "INT" => "types::INT",
+ "INT64" => "types::INT64",
+ "LPCSTR" => "types::LPCSTR",
+ "LPGLYPHMETRICSFLOAT" => "types::LPGLYPHMETRICSFLOAT",
+ "LPVOID" => "types::LPVOID",
+ "PGPU_DEVICE" => "types::PGPU_DEVICE",
+ "PROC" => "types::PROC",
+ "UINT" => "types::UINT",
+ "VOID" => "types::VOID",
+ // "int " => "__gl_imports::raw::c_int",
+ // "unsigned int " => "__gl_imports::raw::c_uint",
+ // "void " => "()",
+ "BOOL *" => "*mut types::BOOL",
+ "DWORD *" => "*mut types::DWORD",
+ "FLOAT *" => "*mut types::FLOAT",
+ // "GLuint *" => "*mut types::GLuint",
+ "HANDLE *" => "*mut types::HANDLE",
+ "HGPUNV *" => "*mut types::HGPUNV",
+ "HPVIDEODEV *" => "*mut types::HPVIDEODEV",
+ "HVIDEOINPUTDEVICENV *" => "*mut types::HVIDEOINPUTDEVICENV",
+ "HVIDEOOUTPUTDEVICENV *" => "*mut types::HVIDEOOUTPUTDEVICENV",
+ "INT32 *" => "*mut types::INT32",
+ "INT64 *" => "*mut types::INT64",
+ "UINT *" => "*mut types::UINT",
+ "USHORT *" => "*mut types::USHORT",
+ "const COLORREF *" => "*const types::COLORREF",
+ "const DWORD *" => "*const types::DWORD",
+ "const FLOAT *" => "*const types::FLOAT",
+ // "const GLushort *" => "*const types::GLushort",
+ "const HANDLE *" => "*const types::HANDLE",
+ "const HGPUNV *" => "*const types::HGPUNV",
+ "const LAYERPLANEDESCRIPTOR *" => "*const types::LAYERPLANEDESCRIPTOR",
+ "const LPVOID *" => "*const types::LPVOID",
+ "const PIXELFORMATDESCRIPTOR *" => "*const types::IXELFORMATDESCRIPTOR",
+ "const USHORT *" => "*const types::USHORT",
+ // "const char *" => "*const __gl_imports::raw::c_char",
+ // "const int *" => "*const __gl_imports::raw::c_int",
+ "float *" => "*mut __gl_imports::raw::c_float",
+ // "int *" => "*mut __gl_imports::raw::c_int",
+ // "unsigned long *" => "*mut __gl_imports::raw::c_ulong",
+ // "void *" => "*mut __gl_imports::raw::c_void",
+
+ // elx.xml types
+ "khronos_utime_nanoseconds_t" => "types::khronos_utime_nanoseconds_t",
+ "khronos_uint64_t" => "types::khronos_uint64_t",
+ "khronos_ssize_t" => "types::khronos_ssize_t",
+ "EGLNativeDisplayType" => "types::EGLNativeDisplayType",
+ "EGLNativePixmapType" => "types::EGLNativePixmapType",
+ "EGLNativeWindowType" => "types::EGLNativeWindowType",
+ "EGLint" => "types::EGLint",
+ "EGLint *" => "*mut types::EGLint",
+ "const EGLint *" => "*const types::EGLint",
+ "NativeDisplayType" => "types::NativeDisplayType",
+ "NativePixmapType" => "types::NativePixmapType",
+ "NativeWindowType" => "types::NativeWindowType",
+ //"Bool" => "types::Bool",
+ "EGLBoolean" => "types::EGLBoolean",
+ "EGLenum" => "types::EGLenum",
+ "EGLAttribKHR" => "types::EGLAttribKHR",
+ "EGLAttrib" => "types::EGLAttrib",
+ "EGLAttrib *" => "*mut types::EGLAttrib",
+ "const EGLAttrib *" => "*const types::EGLAttrib",
+ "const EGLattrib *" => "*const types::EGLAttrib", // Due to a typo in khronos_api/api_angle/scripts/egl_angle_ext.xml - see brendanzab/gl-rs#491
+ "EGLConfig" => "types::EGLConfig",
+ "EGLConfig *" => "*mut types::EGLConfig",
+ "EGLContext" => "types::EGLContext",
+ "EGLDeviceEXT" => "types::EGLDeviceEXT",
+ "EGLDisplay" => "types::EGLDisplay",
+ "EGLSurface" => "types::EGLSurface",
+ "EGLClientBuffer" => "types::EGLClientBuffer",
+ "__eglMustCastToProperFunctionPointerType" => {
+ "types::__eglMustCastToProperFunctionPointerType"
+ },
+ "EGLImageKHR" => "types::EGLImageKHR",
+ "EGLImage" => "types::EGLImage",
+ "EGLOutputLayerEXT" => "types::EGLOutputLayerEXT",
+ "EGLOutputPortEXT" => "types::EGLOutputPortEXT",
+ "EGLSyncKHR" => "types::EGLSyncKHR",
+ "EGLSync" => "types::EGLSync",
+ "EGLTimeKHR" => "types::EGLTimeKHR",
+ "EGLTime" => "types::EGLTime",
+ "EGLSyncNV" => "types::EGLSyncNV",
+ "EGLTimeNV" => "types::EGLTimeNV",
+ "EGLuint64NV" => "types::EGLuint64NV",
+ "EGLStreamKHR" => "types::EGLStreamKHR",
+ "EGLuint64KHR" => "types::EGLuint64KHR",
+ "EGLNativeFileDescriptorKHR" => "types::EGLNativeFileDescriptorKHR",
+ "EGLsizeiANDROID" => "types::EGLsizeiANDROID",
+ "EGLSetBlobFuncANDROID" => "types::EGLSetBlobFuncANDROID",
+ "EGLGetBlobFuncANDROID" => "types::EGLGetBlobFuncANDROID",
+ "EGLClientPixmapHI" => "types::EGLClientPixmapHI",
+ "struct EGLClientPixmapHI *" => "*const types::EGLClientPixmapHI",
+ "const EGLAttribKHR *" => "*const types::EGLAttribKHR",
+ "const EGLuint64KHR *" => "*const types::EGLuint64KHR",
+ "EGLAttribKHR *" => "*mut types::EGLAttribKHR",
+ "EGLDeviceEXT *" => "*mut types::EGLDeviceEXT",
+ "EGLNativeDisplayType *" => "*mut types::EGLNativeDisplayType",
+ "EGLNativePixmapType *" => "*mut types::EGLNativePixmapType",
+ "EGLNativeWindowType *" => "*mut types::EGLNativeWindowType",
+ "EGLOutputLayerEXT *" => "*mut types::EGLOutputLayerEXT",
+ "EGLTimeKHR *" => "*mut types::EGLTimeKHR",
+ "EGLOutputPortEXT *" => "*mut types::EGLOutputPortEXT",
+ "EGLuint64KHR *" => "*mut types::EGLuint64KHR",
+ "const struct AHardwareBuffer *" => "*const __gl_imports::raw::c_void", // humm
+
+ "GLeglClientBufferEXT" => "types::GLeglClientBufferEXT",
+ "GLVULKANPROCNV" => "types::GLVULKANPROCNV",
+ "EGLDEBUGPROCKHR" => "types::EGLDEBUGPROCKHR",
+ "EGLObjectKHR" => "types::EGLObjectKHR",
+ "EGLLabelKHR" => "types::EGLLabelKHR",
+ "EGLnsecsANDROID" => "types::EGLnsecsANDROID",
+ "EGLnsecsANDROID *" => "*mut types::EGLnsecsANDROID",
+ "EGLBoolean *" => "*mut types::EGLBoolean",
+
+ // failure
+ _ => panic!("Type conversion not implemented for `{}`", ty.as_ref()),
+ };
+
+ Cow::Borrowed(ty)
+}
+
+#[cfg(test)]
+mod tests {
+ mod underscore_numeric_prefix {
+ use registry::parse;
+
+ #[test]
+ fn test_numeric_prefix() {
+ assert_eq!(parse::underscore_numeric_prefix("3"), "_3");
+ assert_eq!(parse::underscore_numeric_prefix("123_FOO"), "_123_FOO");
+ }
+
+ #[test]
+ fn test_non_numeric_prefix() {
+ assert_eq!(parse::underscore_numeric_prefix(""), "");
+ assert_eq!(parse::underscore_numeric_prefix("A"), "A");
+ assert_eq!(parse::underscore_numeric_prefix("FOO"), "FOO");
+ }
+ }
+
+ mod underscore_keyword {
+ use registry::parse;
+
+ #[test]
+ fn test_keyword() {
+ assert_eq!(parse::underscore_keyword("in".to_string()), "in_");
+ assert_eq!(parse::underscore_keyword("ref".to_string()), "ref_");
+ assert_eq!(parse::underscore_keyword("type".to_string()), "type_");
+ }
+
+ #[test]
+ fn test_non_keyword() {
+ assert_eq!(parse::underscore_keyword("foo".to_string()), "foo");
+ assert_eq!(parse::underscore_keyword("bar".to_string()), "bar");
+ }
+ }
+ mod make_enum {
+ use registry::parse;
+
+ #[test]
+ fn test_cast_0() {
+ let e = parse::make_enum(
+ "FOO".to_string(),
+ None,
+ "((EGLint)-1)".to_string(),
+ Some("BAR".to_string()),
+ );
+ assert_eq!(e.ident, "FOO");
+ assert_eq!((&*e.ty, &*e.value), ("EGLint", "-1"));
+ assert_eq!(e.alias, Some("BAR".to_string()));
+ }
+
+ #[test]
+ fn test_cast_1() {
+ let e = parse::make_enum(
+ "FOO".to_string(),
+ None,
+ "((EGLint)(-1))".to_string(),
+ Some("BAR".to_string()),
+ );
+ assert_eq!(e.ident, "FOO");
+ assert_eq!((&*e.ty, &*e.value), ("EGLint", "(-1)"));
+ assert_eq!(e.alias, Some("BAR".to_string()));
+ }
+
+ #[test]
+ fn test_no_type() {
+ let e = parse::make_enum(
+ "FOO".to_string(),
+ None,
+ "value".to_string(),
+ Some("BAR".to_string()),
+ );
+ assert_eq!(e.ident, "FOO");
+ assert_eq!(e.value, "value");
+ assert_eq!(e.alias, Some("BAR".to_string()));
+ assert_eq!(e.ty, "GLenum");
+ assert_eq!(e.cast, false);
+ }
+
+ #[test]
+ fn test_u() {
+ let e = parse::make_enum(
+ "FOO".to_string(),
+ Some("u".to_string()),
+ String::new(),
+ None,
+ );
+ assert_eq!(e.ty, "GLuint");
+ }
+
+ #[test]
+ fn test_ull() {
+ let e = parse::make_enum(
+ "FOO".to_string(),
+ Some("ull".to_string()),
+ String::new(),
+ None,
+ );
+ assert_eq!(e.ty, "GLuint64");
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_unknown_type() {
+ parse::make_enum(
+ "FOO".to_string(),
+ Some("blargh".to_string()),
+ String::new(),
+ None,
+ );
+ }
+
+ #[test]
+ fn test_value_str() {
+ let e = parse::make_enum("FOO".to_string(), None, "\"hi\"".to_string(), None);
+ assert_eq!(e.ty, "&'static str");
+ }
+
+ #[test]
+ fn test_ident_true() {
+ let e = parse::make_enum("TRUE".to_string(), None, String::new(), None);
+ assert_eq!(e.ty, "GLboolean");
+ }
+
+ #[test]
+ fn test_ident_false() {
+ let e = parse::make_enum("FALSE".to_string(), None, String::new(), None);
+ assert_eq!(e.ty, "GLboolean");
+ }
+ }
+
+ mod make_egl_enum {
+ use registry::parse;
+
+ #[test]
+ fn test_cast_egl() {
+ let e = parse::make_egl_enum(
+ "FOO".to_string(),
+ None,
+ "EGL_CAST(EGLint,-1)".to_string(),
+ Some("BAR".to_string()),
+ );
+ assert_eq!(e.ident, "FOO");
+ assert_eq!((&*e.ty, &*e.value), ("EGLint", "-1"));
+ assert_eq!(e.alias, Some("BAR".to_string()));
+ }
+
+ #[test]
+ fn test_ident_true() {
+ let e = parse::make_egl_enum("TRUE".to_string(), None, "1234".to_string(), None);
+ assert_eq!(e.ty, "EGLBoolean");
+ }
+
+ #[test]
+ fn test_ident_false() {
+ let e = parse::make_egl_enum("FALSE".to_string(), None, "1234".to_string(), None);
+ assert_eq!(e.ty, "EGLBoolean");
+ }
+
+ #[test]
+ fn test_ull() {
+ let e = parse::make_egl_enum(
+ "FOO".to_string(),
+ Some("ull".to_string()),
+ "1234".to_string(),
+ None,
+ );
+ assert_eq!(e.ty, "EGLuint64KHR");
+ }
+
+ #[test]
+ fn test_negative_value() {
+ let e = parse::make_egl_enum("FOO".to_string(), None, "-1".to_string(), None);
+ assert_eq!(e.ty, "EGLint");
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_unknown_type() {
+ parse::make_egl_enum(
+ "FOO".to_string(),
+ Some("blargh".to_string()),
+ String::new(),
+ None,
+ );
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_unknown_value() {
+ parse::make_egl_enum("FOO".to_string(), None, "a".to_string(), None);
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_empty_value() {
+ parse::make_egl_enum("FOO".to_string(), None, String::new(), None);
+ }
+ }
+
+ mod parse_event {
+ mod from_xml {
+ use xml::attribute::OwnedAttribute;
+ use xml::common::XmlVersion;
+ use xml::name::OwnedName;
+ use xml::namespace::Namespace;
+ use xml::reader::XmlEvent;
+
+ use registry::parse::{Attribute, ParseEvent};
+
+ #[test]
+ fn test_start_event() {
+ let given = XmlEvent::StartElement {
+ name: OwnedName::local("element"),
+ attributes: vec![
+ OwnedAttribute::new(OwnedName::local("attr1"), "val1"),
+ OwnedAttribute::new(OwnedName::local("attr2"), "val2"),
+ ],
+ namespace: Namespace::empty(),
+ };
+ let expected = ParseEvent::Start(
+ "element".to_string(),
+ vec![
+ Attribute::new("attr1", "val1"),
+ Attribute::new("attr2", "val2"),
+ ],
+ );
+ assert_eq!(ParseEvent::from_xml(given), Some(expected));
+ }
+
+ #[test]
+ fn test_end_element() {
+ let given = XmlEvent::EndElement {
+ name: OwnedName::local("element"),
+ };
+ let expected = ParseEvent::End("element".to_string());
+ assert_eq!(ParseEvent::from_xml(given), Some(expected));
+ }
+
+ #[test]
+ fn test_characters() {
+ let given = XmlEvent::Characters("text".to_string());
+ let expected = ParseEvent::Text("text".to_string());
+ assert_eq!(ParseEvent::from_xml(given), Some(expected));
+ }
+
+ #[test]
+ fn test_start_document() {
+ let given = XmlEvent::StartDocument {
+ version: XmlVersion::Version10,
+ encoding: "".to_string(),
+ standalone: None,
+ };
+ assert_eq!(ParseEvent::from_xml(given), None);
+ }
+
+ #[test]
+ fn test_end_document() {
+ let given = XmlEvent::EndDocument;
+ assert_eq!(ParseEvent::from_xml(given), None);
+ }
+
+ #[test]
+ fn test_processing_instruction() {
+ let given = XmlEvent::ProcessingInstruction {
+ name: "".to_string(),
+ data: None,
+ };
+ assert_eq!(ParseEvent::from_xml(given), None);
+ }
+
+ #[test]
+ fn test_cdata() {
+ let given = XmlEvent::CData("CData".to_string());
+ assert_eq!(ParseEvent::from_xml(given), None);
+ }
+
+ #[test]
+ fn test_comment() {
+ let given = XmlEvent::Comment("Comment".to_string());
+ assert_eq!(ParseEvent::from_xml(given), None);
+ }
+
+ #[test]
+ fn test_whitespace() {
+ let given = XmlEvent::Whitespace("Whitespace".to_string());
+ assert_eq!(ParseEvent::from_xml(given), None);
+ }
+ }
+ }
+}