зеркало из https://github.com/mozilla/gecko-dev.git
1394 строки
51 KiB
Rust
1394 строки
51 KiB
Rust
// 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);
|
|
}
|
|
}
|
|
}
|
|
}
|