Repository: brendanzab/gl-rs (language: rust)

Issue:
Add a "compiletime" generator
Calling `egl::load_with` or `wgl::load_with` makes no sense. We need a generator that creates regular bindings that are linked at compile-time.



Discussion / hints:
So you mean just plain old bindings?

Yes. This is the only way to use glx/wgl/egl, and could come in handy for OpenGL ES.

indeed - if we could get something nice for OpenGL ES, then there is potential for Servo to start using gl-rs.

I couldn't think of a good name, maybe "compiletime" or "extern".
"static" could be appropriate, but we'd need to rename to default generator to something else.

hmm, maybe `static`, `global`, `struct`?


Fix patch:
diff --git a/README.md b/README.md
index 72423da1..d5533775 100644
--- a/README.md
+++ b/README.md
@@ -100,7 +100,7 @@ The parameters are the following:
  * Profile: Can be `core` or `compatibility`.
  * Version: The requested version of OpenGL, WGL, GLX or EGL in the format
     `x.x`.
- * Generator: Can be `global` or `struct` (more informations below).
+ * Generator: Can be `static`, `global` or `struct` (more informations below).
  * Extensions (optional): An array of extensions to include in the bindings.
     For example: `generate_gl_bindings!("gl", "core", "4.5", "global",
     [ "GL_EXT_texture_filter_anisotropic" ])`
@@ -120,3 +120,19 @@ functions are not static functions but member functions in this `Gl` struct.
 
 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 guanteed 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.
diff --git a/src/gl_generator/common.rs b/src/gl_generator/common.rs
index f13c64b7..5b1a1aaf 100644
--- a/src/gl_generator/common.rs
+++ b/src/gl_generator/common.rs
@@ -67,7 +67,7 @@ pub fn gen_return_suffix(cmd: &Cmd) -> String {
 pub fn gen_symbol_name(ns: &Ns, cmd: &Cmd) -> String {
     (match *ns {
         Gl | Gles1 | Gles2 => "gl",
-        Glx => "glx",
+        Glx => "glX",
         Wgl => "wgl",
         Egl => "egl",
     }).to_string().append(cmd.proto.ident.as_slice())
diff --git a/src/gl_generator/lib.rs b/src/gl_generator/lib.rs
index ccc3a8ec..162e4007 100644
--- a/src/gl_generator/lib.rs
+++ b/src/gl_generator/lib.rs
@@ -39,7 +39,7 @@
 //!    by the requested version it self, while `compatibility` will include all the functions from
 //!    previous versions as well.
 //! * Version: The requested version of OpenGL, WGL, GLX or EGL in the format `x.x`.
-//! * Generator: Can be `global` or `struct`.
+//! * Generator: Can be `static`, `global` or `struct`.
 //! * Extensions (optional): An array of extensions to include in the bindings.
 //! 
 //! ## About EGL
@@ -89,10 +89,12 @@ use syntax::codemap::Span;
 
 use registry::*;
 use global_gen::GlobalGenerator;
+use static_gen::StaticGenerator;
 use struct_gen::StructGenerator;
 
 mod common;
 pub mod global_gen;
+pub mod static_gen;
 pub mod struct_gen;
 pub mod registry;
 pub mod ty;
@@ -200,10 +202,11 @@ fn macro_handler(ecx: &mut ExtCtxt, span: Span, token_tree: &[TokenTree]) -> Box
                 buffer
             }),
 
-            "static" => {
-                ecx.span_err(span, "the 'static' generator has been renamed to 'global'");
-                return DummyResult::any(span);
-            },
+            "static" => task::try(proc() {
+                let mut buffer = MemWriter::new();
+                StaticGenerator::write(&mut buffer, &reg, ns);
+                buffer
+            }),
 
             generator => {
                 ecx.span_err(span, format!("unknown generator type: {}", generator).as_slice());
diff --git a/src/gl_generator/static_gen.rs b/src/gl_generator/static_gen.rs
new file mode 100644
index 00000000..3a6c4e51
--- /dev/null
+++ b/src/gl_generator/static_gen.rs
@@ -0,0 +1,239 @@
+// Copyright 2013-2014 The gl-rs developers. For a full listing of the authors,
+// refer to the AUTHORS file at the top-level directory of this distribution.
+//
+// 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.
+
+#![experimental]
+
+use registry::*;
+use ty;
+use common;
+use std::io::Writer;
+
+static TAB_WIDTH: uint = 4;
+
+pub struct StaticGenerator<'a, W: 'a> {
+    ns: Ns,
+    writer: &'a mut W,
+    registry: &'a Registry,
+    indent: uint,
+}
+
+impl<'a, W: Writer> StaticGenerator<'a, W> {
+    fn new<'a>(writer: &'a mut W, registry: &'a Registry, ns: Ns) -> StaticGenerator<'a, W> {
+        StaticGenerator {
+            ns: ns,
+            writer: writer,
+            registry: registry,
+            indent: 0,
+        }
+    }
+
+    fn incr_indent(&mut self) {
+        self.indent += 1;
+    }
+
+    fn decr_indent(&mut self) {
+        if self.indent > 0 { self.indent -= 1 }
+    }
+
+    #[allow(unused_must_use)]
+    fn write_str(&mut self, s: &str) {
+        self.writer.write(s.as_bytes());
+    }
+
+    fn write_indent(&mut self) {
+        for _ in range(0, TAB_WIDTH * self.indent) {
+            self.write_str(" ");
+        }
+    }
+
+    fn write_line(&mut self, s: &str) {
+        self.write_indent();
+        self.write_str(s);
+        self.write_str("\n");
+    }
+
+    fn write_enum(&mut self, enm: &Enum) {
+        let ident = if (enm.ident.as_slice().char_at(0)).is_digit() {
+            format!("_{}", enm.ident)
+        } else {
+            enm.ident.clone()
+        };
+
+        let ty = {
+            let regex = regex!(r"\(\((\w+)\).+\)");
+
+            if (regex).is_match(enm.value.as_slice()) {
+                // if the value is ((Type)value), then the type is types::Type
+                regex.replace(enm.value.as_slice(), "types::$1")
+
+            } else if enm.value.as_slice().starts_with("\"") {
+                "&'static str".to_string()
+
+            } else {
+                match ident.as_slice() {
+                    "TRUE" | "FALSE" => "types::GLboolean",
+                    _ => match enm.ty {
+                        Some(ref s) if s.as_slice() == "ull" => "types::GLuint64",
+                        _ => "types::GLenum"
+                    }
+                }.to_string()
+            }
+        };
+
+        let value = {
+            let ref value = enm.value;
+
+            // replacing "((EGLType)0)" by "0 as types::EGLType"
+            let regex = regex!(r"\(\((EGL\w+)\)0\)");
+            let value = regex.replace(value.as_slice(), "0 as types::$1");
+
+            // replacing "((Type)value)" by "value"
+            let regex = regex!(r"\(\(\w+\)(.+)\)");
+            let value = regex.replace(value.as_slice(), "$1");
+
+            value
+        };
+
+        self.write_line("#[stable]");
+        self.write_line("#[allow(dead_code)]");
+        self.write_line(format!("pub static {}: {} = {};", ident, ty, value).as_slice())
+    }
+
+    fn write_enums(&mut self) {
+        for e in self.registry.enum_iter() {
+            self.write_enum(e);
+        }
+    }
+
+    fn write_header(&mut self) {
+        self.write_line("mod __gl_imports {");
+        self.write_line("    extern crate libc;");
+        self.write_line("    pub use std::mem;");
+        self.write_line("}");
+    }
+
+    fn write_type_aliases(&mut self) {
+        self.write_line("#[stable]");
+        self.write_line("pub mod types {");
+        self.incr_indent();
+        self.write_line("");
+        match self.ns {
+            Gl | Gles1 | Gles2 => {
+                for alias in ty::GL_ALIASES.iter() {
+                    self.write_line("#[allow(non_camel_case_types)]");
+                    self.write_line("#[allow(non_snake_case)]");
+                    self.write_line("#[allow(dead_code)]");
+                    self.write_line(*alias)
+                }
+            }
+            Glx => {
+                for alias in ty::GL_ALIASES.iter() {
+                    self.write_line("#[allow(non_camel_case_types)]");
+                    self.write_line("#[allow(non_snake_case)]");
+                    self.write_line("#[allow(dead_code)]");
+                    self.write_line(*alias)
+                }
+                for alias in ty::X_ALIASES.iter() {
+                    self.write_line("#[allow(non_camel_case_types)]");
+                    self.write_line("#[allow(non_snake_case)]");
+                    self.write_line("#[allow(dead_code)]");
+                    self.write_line(*alias)
+                }
+                for alias in ty::GLX_ALIASES.iter() {
+                    self.write_line("#[allow(non_camel_case_types)]");
+                    self.write_line("#[allow(non_snake_case)]");
+                    self.write_line("#[allow(dead_code)]");
+                    self.write_line(*alias)
+                }
+            }
+            Wgl => {
+                for alias in ty::GL_ALIASES.iter() {
+                    self.write_line("#[allow(non_camel_case_types)]");
+                    self.write_line("#[allow(non_snake_case)]");
+                    self.write_line("#[allow(dead_code)]");
+                    self.write_line(*alias)
+                }
+                for alias in ty::WIN_ALIASES.iter() {
+                    self.write_line("#[allow(non_camel_case_types)]");
+                    self.write_line("#[allow(non_snake_case)]");
+                    self.write_line("#[allow(dead_code)]");
+                    self.write_line(*alias)
+                }
+                for alias in ty::WGL_ALIASES.iter() {
+                    self.write_line("#[allow(non_camel_case_types)]");
+                    self.write_line("#[allow(non_snake_case)]");
+                    self.write_line("#[allow(dead_code)]");
+                    self.write_line(*alias)
+                }
+            }
+            Egl => {
+                for alias in ty::GL_ALIASES.iter() {
+                    self.write_line("#[allow(non_camel_case_types)]");
+                    self.write_line("#[allow(non_snake_case)]");
+                    self.write_line("#[allow(dead_code)]");
+                    self.write_line(*alias)
+                }
+                for alias in ty::EGL_ALIASES.iter() {
+                    self.write_line("#[allow(non_camel_case_types)]");
+                    self.write_line("#[allow(non_snake_case)]");
+                    self.write_line("#[allow(dead_code)]");
+                    self.write_line(*alias)
+                }
+            }
+        }
+        self.decr_indent();
+        self.write_line("}");
+    }
+
+    fn write_fns(&mut self) {
+        let ns = self.ns;
+
+        self.write_line("#[allow(non_snake_case)] #[allow(unused_variable)] #[allow(dead_code)]");
+        self.write_line("extern \"system\" {");
+        self.write_line("");
+        for c in self.registry.cmd_iter() {
+            self.write_line(format!(
+                "#[link_name=\"{symbol}\"]
+                pub fn {name}({params}){return_suffix};",
+                symbol = common::gen_symbol_name(&ns, c),
+                name = c.proto.ident,
+                params = common::gen_param_list(c, true),
+                return_suffix = common::gen_return_suffix(c)
+            ).as_slice());
+        }
+        self.decr_indent();
+        self.write_line("}");
+    }
+
+    pub fn write(writer: &mut W, registry: &Registry, ns: Ns) {
+        let mut gen = StaticGenerator::new(writer, registry, ns);
+
+        // header with imports
+        gen.write_header();
+        gen.write_line("");
+
+        // type aliases
+        gen.write_type_aliases();
+        gen.write_line("");
+
+        // enums definitions
+        gen.write_enums();
+        gen.write_line("");
+
+        // safe and unsafe OpenGl functions
+        gen.write_fns();
+        gen.write_line("");
+    }
+}


Test patch:
diff --git a/tests/no_warning.rs b/tests/no_warning.rs
index 983bba7d..2ba06e8f 100644
--- a/tests/no_warning.rs
+++ b/tests/no_warning.rs
@@ -10,31 +10,43 @@ extern crate gl_generator;
 
 extern crate libc;
 
-mod gl_static {
+mod gl_global {
     generate_gl_bindings!("gl", "core", "4.5", "global")
 }
 
+mod gl_static {
+    generate_gl_bindings!("gl", "core", "4.5", "static")
+}
+
 mod gl_struct {
     generate_gl_bindings!("gl", "core", "4.5", "struct")
 }
 
-mod glx_static {
+mod glx_global {
     generate_gl_bindings!("glx", "core", "1.4", "global")
 }
 
+mod glx_static {
+    generate_gl_bindings!("glx", "core", "1.4", "static")
+}
+
 mod glx_struct {
     generate_gl_bindings!("glx", "core", "1.4", "struct")
 }
 
-mod wgl_static {
+mod wgl_global {
     generate_gl_bindings!("wgl", "core", "1.0", "global")
 }
 
+mod wgl_static {
+    generate_gl_bindings!("wgl", "core", "1.0", "static")
+}
+
 mod wgl_struct {
     generate_gl_bindings!("wgl", "core", "1.0", "struct")
 }
 
-mod egl_static {
+mod egl_global {
     use libc;
 
     #[allow(non_camel_case_types)]
@@ -54,6 +66,26 @@ mod egl_static {
     generate_gl_bindings!("egl", "core", "1.5", "global")
 }
 
+mod egl_static {
+    use libc;
+
+    #[allow(non_camel_case_types)]
+    pub type khronos_utime_nanoseconds_t = libc::c_int;
+    #[allow(non_camel_case_types)]
+    pub type khronos_uint64_t = libc::uint64_t;
+    #[allow(non_camel_case_types)]
+    pub type khronos_ssize_t = libc::ssize_t;
+    pub type EGLNativeDisplayType = *const libc::c_void;
+    pub type EGLNativePixmapType = *const libc::c_void;
+    pub type EGLNativeWindowType = *const libc::c_void;
+    pub type EGLint = libc::c_int;
+    pub type NativeDisplayType = *const libc::c_void;
+    pub type NativePixmapType = *const libc::c_void;
+    pub type NativeWindowType = *const libc::c_void;
+
+    generate_gl_bindings!("egl", "core", "1.5", "static")
+}
+
 mod egl_struct {
     use libc;
 
@@ -74,18 +106,26 @@ mod egl_struct {
     generate_gl_bindings!("egl", "core", "1.5", "struct")
 }
 
-mod gles1_static {
+mod gles1_global {
     generate_gl_bindings!("gles1", "core", "1.1", "global")
 }
 
+mod gles1_static {
+    generate_gl_bindings!("gles1", "core", "1.1", "static")
+}
+
 mod gles1_struct {
     generate_gl_bindings!("gles1", "core", "1.1", "struct")
 }
 
-mod gles2_static {
+mod gles2_global {
     generate_gl_bindings!("gles2", "core", "3.1", "global")
 }
 
+mod gles2_static {
+    generate_gl_bindings!("gles2", "core", "3.1", "static")
+}
+
 mod gles2_struct {
     generate_gl_bindings!("gles2", "core", "3.1", "struct")
 }