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(())
}
}
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;
}}
"#
)
}
fn write_metaloadfn<W>(dest: &mut W) -> io::Result<()>
where
W: io::Write,
{
writeln!(
dest,
r#"
#[inline(never)]
fn metaloadfn(loadfn: &mut 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
}}
"#
)
}
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,
"
}}
"
)
}
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(())
}
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(())
}
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 }}
}}
}}
}}
")
}
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, "}}")
}
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(())
}
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
)
}
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 {{
"));
for c in ®istry.cmds {
try!(writeln!(
dest,
"{cmd_name}::load_with(&mut loadfn);",
cmd_name = &c.proto.ident[..]
));
}
writeln!(
dest,
"
}}
"
)
}