diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/gl_generator | |
parent | Initial commit. (diff) | |
download | firefox-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')
16 files changed, 3579 insertions, 0 deletions
diff --git a/third_party/rust/gl_generator/.cargo-checksum.json b/third_party/rust/gl_generator/.cargo-checksum.json new file mode 100644 index 0000000000..863d2f5ad9 --- /dev/null +++ b/third_party/rust/gl_generator/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"f586015aa2816b3c34d89f5e6a6539172efcd7f3ed055a0fab433ea83e2a0f0f","README.md":"52d8fee4681c879f2c964fd30e3faf0c907e8bf676eab7b44beab5c5bbd5c284","generators/debug_struct_gen.rs":"6fecccf8e57d4be93ea2657328d6e111ca44bc69542a5522cd7360d80ca64630","generators/global_gen.rs":"1696013af16bb92a3fa7cf3802a57ec6f7ba460322ede33aa2af30fc9911bd98","generators/mod.rs":"100a1da965bf11eaa9fad48a06c7856b60f48363a4a707e34ba97938bedae0b8","generators/static_gen.rs":"925a9401e27358a466baadfb660056a24394cf2fa21f5613e2d7f50ab8935e71","generators/static_struct_gen.rs":"eb08e6e59b0e0947c4ab263a0749efbb28430c5741634c413a2be011fcdad88f","generators/struct_gen.rs":"fa1bcda4501a597922be7c7ef4ad13738536a9c97529996671e264acd709c680","generators/templates/types/egl.rs":"d1785a30f1098e101302ba74ba4c22cf95ac44b17edf221dbb9d890f4bd635a2","generators/templates/types/gl.rs":"d72f91355febec875c40899a44c5575bd04993f7cf5c6e289eec872a2a161b20","generators/templates/types/glx.rs":"f444166d117b96afed2d8d13db6cd3369d6c59704f296e76202269f411bbd4a8","generators/templates/types/wgl.rs":"9d626e0959374c694c19a36d4dd34dae2f37acf3cb94e9bd4d242a16b41a970d","lib.rs":"6f47da878479b503b5202bda84ad8935607264ac03c0b68203109fad9cd479db","registry/mod.rs":"84eed5c113b322e5267b2b130987e6bb726b4e7c38ce50292cd6cc57b8e06994","registry/parse.rs":"5cb781082014f143b06ef7d3678f3c4ca59133a5732d4e136fd750b78fb9453f"},"package":"1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d"}
\ No newline at end of file diff --git a/third_party/rust/gl_generator/Cargo.toml b/third_party/rust/gl_generator/Cargo.toml new file mode 100644 index 0000000000..88c6a85a9b --- /dev/null +++ b/third_party/rust/gl_generator/Cargo.toml @@ -0,0 +1,39 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "gl_generator" +version = "0.14.0" +authors = ["Brendan Zabarauskas <bjzaba@yahoo.com.au>", "Corey Richardson", "Arseny Kapoulkine"] +description = "Code generators for creating bindings to the Khronos OpenGL APIs." +homepage = "https://github.com/brendanzab/gl-rs/" +documentation = "https://docs.rs/gl_generator" +readme = "README.md" +keywords = ["gl", "egl", "opengl", "khronos"] +categories = ["api-bindings", "rendering::graphics-api"] +license = "Apache-2.0" +repository = "https://github.com/brendanzab/gl-rs/" + +[lib] +name = "gl_generator" +path = "lib.rs" +[dependencies.khronos_api] +version = "3.1.0" + +[dependencies.log] +version = "0.4" + +[dependencies.xml-rs] +version = "0.8" + +[features] +unstable_generator_utils = [] diff --git a/third_party/rust/gl_generator/README.md b/third_party/rust/gl_generator/README.md new file mode 100644 index 0000000000..36d3e707b6 --- /dev/null +++ b/third_party/rust/gl_generator/README.md @@ -0,0 +1,165 @@ +# gl_generator + +[![Version](https://img.shields.io/crates/v/gl_generator.svg)](https://crates.io/crates/gl_generator) +[![License](https://img.shields.io/crates/l/gl_generator.svg)](https://github.com/brendanzab/gl-rs/blob/master/LICENSE) +[![Downloads](https://img.shields.io/crates/d/gl_generator.svg)](https://crates.io/crates/gl_generator) + +Code generators for creating bindings to the Khronos OpenGL APIs. + +## Usage + +If you need a specific version of OpenGL, or you need a different API +(OpenGL ES, EGL, WGL, GLX), or if you need certain extensions, you should use +the `gl_generator` plugin instead. + +See [gfx_gl](https://github.com/gfx-rs/gfx_gl) for an example of using a +custom gfx-rs loader for a project. + +Add this to your `Cargo.toml`: + +```toml +[build-dependencies] +gl_generator = "0.5.0" +``` + +Under the `[package]` section, add: + +```toml +build = "build.rs" +``` + +Create a `build.rs` to pull your specific version/API: + +```rust +extern crate gl_generator; + +use gl_generator::{Registry, Api, Profile, Fallbacks, GlobalGenerator}; +use std::env; +use std::fs::File; +use std::path::Path; + +fn main() { + let dest = env::var("OUT_DIR").unwrap(); + let mut file = File::create(&Path::new(&dest).join("bindings.rs")).unwrap(); + + Registry::new(Api::Gl, (4, 5), Profile::Core, Fallbacks::All, []) + .write_bindings(GlobalGenerator, &mut file) + .unwrap(); +} +``` + +Then use it like this: + +```rust +mod gl { + include!(concat!(env!("OUT_DIR"), "/bindings.rs")); +} + +/// Simple loading example +fn main() { + let window = ...; + + // Assuming `window` is GLFW: initialize, and make current + gl::load_with(|s| window.get_proc_address(s) as *const _); +} +``` + +The `build.rs` file will generate all the OpenGL functions in a file named, +`bindings.rs` plus all enumerations, and all types in the `types` submodule. + +## Generator types + +### Global generator + +The global generator is the one used by default by the `gl` crate. See above +for more details. + +### Struct generator + +The struct generator is a cleaner alternative to the global generator. + +The main difference is that you must call `gl::Gl::load_with` instead of +`gl::load_with`, and this functions returns a struct of type `Gl`. The OpenGL +functions are not static functions but member functions in this `Gl` struct. +This is important when the GL functions are associated with the current +context, as is true on Windows. + +The enumerations and types are still static and available in a similar way as +in the global generator. + +### Static generator + +The static generator generates plain old bindings. You don't need to load the +functions. + +This generator should only be used only if the platform you are compiling for +is guaranteed to support the requested API. Otherwise you will get a +compilation error. +For example, you can use it for WGL and OpenGL 1.1 on Windows or GLX and +OpenGL 1.3 on Linux, because Windows and Linux are guaranteed to provide +implementations for these APIs. + +You will need to manually provide the linkage. For example to use WGL or +OpenGL 1.1 on Windows, you will need to add +`#[link="OpenGL32.lib"] extern {}` somewhere in your code. + +### Custom Generators + +The `gl_generator` can be extended with custom generators. This is a niche +feature useful only in very rare cases. To create a custom generator, implement +the `gl_generator::Generator` trait. See the source of the +`gl_generator::generators` module for examples. + +Various utility functions are provided in the `generators` module, but the api +is unstable, so it has been placed behind a feature flag. In access these +functions, you will need to add the `"unstable_generator_utils"` feature to +your `Cargo.toml`: + +```toml +[build-dependencies.gl_generator] +version = "0.4.2" +features = ["unstable_generator_utils"] +``` + +## Extra features + +The global and struct generators will attempt to use fallbacks functions when +they are available. For example, if `glGenFramebuffers` cannot be loaded it will +also attempt to load `glGenFramebuffersEXT` as a fallback. + +## Changelog + +### v0.5.0 + +- Rename `Ns` to `API`, and expose at the top level +- Remove the need for clients to depend on the `khronos_api` crate by + determining the XML source based on the requested `API` +- Use a `(u8, u8)` instead of a string for the target version number +- Use a `Profile` enum instead of a string for the profile +- Remove unused fields from `Registry` +- Accept types satisfying `AsRef<[&str]>` for extension lists +- Separate parsing and generation stages in API +- Hide `registry::{Feature, Filter, Require, Remove, Extension}` types from the + public API +- Move `registry::{Fallbacks, Api, Profile}` types to top level module +- Remove `GlxOpcode::type` field +- Make `ty` fields on `Enum` and `Binding` take `Cow<'static, str>`s to reduce + allocations + +### v0.4.2 + +- Update crate metadata + +### v0.4.1 + +- Upgrade `khronos_api` to v1.0.0 + +### v0.4.0 + +- Upgrade `xml-rs` to v0.2.2 +- Use `raw::c_void` for `GLvoid` +- Remove `registry::{Group, EnumNs, CmdNs}` +- Remove `groups` field from `registry::Registry` +- Remove `is_safe` field from `registry::Cmd` +- Remove `comment` field from `registry::{Require, Remove, GlxOpcode}` +- Downgrade `khronos_api` to be a dev-dependency diff --git a/third_party/rust/gl_generator/generators/debug_struct_gen.rs b/third_party/rust/gl_generator/generators/debug_struct_gen.rs new file mode 100644 index 0000000000..98fbcef158 --- /dev/null +++ b/third_party/rust/gl_generator/generators/debug_struct_gen.rs @@ -0,0 +1,289 @@ +// 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. + +use registry::Registry; +use std::io; + +#[allow(missing_copy_implementations)] +pub struct DebugStructGenerator; + +impl super::Generator for DebugStructGenerator { + fn write<W>(&self, registry: &Registry, dest: &mut W) -> io::Result<()> + where + W: io::Write, + { + try!(write_header(dest)); + try!(write_type_aliases(registry, dest)); + try!(write_enums(registry, dest)); + try!(write_fnptr_struct_def(dest)); + try!(write_panicking_fns(registry, dest)); + try!(write_struct(registry, dest)); + try!(write_impl(registry, dest)); + Ok(()) + } +} + +/// Creates a `__gl_imports` module which contains all the external symbols that we need for the +/// bindings. +fn write_header<W>(dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + writeln!( + dest, + r#" + mod __gl_imports {{ + pub use std::mem; + pub use std::marker::Send; + pub use std::os::raw; + }} + "# + ) +} + +/// Creates a `types` module which contains all the type aliases. +/// +/// See also `generators::gen_types`. +fn write_type_aliases<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + try!(writeln!( + dest, + r#" + pub mod types {{ + #![allow(non_camel_case_types, non_snake_case, dead_code, missing_copy_implementations)] + "# + )); + + try!(super::gen_types(registry.api, dest)); + + writeln!(dest, "}}") +} + +/// Creates all the `<enum>` elements at the root of the bindings. +fn write_enums<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + for enm in ®istry.enums { + try!(super::gen_enum_item(enm, "types::", dest)); + } + + Ok(()) +} + +/// Creates a `FnPtr` structure which contains the store for a single binding. +fn write_fnptr_struct_def<W>(dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + writeln!( + dest, + " + #[allow(dead_code, missing_copy_implementations)] + #[derive(Clone)] + pub struct FnPtr {{ + /// The function pointer that will be used when calling the function. + f: *const __gl_imports::raw::c_void, + /// True if the pointer points to a real function, false if points to a `panic!` fn. + is_loaded: bool, + }} + + impl FnPtr {{ + /// Creates a `FnPtr` from a load attempt. + fn new(ptr: *const __gl_imports::raw::c_void) -> FnPtr {{ + if ptr.is_null() {{ + FnPtr {{ + f: missing_fn_panic as *const __gl_imports::raw::c_void, + is_loaded: false + }} + }} else {{ + FnPtr {{ f: ptr, is_loaded: true }} + }} + }} + + /// Returns `true` if the function has been successfully loaded. + /// + /// If it returns `false`, calling the corresponding function will fail. + #[inline] + #[allow(dead_code)] + pub fn is_loaded(&self) -> bool {{ + self.is_loaded + }} + }} + " + ) +} + +/// Creates a `panicking` module which contains one function per GL command. +/// +/// These functions are the mocks that are called if the real function could not be loaded. +fn write_panicking_fns<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + writeln!( + dest, + "#[inline(never)] + fn missing_fn_panic() -> ! {{ + panic!(\"{api} function was not loaded\") + }}", + api = registry.api + ) +} + +/// Creates a structure which stores all the `FnPtr` of the bindings. +/// +/// The name of the struct corresponds to the namespace. +fn write_struct<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + try!(writeln!( + dest, + " + #[allow(non_camel_case_types, non_snake_case, dead_code)] + #[derive(Clone)] + pub struct {api} {{", + api = super::gen_struct_name(registry.api) + )); + + for cmd in ®istry.cmds { + if let Some(v) = registry.aliases.get(&cmd.proto.ident) { + try!(writeln!(dest, "/// Fallbacks: {}", v.join(", "))); + } + try!(writeln!(dest, "pub {name}: FnPtr,", name = cmd.proto.ident)); + } + try!(writeln!(dest, "_priv: ()")); + + writeln!(dest, "}}") +} + +/// Creates the `impl` of the structure created by `write_struct`. +fn write_impl<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + try!(writeln!(dest, + "impl {api} {{ + /// Load each OpenGL symbol using a custom load function. This allows for the + /// use of functions like `glfwGetProcAddress` or `SDL_GL_GetProcAddress`. + /// + /// ~~~ignore + /// let gl = Gl::load_with(|s| glfw.get_proc_address(s)); + /// ~~~ + #[allow(dead_code, unused_variables)] + pub fn load_with<F>(mut loadfn: F) -> {api} where F: FnMut(&'static str) -> *const __gl_imports::raw::c_void {{ + #[inline(never)] + fn do_metaloadfn(loadfn: &mut dyn FnMut(&'static str) -> *const __gl_imports::raw::c_void, + symbol: &'static str, + symbols: &[&'static str]) + -> *const __gl_imports::raw::c_void {{ + let mut ptr = loadfn(symbol); + if ptr.is_null() {{ + for &sym in symbols {{ + ptr = loadfn(sym); + if !ptr.is_null() {{ break; }} + }} + }} + ptr + }} + let mut metaloadfn = |symbol: &'static str, symbols: &[&'static str]| {{ + do_metaloadfn(&mut loadfn, symbol, symbols) + }}; + {api} {{", + api = super::gen_struct_name(registry.api))); + + for cmd in ®istry.cmds { + try!(writeln!( + dest, + "{name}: FnPtr::new(metaloadfn(\"{symbol}\", &[{fallbacks}])),", + name = cmd.proto.ident, + symbol = super::gen_symbol_name(registry.api, &cmd.proto.ident), + fallbacks = match registry.aliases.get(&cmd.proto.ident) { + Some(fbs) => fbs + .iter() + .map(|name| format!("\"{}\"", super::gen_symbol_name(registry.api, &name))) + .collect::<Vec<_>>() + .join(", "), + None => format!(""), + }, + )) + } + try!(writeln!(dest, "_priv: ()")); + + try!(writeln!( + dest, + "}} + }}" + )); + + for cmd in ®istry.cmds { + let idents = super::gen_parameters(cmd, true, false); + let typed_params = super::gen_parameters(cmd, false, true); + let println = format!( + "println!(\"[OpenGL] {}({})\" {});", + cmd.proto.ident, + (0..idents.len()) + .map(|_| "{:?}".to_string()) + .collect::<Vec<_>>() + .join(", "), + idents + .iter() + .zip(typed_params.iter()) + .map(|(name, ty)| if ty.contains("GLDEBUGPROC") { + format!(", \"<callback>\"") + } else { + format!(", {}", name) + }).collect::<Vec<_>>() + .concat() + ); + + try!(writeln!(dest, + "#[allow(non_snake_case, unused_variables, dead_code)] + #[inline] pub unsafe fn {name}(&self, {params}) -> {return_suffix} {{ \ + {println} + let r = __gl_imports::mem::transmute::<_, extern \"system\" fn({typed_params}) -> {return_suffix}>\ + (self.{name}.f)({idents}); + {print_err} + r + }}", + name = cmd.proto.ident, + params = super::gen_parameters(cmd, true, true).join(", "), + typed_params = typed_params.join(", "), + return_suffix = cmd.proto.ty, + idents = idents.join(", "), + println = println, + print_err = if cmd.proto.ident != "GetError" && + registry + .cmds + .iter() + .find(|cmd| cmd.proto.ident == "GetError") + .is_some() { + format!(r#"match __gl_imports::mem::transmute::<_, extern "system" fn() -> u32> + (self.GetError.f)() {{ 0 => (), r => println!("[OpenGL] ^ GL error triggered: {{}}", r) }}"#) + } else { + format!("") + })) + } + + writeln!( + dest, + "}} + + unsafe impl __gl_imports::Send for {api} {{}}", + api = super::gen_struct_name(registry.api) + ) +} diff --git a/third_party/rust/gl_generator/generators/global_gen.rs b/third_party/rust/gl_generator/generators/global_gen.rs new file mode 100644 index 0000000000..82c4710979 --- /dev/null +++ b/third_party/rust/gl_generator/generators/global_gen.rs @@ -0,0 +1,309 @@ +// 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. + +use registry::Registry; +use std::io; + +#[allow(missing_copy_implementations)] +pub struct GlobalGenerator; + +impl super::Generator for GlobalGenerator { + fn write<W>(&self, registry: &Registry, dest: &mut W) -> io::Result<()> + where + W: io::Write, + { + try!(write_header(dest)); + try!(write_metaloadfn(dest)); + try!(write_type_aliases(registry, dest)); + try!(write_enums(registry, dest)); + try!(write_fns(registry, dest)); + try!(write_fnptr_struct_def(dest)); + try!(write_ptrs(registry, dest)); + try!(write_fn_mods(registry, dest)); + try!(write_panicking_fns(registry, dest)); + try!(write_load_fn(registry, dest)); + Ok(()) + } +} + +/// Creates a `__gl_imports` module which contains all the external symbols that we need for the +/// bindings. +fn write_header<W>(dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + writeln!( + dest, + r#" + mod __gl_imports {{ + pub use std::mem; + pub use std::os::raw; + }} + "# + ) +} + +/// Creates the metaloadfn function for fallbacks +fn write_metaloadfn<W>(dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + writeln!( + dest, + r#" + #[inline(never)] + fn metaloadfn(loadfn: &mut dyn FnMut(&'static str) -> *const __gl_imports::raw::c_void, + symbol: &'static str, + fallbacks: &[&'static str]) -> *const __gl_imports::raw::c_void {{ + let mut ptr = loadfn(symbol); + if ptr.is_null() {{ + for &sym in fallbacks {{ + ptr = loadfn(sym); + if !ptr.is_null() {{ break; }} + }} + }} + ptr + }} + "# + ) +} + +/// Creates a `types` module which contains all the type aliases. +/// +/// See also `generators::gen_types`. +fn write_type_aliases<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + try!(writeln!( + dest, + r#" + pub mod types {{ + #![allow(non_camel_case_types, non_snake_case, dead_code, missing_copy_implementations)] + "# + )); + + try!(super::gen_types(registry.api, dest)); + + writeln!( + dest, + " + }} + " + ) +} + +/// Creates all the `<enum>` elements at the root of the bindings. +fn write_enums<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + for enm in ®istry.enums { + try!(super::gen_enum_item(enm, "types::", dest)); + } + + Ok(()) +} + +/// Creates the functions corresponding to the GL commands. +/// +/// The function calls the corresponding function pointer stored in the `storage` module created +/// by `write_ptrs`. +fn write_fns<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + for cmd in ®istry.cmds { + if let Some(v) = registry.aliases.get(&cmd.proto.ident) { + try!(writeln!(dest, "/// Fallbacks: {}", v.join(", "))); + } + + try!(writeln!(dest, + "#[allow(non_snake_case, unused_variables, dead_code)] #[inline] + pub unsafe fn {name}({params}) -> {return_suffix} {{ \ + __gl_imports::mem::transmute::<_, extern \"system\" fn({typed_params}) -> {return_suffix}>\ + (storage::{name}.f)({idents}) \ + }}", + name = cmd.proto.ident, + params = super::gen_parameters(cmd, true, true).join(", "), + typed_params = super::gen_parameters(cmd, false, true).join(", "), + return_suffix = cmd.proto.ty, + idents = super::gen_parameters(cmd, true, false).join(", "), + )); + } + + Ok(()) +} + +/// Creates a `FnPtr` structure which contains the store for a single binding. +fn write_fnptr_struct_def<W>(dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + writeln!(dest, + " + #[allow(missing_copy_implementations)] + pub struct FnPtr {{ + /// The function pointer that will be used when calling the function. + f: *const __gl_imports::raw::c_void, + /// True if the pointer points to a real function, false if points to a `panic!` fn. + is_loaded: bool, + }} + + impl FnPtr {{ + /// Creates a `FnPtr` from a load attempt. + pub fn new(ptr: *const __gl_imports::raw::c_void) -> FnPtr {{ + if ptr.is_null() {{ + FnPtr {{ f: missing_fn_panic as *const __gl_imports::raw::c_void, is_loaded: false }} + }} else {{ + FnPtr {{ f: ptr, is_loaded: true }} + }} + }} + }} + ") +} + +/// Creates a `storage` module which contains a static `FnPtr` per GL command in the registry. +fn write_ptrs<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + try!(writeln!( + dest, + "mod storage {{ + #![allow(non_snake_case)] + #![allow(non_upper_case_globals)] + use super::__gl_imports::raw; + use super::FnPtr;" + )); + + for c in ®istry.cmds { + try!(writeln!( + dest, + "pub static mut {name}: FnPtr = FnPtr {{ + f: super::missing_fn_panic as *const raw::c_void, + is_loaded: false + }};", + name = c.proto.ident + )); + } + + writeln!(dest, "}}") +} + +/// Creates one module for each GL command. +/// +/// Each module contains `is_loaded` and `load_with` which interact with the `storage` module +/// created by `write_ptrs`. +fn write_fn_mods<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + for c in ®istry.cmds { + let fallbacks = match registry.aliases.get(&c.proto.ident) { + Some(v) => { + let names = v + .iter() + .map(|name| format!("\"{}\"", super::gen_symbol_name(registry.api, &name[..]))) + .collect::<Vec<_>>(); + format!("&[{}]", names.join(", ")) + }, + None => "&[]".to_string(), + }; + let fnname = &c.proto.ident[..]; + let symbol = super::gen_symbol_name(registry.api, &c.proto.ident[..]); + let symbol = &symbol[..]; + + try!(writeln!(dest, r##" + #[allow(non_snake_case)] + pub mod {fnname} {{ + use super::{{storage, metaloadfn}}; + use super::__gl_imports::raw; + use super::FnPtr; + + #[inline] + #[allow(dead_code)] + pub fn is_loaded() -> bool {{ + unsafe {{ storage::{fnname}.is_loaded }} + }} + + #[allow(dead_code)] + pub fn load_with<F>(mut loadfn: F) where F: FnMut(&'static str) -> *const raw::c_void {{ + unsafe {{ + storage::{fnname} = FnPtr::new(metaloadfn(&mut loadfn, "{symbol}", {fallbacks})) + }} + }} + }} + "##, fnname = fnname, fallbacks = fallbacks, symbol = symbol)); + } + + Ok(()) +} + +/// Creates a `missing_fn_panic` function. +/// +/// This function is the mock that is called if the real function could not be called. +fn write_panicking_fns<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + writeln!( + dest, + "#[inline(never)] + fn missing_fn_panic() -> ! {{ + panic!(\"{api} function was not loaded\") + }} + ", + api = registry.api + ) +} + +/// Creates the `load_with` function. +/// +/// The function calls `load_with` in each module created by `write_fn_mods`. +fn write_load_fn<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + try!(writeln!(dest, + " + /// Load each OpenGL symbol using a custom load function. This allows for the + /// use of functions like `glfwGetProcAddress` or `SDL_GL_GetProcAddress`. + /// ~~~ignore + /// gl::load_with(|s| glfw.get_proc_address(s)); + /// ~~~ + #[allow(dead_code)] + pub fn load_with<F>(mut loadfn: F) where F: FnMut(&'static str) -> *const __gl_imports::raw::c_void {{ + #[inline(never)] + fn inner(loadfn: &mut dyn FnMut(&'static str) -> *const __gl_imports::raw::c_void) {{ + ")); + + for c in ®istry.cmds { + try!(writeln!( + dest, + "{cmd_name}::load_with(&mut *loadfn);", + cmd_name = &c.proto.ident[..] + )); + } + + writeln!( + dest, + " + }} + + inner(&mut loadfn) + }} + " + ) +} diff --git a/third_party/rust/gl_generator/generators/mod.rs b/third_party/rust/gl_generator/generators/mod.rs new file mode 100644 index 0000000000..659d2ecaf4 --- /dev/null +++ b/third_party/rust/gl_generator/generators/mod.rs @@ -0,0 +1,119 @@ +// 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. + +use registry::{Cmd, Enum, Registry}; +use std::io; +use Api; + +pub mod debug_struct_gen; +pub mod global_gen; +pub mod static_gen; +pub mod static_struct_gen; +pub mod struct_gen; + +/// Trait for a bindings generator. +/// +/// See https://github.com/brendanzab/gl-rs/tree/master/gl_generator#generator-types +pub trait Generator { + /// Builds the GL bindings. + fn write<W>(&self, registry: &Registry, dest: &mut W) -> io::Result<()> + where + W: io::Write; +} + +pub fn gen_struct_name(api: Api) -> &'static str { + match api { + Api::Gl => "Gl", + Api::Glx => "Glx", + Api::Wgl => "Wgl", + Api::Egl => "Egl", + Api::GlCore => "GlCore", + Api::Gles1 => "Gles1", + Api::Gles2 => "Gles2", + Api::Glsc2 => "Glsc2", + } +} + +/// This function generates a `const name: type = value;` item. +pub fn gen_enum_item<W>(enm: &Enum, types_prefix: &str, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + writeln!(dest, + "#[allow(dead_code, non_upper_case_globals)] pub const {ident}: {types_prefix}{ty} = {value}{cast_suffix};", + ident = enm.ident, + types_prefix = if enm.ty == "&'static str" { "" } else { types_prefix }, + ty = enm.ty, + value = enm.value, + cast_suffix = match enm.cast { + true => format!(" as {}{}", types_prefix, enm.ty), + false => String::new(), + }, + ) +} + +/// Generates all the type aliases for a namespace. +/// +/// Aliases are either `pub type = ...` or `#[repr(C)] pub struct ... { ... }` and contain all the +/// things that we can't obtain from the XML files. +pub fn gen_types<W>(api: Api, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + if let Api::Egl = api { + try!(writeln!(dest, "{}", include_str!("templates/types/egl.rs"))); + return Ok(()); + } + + try!(writeln!(dest, "{}", include_str!("templates/types/gl.rs"))); + + match api { + Api::Glx => try!(writeln!(dest, "{}", include_str!("templates/types/glx.rs"))), + Api::Wgl => try!(writeln!(dest, "{}", include_str!("templates/types/wgl.rs"))), + _ => {}, + } + + Ok(()) +} + +/// Generates the list of Rust `Arg`s that a `Cmd` requires. +pub fn gen_parameters(cmd: &Cmd, with_idents: bool, with_types: bool) -> Vec<String> { + cmd.params + .iter() + .map(|binding| { + // returning + if with_idents && with_types { + format!("{}: {}", binding.ident, binding.ty) + } else if with_types { + format!("{}", binding.ty) + } else if with_idents { + format!("{}", binding.ident) + } else { + panic!() + } + }) + .collect() +} + +/// Generates the native symbol name of a `Cmd`. +/// +/// Example results: `"glClear"`, `"wglCreateContext"`, etc. +pub fn gen_symbol_name(api: Api, cmd: &str) -> String { + match api { + Api::Gl | Api::GlCore | Api::Gles1 | Api::Gles2 | Api::Glsc2 => format!("gl{}", cmd), + Api::Glx => format!("glX{}", cmd), + Api::Wgl => format!("wgl{}", cmd), + Api::Egl => format!("egl{}", cmd), + } +} diff --git a/third_party/rust/gl_generator/generators/static_gen.rs b/third_party/rust/gl_generator/generators/static_gen.rs new file mode 100644 index 0000000000..8d15de0103 --- /dev/null +++ b/third_party/rust/gl_generator/generators/static_gen.rs @@ -0,0 +1,115 @@ +// 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. + +use registry::Registry; +use std::io; + +#[allow(missing_copy_implementations)] +pub struct StaticGenerator; + +impl super::Generator for StaticGenerator { + fn write<W>(&self, registry: &Registry, dest: &mut W) -> io::Result<()> + where + W: io::Write, + { + try!(write_header(dest)); + try!(write_type_aliases(registry, dest)); + try!(write_enums(registry, dest)); + try!(write_fns(registry, dest)); + Ok(()) + } +} + +/// Creates a `__gl_imports` module which contains all the external symbols that we need for the +/// bindings. +fn write_header<W>(dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + writeln!( + dest, + r#" + mod __gl_imports {{ + pub use std::mem; + pub use std::os::raw; + }} + "# + ) +} + +/// Creates a `types` module which contains all the type aliases. +/// +/// See also `generators::gen_types`. +fn write_type_aliases<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + try!(writeln!( + dest, + r#" + pub mod types {{ + #![allow(non_camel_case_types, non_snake_case, dead_code, missing_copy_implementations)] + "# + )); + + try!(super::gen_types(registry.api, dest)); + + writeln!( + dest, + " + }} + " + ) +} + +/// Creates all the `<enum>` elements at the root of the bindings. +fn write_enums<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + for enm in ®istry.enums { + try!(super::gen_enum_item(enm, "types::", dest)); + } + + Ok(()) +} + +/// io::Writes all functions corresponding to the GL bindings. +/// +/// These are foreign functions, they don't have any content. +fn write_fns<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + try!(writeln!( + dest, + " + #[allow(non_snake_case, unused_variables, dead_code)] + extern \"system\" {{" + )); + + for cmd in ®istry.cmds { + try!(writeln!( + dest, + "#[link_name=\"{symbol}\"] + pub fn {name}({params}) -> {return_suffix};", + symbol = super::gen_symbol_name(registry.api, &cmd.proto.ident), + name = cmd.proto.ident, + params = super::gen_parameters(cmd, true, true).join(", "), + return_suffix = cmd.proto.ty, + )); + } + + writeln!(dest, "}}") +} diff --git a/third_party/rust/gl_generator/generators/static_struct_gen.rs b/third_party/rust/gl_generator/generators/static_struct_gen.rs new file mode 100644 index 0000000000..c03a3e09dd --- /dev/null +++ b/third_party/rust/gl_generator/generators/static_struct_gen.rs @@ -0,0 +1,165 @@ +// 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. + +use registry::Registry; +use std::io; + +#[allow(missing_copy_implementations)] +pub struct StaticStructGenerator; + +impl super::Generator for StaticStructGenerator { + fn write<W>(&self, registry: &Registry, dest: &mut W) -> io::Result<()> + where + W: io::Write, + { + try!(write_header(dest)); + try!(write_type_aliases(registry, dest)); + try!(write_enums(registry, dest)); + try!(write_struct(registry, dest)); + try!(write_impl(registry, dest)); + try!(write_fns(registry, dest)); + Ok(()) + } +} + +/// Creates a `__gl_imports` module which contains all the external symbols that we need for the +/// bindings. +fn write_header<W>(dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + writeln!( + dest, + r#" + mod __gl_imports {{ + pub use std::mem; + pub use std::os::raw; + }} + "# + ) +} + +/// Creates a `types` module which contains all the type aliases. +/// +/// See also `generators::gen_types`. +fn write_type_aliases<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + try!(writeln!( + dest, + r#" + pub mod types {{ + #![allow(non_camel_case_types, non_snake_case, dead_code, missing_copy_implementations)] + "# + )); + + try!(super::gen_types(registry.api, dest)); + + writeln!(dest, "}}") +} + +/// Creates all the `<enum>` elements at the root of the bindings. +fn write_enums<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + for enm in ®istry.enums { + try!(super::gen_enum_item(enm, "types::", dest)); + } + + Ok(()) +} + +/// Creates a stub structure. +/// +/// The name of the struct corresponds to the namespace. +fn write_struct<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + writeln!( + dest, + " + #[allow(non_camel_case_types, non_snake_case, dead_code)] + #[derive(Copy, Clone)] + pub struct {api};", + api = super::gen_struct_name(registry.api), + ) +} + +/// Creates the `impl` of the structure created by `write_struct`. +fn write_impl<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + try!(writeln!(dest, + "impl {api} {{ + /// Stub function. + #[allow(dead_code)] + pub fn load_with<F>(mut _loadfn: F) -> {api} where F: FnMut(&'static str) -> *const __gl_imports::raw::c_void {{ + {api} + }}", + api = super::gen_struct_name(registry.api), + )); + + for cmd in ®istry.cmds { + try!(writeln!( + dest, + "#[allow(non_snake_case)] + // #[allow(unused_variables)] + #[allow(dead_code)] + #[inline] + pub unsafe fn {name}(&self, {typed_params}) -> {return_suffix} {{ + {name}({idents}) + }}", + name = cmd.proto.ident, + typed_params = super::gen_parameters(cmd, true, true).join(", "), + return_suffix = cmd.proto.ty, + idents = super::gen_parameters(cmd, true, false).join(", "), + )); + } + + writeln!(dest, "}}") +} + +/// io::Writes all functions corresponding to the GL bindings. +/// +/// These are foreign functions, they don't have any content. +fn write_fns<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + try!(writeln!( + dest, + " + #[allow(non_snake_case)] + #[allow(unused_variables)] + #[allow(dead_code)] + extern \"system\" {{" + )); + + for cmd in ®istry.cmds { + try!(writeln!( + dest, + "#[link_name=\"{symbol}\"] fn {name}({params}) -> {return_suffix};", + symbol = super::gen_symbol_name(registry.api, &cmd.proto.ident), + name = cmd.proto.ident, + params = super::gen_parameters(cmd, true, true).join(", "), + return_suffix = cmd.proto.ty, + )); + } + + writeln!(dest, "}}") +} diff --git a/third_party/rust/gl_generator/generators/struct_gen.rs b/third_party/rust/gl_generator/generators/struct_gen.rs new file mode 100644 index 0000000000..6fcc3af00e --- /dev/null +++ b/third_party/rust/gl_generator/generators/struct_gen.rs @@ -0,0 +1,256 @@ +// 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. + +use registry::Registry; +use std::io; + +#[allow(missing_copy_implementations)] +pub struct StructGenerator; + +impl super::Generator for StructGenerator { + fn write<W>(&self, registry: &Registry, dest: &mut W) -> io::Result<()> + where + W: io::Write, + { + try!(write_header(dest)); + try!(write_type_aliases(registry, dest)); + try!(write_enums(registry, dest)); + try!(write_fnptr_struct_def(dest)); + try!(write_panicking_fns(registry, dest)); + try!(write_struct(registry, dest)); + try!(write_impl(registry, dest)); + Ok(()) + } +} + +/// Creates a `__gl_imports` module which contains all the external symbols that we need for the +/// bindings. +fn write_header<W>(dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + writeln!( + dest, + r#" + mod __gl_imports {{ + pub use std::mem; + pub use std::marker::Send; + pub use std::os::raw; + }} + "# + ) +} + +/// Creates a `types` module which contains all the type aliases. +/// +/// See also `generators::gen_types`. +fn write_type_aliases<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + try!(writeln!( + dest, + r#" + pub mod types {{ + #![allow(non_camel_case_types, non_snake_case, dead_code, missing_copy_implementations)] + "# + )); + + try!(super::gen_types(registry.api, dest)); + + writeln!(dest, "}}") +} + +/// Creates all the `<enum>` elements at the root of the bindings. +fn write_enums<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + for enm in ®istry.enums { + try!(super::gen_enum_item(enm, "types::", dest)); + } + + Ok(()) +} + +/// Creates a `FnPtr` structure which contains the store for a single binding. +fn write_fnptr_struct_def<W>(dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + writeln!( + dest, + " + #[allow(dead_code, missing_copy_implementations)] + #[derive(Clone)] + pub struct FnPtr {{ + /// The function pointer that will be used when calling the function. + f: *const __gl_imports::raw::c_void, + /// True if the pointer points to a real function, false if points to a `panic!` fn. + is_loaded: bool, + }} + + impl FnPtr {{ + /// Creates a `FnPtr` from a load attempt. + fn new(ptr: *const __gl_imports::raw::c_void) -> FnPtr {{ + if ptr.is_null() {{ + FnPtr {{ + f: missing_fn_panic as *const __gl_imports::raw::c_void, + is_loaded: false + }} + }} else {{ + FnPtr {{ f: ptr, is_loaded: true }} + }} + }} + + /// Returns `true` if the function has been successfully loaded. + /// + /// If it returns `false`, calling the corresponding function will fail. + #[inline] + #[allow(dead_code)] + pub fn is_loaded(&self) -> bool {{ + self.is_loaded + }} + }} + " + ) +} + +/// Creates a `panicking` module which contains one function per GL command. +/// +/// These functions are the mocks that are called if the real function could not be loaded. +fn write_panicking_fns<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + writeln!( + dest, + "#[inline(never)] + fn missing_fn_panic() -> ! {{ + panic!(\"{api} function was not loaded\") + }}", + api = registry.api + ) +} + +/// Creates a structure which stores all the `FnPtr` of the bindings. +/// +/// The name of the struct corresponds to the namespace. +fn write_struct<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + try!(writeln!( + dest, + " + #[allow(non_camel_case_types, non_snake_case, dead_code)] + #[derive(Clone)] + pub struct {api} {{", + api = super::gen_struct_name(registry.api) + )); + + for cmd in ®istry.cmds { + if let Some(v) = registry.aliases.get(&cmd.proto.ident) { + try!(writeln!(dest, "/// Fallbacks: {}", v.join(", "))); + } + try!(writeln!(dest, "pub {name}: FnPtr,", name = cmd.proto.ident)); + } + try!(writeln!(dest, "_priv: ()")); + + writeln!(dest, "}}") +} + +/// Creates the `impl` of the structure created by `write_struct`. +fn write_impl<W>(registry: &Registry, dest: &mut W) -> io::Result<()> +where + W: io::Write, +{ + try!(writeln!(dest, + "impl {api} {{ + /// Load each OpenGL symbol using a custom load function. This allows for the + /// use of functions like `glfwGetProcAddress` or `SDL_GL_GetProcAddress`. + /// + /// ~~~ignore + /// let gl = Gl::load_with(|s| glfw.get_proc_address(s)); + /// ~~~ + #[allow(dead_code, unused_variables)] + pub fn load_with<F>(mut loadfn: F) -> {api} where F: FnMut(&'static str) -> *const __gl_imports::raw::c_void {{ + #[inline(never)] + fn do_metaloadfn(loadfn: &mut dyn FnMut(&'static str) -> *const __gl_imports::raw::c_void, + symbol: &'static str, + symbols: &[&'static str]) + -> *const __gl_imports::raw::c_void {{ + let mut ptr = loadfn(symbol); + if ptr.is_null() {{ + for &sym in symbols {{ + ptr = loadfn(sym); + if !ptr.is_null() {{ break; }} + }} + }} + ptr + }} + let mut metaloadfn = |symbol: &'static str, symbols: &[&'static str]| {{ + do_metaloadfn(&mut loadfn, symbol, symbols) + }}; + {api} {{", + api = super::gen_struct_name(registry.api))); + + for cmd in ®istry.cmds { + try!(writeln!( + dest, + "{name}: FnPtr::new(metaloadfn(\"{symbol}\", &[{fallbacks}])),", + name = cmd.proto.ident, + symbol = super::gen_symbol_name(registry.api, &cmd.proto.ident), + fallbacks = match registry.aliases.get(&cmd.proto.ident) { + Some(fbs) => fbs + .iter() + .map(|name| format!("\"{}\"", super::gen_symbol_name(registry.api, &name))) + .collect::<Vec<_>>() + .join(", "), + None => format!(""), + }, + )) + } + + try!(writeln!(dest, "_priv: ()")); + + try!(writeln!( + dest, + "}} + }}" + )); + + for cmd in ®istry.cmds { + try!(writeln!(dest, + "#[allow(non_snake_case, unused_variables, dead_code)] + #[inline] pub unsafe fn {name}(&self, {params}) -> {return_suffix} {{ \ + __gl_imports::mem::transmute::<_, extern \"system\" fn({typed_params}) -> {return_suffix}>\ + (self.{name}.f)({idents}) \ + }}", + name = cmd.proto.ident, + params = super::gen_parameters(cmd, true, true).join(", "), + typed_params = super::gen_parameters(cmd, false, true).join(", "), + return_suffix = cmd.proto.ty, + idents = super::gen_parameters(cmd, true, false).join(", "), + )) + } + + writeln!( + dest, + "}} + + unsafe impl __gl_imports::Send for {api} {{}}", + api = super::gen_struct_name(registry.api) + ) +} diff --git a/third_party/rust/gl_generator/generators/templates/types/egl.rs b/third_party/rust/gl_generator/generators/templates/types/egl.rs new file mode 100644 index 0000000000..877638ab98 --- /dev/null +++ b/third_party/rust/gl_generator/generators/templates/types/egl.rs @@ -0,0 +1,70 @@ +// platform-specific aliases are unknown +// IMPORTANT: these are alises to the same level of the bindings +// the values must be defined by the user +#[allow(dead_code)] +pub type khronos_utime_nanoseconds_t = super::khronos_utime_nanoseconds_t; +#[allow(dead_code)] +pub type khronos_uint64_t = super::khronos_uint64_t; +#[allow(dead_code)] +pub type khronos_ssize_t = super::khronos_ssize_t; +pub type EGLNativeDisplayType = super::EGLNativeDisplayType; +#[allow(dead_code)] +pub type EGLNativePixmapType = super::EGLNativePixmapType; +#[allow(dead_code)] +pub type EGLNativeWindowType = super::EGLNativeWindowType; +pub type EGLint = super::EGLint; +#[allow(dead_code)] +pub type NativeDisplayType = super::NativeDisplayType; +#[allow(dead_code)] +pub type NativePixmapType = super::NativePixmapType; +#[allow(dead_code)] +pub type NativeWindowType = super::NativeWindowType; + +// EGL alises +pub type Bool = EGLBoolean; // TODO: not sure +pub type EGLBoolean = super::__gl_imports::raw::c_uint; +pub type EGLenum = super::__gl_imports::raw::c_uint; +pub type EGLAttribKHR = isize; +pub type EGLAttrib = isize; +pub type EGLConfig = *const super::__gl_imports::raw::c_void; +pub type EGLContext = *const super::__gl_imports::raw::c_void; +pub type EGLDeviceEXT = *const super::__gl_imports::raw::c_void; +pub type EGLDisplay = *const super::__gl_imports::raw::c_void; +pub type EGLSurface = *const super::__gl_imports::raw::c_void; +pub type EGLClientBuffer = *const super::__gl_imports::raw::c_void; +pub enum __eglMustCastToProperFunctionPointerType_fn {} +pub type __eglMustCastToProperFunctionPointerType = + *mut __eglMustCastToProperFunctionPointerType_fn; +pub type EGLImageKHR = *const super::__gl_imports::raw::c_void; +pub type EGLImage = *const super::__gl_imports::raw::c_void; +pub type EGLOutputLayerEXT = *const super::__gl_imports::raw::c_void; +pub type EGLOutputPortEXT = *const super::__gl_imports::raw::c_void; +pub type EGLSyncKHR = *const super::__gl_imports::raw::c_void; +pub type EGLSync = *const super::__gl_imports::raw::c_void; +pub type EGLTimeKHR = khronos_utime_nanoseconds_t; +pub type EGLTime = khronos_utime_nanoseconds_t; +pub type EGLSyncNV = *const super::__gl_imports::raw::c_void; +pub type EGLTimeNV = khronos_utime_nanoseconds_t; +pub type EGLuint64NV = khronos_utime_nanoseconds_t; +pub type EGLStreamKHR = *const super::__gl_imports::raw::c_void; +pub type EGLuint64KHR = khronos_uint64_t; +pub type EGLNativeFileDescriptorKHR = super::__gl_imports::raw::c_int; +pub type EGLsizeiANDROID = khronos_ssize_t; +pub type EGLSetBlobFuncANDROID = extern "system" fn(*const super::__gl_imports::raw::c_void, + EGLsizeiANDROID, + *const super::__gl_imports::raw::c_void, + EGLsizeiANDROID) + -> (); +pub type EGLGetBlobFuncANDROID = extern "system" fn(*const super::__gl_imports::raw::c_void, + EGLsizeiANDROID, + *mut super::__gl_imports::raw::c_void, + EGLsizeiANDROID) + -> EGLsizeiANDROID; + +#[repr(C)] +pub struct EGLClientPixmapHI { + pData: *const super::__gl_imports::raw::c_void, + iWidth: EGLint, + iHeight: EGLint, + iStride: EGLint, +} diff --git a/third_party/rust/gl_generator/generators/templates/types/gl.rs b/third_party/rust/gl_generator/generators/templates/types/gl.rs new file mode 100644 index 0000000000..90e4620104 --- /dev/null +++ b/third_party/rust/gl_generator/generators/templates/types/gl.rs @@ -0,0 +1,108 @@ +// Common types from OpenGL 1.1 +pub type GLenum = super::__gl_imports::raw::c_uint; +pub type GLboolean = super::__gl_imports::raw::c_uchar; +pub type GLbitfield = super::__gl_imports::raw::c_uint; +pub type GLvoid = super::__gl_imports::raw::c_void; +pub type GLbyte = super::__gl_imports::raw::c_char; +pub type GLshort = super::__gl_imports::raw::c_short; +pub type GLint = super::__gl_imports::raw::c_int; +pub type GLclampx = super::__gl_imports::raw::c_int; +pub type GLubyte = super::__gl_imports::raw::c_uchar; +pub type GLushort = super::__gl_imports::raw::c_ushort; +pub type GLuint = super::__gl_imports::raw::c_uint; +pub type GLsizei = super::__gl_imports::raw::c_int; +pub type GLfloat = super::__gl_imports::raw::c_float; +pub type GLclampf = super::__gl_imports::raw::c_float; +pub type GLdouble = super::__gl_imports::raw::c_double; +pub type GLclampd = super::__gl_imports::raw::c_double; +pub type GLeglImageOES = *const super::__gl_imports::raw::c_void; +pub type GLchar = super::__gl_imports::raw::c_char; +pub type GLcharARB = super::__gl_imports::raw::c_char; + +#[cfg(target_os = "macos")] +pub type GLhandleARB = *const super::__gl_imports::raw::c_void; +#[cfg(not(target_os = "macos"))] +pub type GLhandleARB = super::__gl_imports::raw::c_uint; + +pub type GLhalfARB = super::__gl_imports::raw::c_ushort; +pub type GLhalf = super::__gl_imports::raw::c_ushort; + +// Must be 32 bits +pub type GLfixed = GLint; + +pub type GLintptr = isize; +pub type GLsizeiptr = isize; +pub type GLint64 = i64; +pub type GLuint64 = u64; +pub type GLintptrARB = isize; +pub type GLsizeiptrARB = isize; +pub type GLint64EXT = i64; +pub type GLuint64EXT = u64; + +pub enum __GLsync {} +pub type GLsync = *const __GLsync; + +// compatible with OpenCL cl_context +pub enum _cl_context {} +pub enum _cl_event {} + +pub type GLDEBUGPROC = Option<extern "system" fn(source: GLenum, + gltype: GLenum, + id: GLuint, + severity: GLenum, + length: GLsizei, + message: *const GLchar, + userParam: *mut super::__gl_imports::raw::c_void)>; +pub type GLDEBUGPROCARB = Option<extern "system" fn(source: GLenum, + gltype: GLenum, + id: GLuint, + severity: GLenum, + length: GLsizei, + message: *const GLchar, + userParam: *mut super::__gl_imports::raw::c_void)>; +pub type GLDEBUGPROCKHR = Option<extern "system" fn(source: GLenum, + gltype: GLenum, + id: GLuint, + severity: GLenum, + length: GLsizei, + message: *const GLchar, + userParam: *mut super::__gl_imports::raw::c_void)>; + +// GLES 1 types +// "pub type GLclampx = i32;", + +// GLES 1/2 types (tagged for GLES 1) +// "pub type GLbyte = i8;", +// "pub type GLubyte = u8;", +// "pub type GLfloat = GLfloat;", +// "pub type GLclampf = GLfloat;", +// "pub type GLfixed = i32;", +// "pub type GLint64 = i64;", +// "pub type GLuint64 = u64;", +// "pub type GLintptr = intptr_t;", +// "pub type GLsizeiptr = ssize_t;", + +// GLES 1/2 types (tagged for GLES 2 - attribute syntax is limited) +// "pub type GLbyte = i8;", +// "pub type GLubyte = u8;", +// "pub type GLfloat = GLfloat;", +// "pub type GLclampf = GLfloat;", +// "pub type GLfixed = i32;", +// "pub type GLint64 = i64;", +// "pub type GLuint64 = u64;", +// "pub type GLint64EXT = i64;", +// "pub type GLuint64EXT = u64;", +// "pub type GLintptr = intptr_t;", +// "pub type GLsizeiptr = ssize_t;", + +// GLES 2 types (none currently) + +// Vendor extension types +pub type GLDEBUGPROCAMD = Option<extern "system" fn(id: GLuint, + category: GLenum, + severity: GLenum, + length: GLsizei, + message: *const GLchar, + userParam: *mut super::__gl_imports::raw::c_void)>; +pub type GLhalfNV = super::__gl_imports::raw::c_ushort; +pub type GLvdpauSurfaceNV = GLintptr; diff --git a/third_party/rust/gl_generator/generators/templates/types/glx.rs b/third_party/rust/gl_generator/generators/templates/types/glx.rs new file mode 100644 index 0000000000..b0078da0a1 --- /dev/null +++ b/third_party/rust/gl_generator/generators/templates/types/glx.rs @@ -0,0 +1,128 @@ +pub type XID = super::__gl_imports::raw::c_ulong; +pub type Bool = super::__gl_imports::raw::c_int; // Not sure if this is correct... +pub enum Display {} + +pub type Font = XID; +pub type Pixmap = XID; +pub enum Visual {} // TODO: not sure +pub type VisualID = super::__gl_imports::raw::c_ulong; // TODO: not sure +pub type Window = XID; +pub type GLXFBConfigID = XID; +pub type GLXFBConfig = *const super::__gl_imports::raw::c_void; +pub type GLXContextID = XID; +pub type GLXContext = *const super::__gl_imports::raw::c_void; +pub type GLXPixmap = XID; +pub type GLXDrawable = XID; +pub type GLXWindow = XID; +pub type GLXPbuffer = XID; +pub enum __GLXextFuncPtr_fn {} +pub type __GLXextFuncPtr = *mut __GLXextFuncPtr_fn; +pub type GLXVideoCaptureDeviceNV = XID; +pub type GLXVideoDeviceNV = super::__gl_imports::raw::c_int; +pub type GLXVideoSourceSGIX = XID; +pub type GLXFBConfigIDSGIX = XID; +pub type GLXFBConfigSGIX = *const super::__gl_imports::raw::c_void; +pub type GLXPbufferSGIX = XID; + +#[repr(C)] +pub struct XVisualInfo { + pub visual: *mut Visual, + pub visualid: VisualID, + pub screen: super::__gl_imports::raw::c_int, + pub depth: super::__gl_imports::raw::c_int, + pub class: super::__gl_imports::raw::c_int, + pub red_mask: super::__gl_imports::raw::c_ulong, + pub green_mask: super::__gl_imports::raw::c_ulong, + pub blue_mask: super::__gl_imports::raw::c_ulong, + pub colormap_size: super::__gl_imports::raw::c_int, + pub bits_per_rgb: super::__gl_imports::raw::c_int, +} + +#[repr(C)] +pub struct GLXPbufferClobberEvent { + pub event_type: super::__gl_imports::raw::c_int, // GLX_DAMAGED or GLX_SAVED + pub draw_type: super::__gl_imports::raw::c_int, // GLX_WINDOW or GLX_PBUFFER + pub serial: super::__gl_imports::raw::c_ulong, // # of last request processed by server + pub send_event: Bool, // true if this came for SendEvent request + pub display: *const Display, // display the event was read from + pub drawable: GLXDrawable, // XID of Drawable + pub buffer_mask: super::__gl_imports::raw::c_uint, // mask indicating which buffers are affected + pub aux_buffer: super::__gl_imports::raw::c_uint, // which aux buffer was affected + pub x: super::__gl_imports::raw::c_int, + pub y: super::__gl_imports::raw::c_int, + pub width: super::__gl_imports::raw::c_int, + pub height: super::__gl_imports::raw::c_int, + pub count: super::__gl_imports::raw::c_int, // if nonzero, at least this many more +} + +#[repr(C)] +pub struct GLXBufferSwapComplete { + pub type_: super::__gl_imports::raw::c_int, + pub serial: super::__gl_imports::raw::c_ulong, // # of last request processed by server + pub send_event: Bool, // true if this came from a SendEvent request + pub display: *const Display, // Display the event was read from + pub drawable: GLXDrawable, // drawable on which event was requested in event mask + pub event_type: super::__gl_imports::raw::c_int, + pub ust: i64, + pub msc: i64, + pub sbc: i64, +} + +// typedef union __GLXEvent { +// GLXPbufferClobberEvent glxpbufferclobber; +// GLXBufferSwapComplete glxbufferswapcomplete; +// long pad[24]; +// } + +#[repr(C)] +pub struct GLXBufferClobberEventSGIX { + pub type_: super::__gl_imports::raw::c_int, + pub serial: super::__gl_imports::raw::c_ulong, // # of last request processed by server + pub send_event: Bool, // true if this came for SendEvent request + pub display: *const Display, // display the event was read from + pub drawable: GLXDrawable, // i.d. of Drawable + pub event_type: super::__gl_imports::raw::c_int, // GLX_DAMAGED_SGIX or GLX_SAVED_SGIX + pub draw_type: super::__gl_imports::raw::c_int, // GLX_WINDOW_SGIX or GLX_PBUFFER_SGIX + pub mask: super::__gl_imports::raw::c_uint, // mask indicating which buffers are affected + pub x: super::__gl_imports::raw::c_int, + pub y: super::__gl_imports::raw::c_int, + pub width: super::__gl_imports::raw::c_int, + pub height: super::__gl_imports::raw::c_int, + pub count: super::__gl_imports::raw::c_int, // if nonzero, at least this many more +} + +#[repr(C)] +pub struct GLXHyperpipeNetworkSGIX { + pub pipeName: [super::__gl_imports::raw::c_char; 80], // Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] + pub networkId: super::__gl_imports::raw::c_int, +} + +#[repr(C)] +pub struct GLXHyperpipeConfigSGIX { + pub pipeName: [super::__gl_imports::raw::c_char; 80], // Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] + pub channel: super::__gl_imports::raw::c_int, + pub participationType: super::__gl_imports::raw::c_uint, + pub timeSlice: super::__gl_imports::raw::c_int, +} + +#[repr(C)] +pub struct GLXPipeRect { + pub pipeName: [super::__gl_imports::raw::c_char; 80], // Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] + pub srcXOrigin: super::__gl_imports::raw::c_int, + pub srcYOrigin: super::__gl_imports::raw::c_int, + pub srcWidth: super::__gl_imports::raw::c_int, + pub srcHeight: super::__gl_imports::raw::c_int, + pub destXOrigin: super::__gl_imports::raw::c_int, + pub destYOrigin: super::__gl_imports::raw::c_int, + pub destWidth: super::__gl_imports::raw::c_int, + pub destHeight: super::__gl_imports::raw::c_int, +} + +#[repr(C)] +pub struct GLXPipeRectLimits { + pub pipeName: [super::__gl_imports::raw::c_char; 80], // Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] + pub XOrigin: super::__gl_imports::raw::c_int, + pub YOrigin: super::__gl_imports::raw::c_int, + pub maxHeight: super::__gl_imports::raw::c_int, + pub maxWidth: super::__gl_imports::raw::c_int, +} diff --git a/third_party/rust/gl_generator/generators/templates/types/wgl.rs b/third_party/rust/gl_generator/generators/templates/types/wgl.rs new file mode 100644 index 0000000000..a376d4fa05 --- /dev/null +++ b/third_party/rust/gl_generator/generators/templates/types/wgl.rs @@ -0,0 +1,139 @@ +// From WinNT.h + +pub type CHAR = super::__gl_imports::raw::c_char; +pub type HANDLE = PVOID; +pub type LONG = super::__gl_imports::raw::c_long; +pub type LPCSTR = *const super::__gl_imports::raw::c_char; +pub type VOID = (); +// #define DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name +pub type HPBUFFERARB = *const super::__gl_imports::raw::c_void; +pub type HPBUFFEREXT = *const super::__gl_imports::raw::c_void; +pub type HVIDEOOUTPUTDEVICENV = *const super::__gl_imports::raw::c_void; +pub type HPVIDEODEV = *const super::__gl_imports::raw::c_void; +pub type HPGPUNV = *const super::__gl_imports::raw::c_void; +pub type HGPUNV = *const super::__gl_imports::raw::c_void; +pub type HVIDEOINPUTDEVICENV = *const super::__gl_imports::raw::c_void; + +// From Windef.h + +pub type BOOL = super::__gl_imports::raw::c_int; +pub type BYTE = super::__gl_imports::raw::c_uchar; +pub type COLORREF = DWORD; +pub type FLOAT = super::__gl_imports::raw::c_float; +pub type HDC = HANDLE; +pub type HENHMETAFILE = HANDLE; +pub type HGLRC = *const super::__gl_imports::raw::c_void; +pub type INT = super::__gl_imports::raw::c_int; +pub type PVOID = *const super::__gl_imports::raw::c_void; +pub type LPVOID = *const super::__gl_imports::raw::c_void; +pub enum __PROC_fn {} +pub type PROC = *mut __PROC_fn; + +#[repr(C)] +pub struct RECT { + left: LONG, + top: LONG, + right: LONG, + bottom: LONG, +} + +pub type UINT = super::__gl_imports::raw::c_uint; +pub type USHORT = super::__gl_imports::raw::c_ushort; +pub type WORD = super::__gl_imports::raw::c_ushort; + +// From BaseTsd.h + +pub type INT32 = i32; +pub type INT64 = i64; + +// From IntSafe.h + +pub type DWORD = super::__gl_imports::raw::c_ulong; + +// From Wingdi.h + +#[repr(C)] +pub struct POINTFLOAT { + pub x: FLOAT, + pub y: FLOAT, +} + +#[repr(C)] +pub struct GLYPHMETRICSFLOAT { + pub gmfBlackBoxX: FLOAT, + pub gmfBlackBoxY: FLOAT, + pub gmfptGlyphOrigin: POINTFLOAT, + pub gmfCellIncX: FLOAT, + pub gmfCellIncY: FLOAT, +} +pub type LPGLYPHMETRICSFLOAT = *const GLYPHMETRICSFLOAT; + +#[repr(C)] +pub struct LAYERPLANEDESCRIPTOR { + pub nSize: WORD, + pub nVersion: WORD, + pub dwFlags: DWORD, + pub iPixelType: BYTE, + pub cColorBits: BYTE, + pub cRedBits: BYTE, + pub cRedShift: BYTE, + pub cGreenBits: BYTE, + pub cGreenShift: BYTE, + pub cBlueBits: BYTE, + pub cBlueShift: BYTE, + pub cAlphaBits: BYTE, + pub cAlphaShift: BYTE, + pub cAccumBits: BYTE, + pub cAccumRedBits: BYTE, + pub cAccumGreenBits: BYTE, + pub cAccumBlueBits: BYTE, + pub cAccumAlphaBits: BYTE, + pub cDepthBits: BYTE, + pub cStencilBits: BYTE, + pub cAuxBuffers: BYTE, + pub iLayerType: BYTE, + pub bReserved: BYTE, + pub crTransparent: COLORREF, +} + +#[repr(C)] +pub struct PIXELFORMATDESCRIPTOR { + pub nSize: WORD, + pub nVersion: WORD, + pub dwFlags: DWORD, + pub iPixelType: BYTE, + pub cColorBits: BYTE, + pub cRedBits: BYTE, + pub cRedShift: BYTE, + pub cGreenBits: BYTE, + pub cGreenShift: BYTE, + pub cBlueBits: BYTE, + pub cBlueShift: BYTE, + pub cAlphaBits: BYTE, + pub cAlphaShift: BYTE, + pub cAccumBits: BYTE, + pub cAccumRedBits: BYTE, + pub cAccumGreenBits: BYTE, + pub cAccumBlueBits: BYTE, + pub cAccumAlphaBits: BYTE, + pub cDepthBits: BYTE, + pub cStencilBits: BYTE, + pub cAuxBuffers: BYTE, + pub iLayerType: BYTE, + pub bReserved: BYTE, + pub dwLayerMask: DWORD, + pub dwVisibleMask: DWORD, + pub dwDamageMask: DWORD, +} + +#[repr(C)] +pub struct _GPU_DEVICE { + cb: DWORD, + DeviceName: [CHAR; 32], + DeviceString: [CHAR; 128], + Flags: DWORD, + rcVirtualScreen: RECT, +} + +pub struct GPU_DEVICE(_GPU_DEVICE); +pub struct PGPU_DEVICE(*const _GPU_DEVICE); diff --git a/third_party/rust/gl_generator/lib.rs b/third_party/rust/gl_generator/lib.rs new file mode 100644 index 0000000000..ebeb07be25 --- /dev/null +++ b/third_party/rust/gl_generator/lib.rs @@ -0,0 +1,81 @@ +// 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. + +//! An OpenGL bindings generator. It defines a function named `generate_bindings` which can be +//! used to generate all constants and functions of a given OpenGL version. +//! +//! # Example +//! +//! In `build.rs`: +//! +//! ```no_run +//! extern crate gl_generator; +//! +//! use gl_generator::{Registry, Api, Profile, Fallbacks, GlobalGenerator}; +//! use std::env; +//! use std::fs::File; +//! use std::path::Path; +//! +//! fn main() { +//! let dest = env::var("OUT_DIR").unwrap(); +//! let mut file = File::create(&Path::new(&dest).join("gl_bindings.rs")).unwrap(); +//! +//! Registry::new(Api::Gl, (4, 5), Profile::Core, Fallbacks::All, []) +//! .write_bindings(GlobalGenerator, &mut file) +//! .unwrap(); +//! } +//! ``` +//! +//! In your project: +//! +//! ```ignore +//! include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs")); +//! ``` +//! +//! # About EGL +//! +//! When you generate bindings for EGL, the following platform-specific types must be declared +//! *at the same level where you include the bindings*: +//! +//! - `khronos_utime_nanoseconds_t` +//! - `khronos_uint64_t` +//! - `khronos_ssize_t` +//! - `EGLNativeDisplayType` +//! - `EGLNativePixmapType` +//! - `EGLNativeWindowType` +//! - `EGLint` +//! - `NativeDisplayType` +//! - `NativePixmapType` +//! - `NativeWindowType` +//! + +#[macro_use] +extern crate log; +extern crate xml; + +#[cfg(feature = "unstable_generator_utils")] +pub mod generators; +#[cfg(not(feature = "unstable_generator_utils"))] +mod generators; + +mod registry; + +pub use generators::debug_struct_gen::DebugStructGenerator; +pub use generators::global_gen::GlobalGenerator; +pub use generators::static_gen::StaticGenerator; +pub use generators::static_struct_gen::StaticStructGenerator; +pub use generators::struct_gen::StructGenerator; +pub use generators::Generator; + +pub use registry::*; diff --git a/third_party/rust/gl_generator/registry/mod.rs b/third_party/rust/gl_generator/registry/mod.rs new file mode 100644 index 0000000000..385b2dfea1 --- /dev/null +++ b/third_party/rust/gl_generator/registry/mod.rs @@ -0,0 +1,202 @@ +// Copyright 2015-2016 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::{BTreeMap, BTreeSet}; +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::io; +use std::ops::{Add, AddAssign}; + +use Generator; + +mod parse; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Api { + Gl, + Glx, + Wgl, + Egl, + GlCore, + Gles1, + Gles2, + Glsc2, +} + +impl fmt::Display for Api { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + Api::Gl => write!(fmt, "gl"), + Api::Glx => write!(fmt, "glx"), + Api::Wgl => write!(fmt, "wgl"), + Api::Egl => write!(fmt, "egl"), + Api::GlCore => write!(fmt, "glcore"), + Api::Gles1 => write!(fmt, "gles1"), + Api::Gles2 => write!(fmt, "gles2"), + Api::Glsc2 => write!(fmt, "glsc2"), + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Fallbacks { + All, + None, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Profile { + Core, + Compatibility, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Enum { + pub ident: String, + pub value: String, + pub cast: bool, + pub alias: Option<String>, + pub ty: Cow<'static, str>, +} + +impl Hash for Enum { + fn hash<H: Hasher>(&self, state: &mut H) { + self.ident.hash(state); + } +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Binding { + pub ident: String, + pub ty: Cow<'static, str>, + pub group: Option<String>, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Group { + pub ident: String, + pub enums_type: Option<String>, + pub enums: Vec<String>, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Cmd { + pub proto: Binding, + pub params: Vec<Binding>, + pub alias: Option<String>, + pub vecequiv: Option<String>, + pub glx: Option<GlxOpcode>, +} + +impl Hash for Cmd { + fn hash<H: Hasher>(&self, state: &mut H) { + self.proto.ident.hash(state); + } +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct GlxOpcode { + pub opcode: String, + pub name: Option<String>, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Registry { + pub api: Api, + pub enums: BTreeSet<Enum>, + pub cmds: BTreeSet<Cmd>, + pub aliases: BTreeMap<String, Vec<String>>, + pub groups: BTreeMap<String, Group>, +} + +impl Registry { + pub fn new<'a, Exts>( + api: Api, + version: (u8, u8), + profile: Profile, + fallbacks: Fallbacks, + extensions: Exts, + ) -> Registry + where + Exts: AsRef<[&'a str]>, + { + let (major, minor) = version; + let extensions = extensions.as_ref().iter().map(<&str>::to_string).collect(); + + let filter = parse::Filter { + api, + fallbacks, + extensions, + version: format!("{}.{}", major, minor), + profile, + }; + + let src = match api { + Api::Gl | Api::GlCore | Api::Gles1 | Api::Gles2 | Api::Glsc2 => khronos_api::GL_XML, + Api::Glx => khronos_api::GLX_XML, + Api::Wgl => khronos_api::WGL_XML, + Api::Egl => khronos_api::EGL_XML, + }; + + let mut registry = parse::from_xml(src, &filter, true); + if filter.extensions.iter().any(|e| e.starts_with("GL_ANGLE_")) { + registry += parse::from_xml(khronos_api::GL_ANGLE_EXT_XML, &filter, false); + } + if filter.extensions.iter().any(|e| e.starts_with("EGL_ANGLE_")) { + registry += parse::from_xml(khronos_api::EGL_ANGLE_EXT_XML, &filter, false); + } + registry + } + + pub fn write_bindings<W, G>(&self, generator: G, output: &mut W) -> io::Result<()> + where + G: Generator, + W: io::Write, + { + generator.write(&self, output) + } + + /// Returns a set of all the types used in the supplied registry. This is useful + /// for working out what conversions are needed for the specific registry. + pub fn get_tys(&self) -> BTreeSet<&str> { + let mut tys = BTreeSet::new(); + for def in &self.cmds { + tys.insert(def.proto.ty.as_ref()); + for param in &def.params { + tys.insert(param.ty.as_ref()); + } + } + tys + } +} + +impl Add for Registry { + type Output = Registry; + + fn add(mut self, other: Registry) -> Registry { + self += other; + self + } +} + +impl AddAssign for Registry { + fn add_assign(&mut self, other: Self) { + self.enums.extend(other.enums); + self.cmds.extend(other.cmds); + self.aliases.extend(other.aliases); + } +} 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); + } + } + } +} |