1 | // Copyright 2015 Brendan Zabarauskas and the gl-rs developers |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | use registry::Registry; |
16 | use std::io; |
17 | |
18 | #[allow (missing_copy_implementations)] |
19 | pub struct DebugStructGenerator; |
20 | |
21 | impl super::Generator for DebugStructGenerator { |
22 | fn write<W>(&self, registry: &Registry, dest: &mut W) -> io::Result<()> |
23 | where |
24 | W: io::Write, |
25 | { |
26 | try!(write_header(dest)); |
27 | try!(write_type_aliases(registry, dest)); |
28 | try!(write_enums(registry, dest)); |
29 | try!(write_fnptr_struct_def(dest)); |
30 | try!(write_panicking_fns(registry, dest)); |
31 | try!(write_struct(registry, dest)); |
32 | try!(write_impl(registry, dest)); |
33 | Ok(()) |
34 | } |
35 | } |
36 | |
37 | /// Creates a `__gl_imports` module which contains all the external symbols that we need for the |
38 | /// bindings. |
39 | fn write_header<W>(dest: &mut W) -> io::Result<()> |
40 | where |
41 | W: io::Write, |
42 | { |
43 | writeln!( |
44 | dest, |
45 | r#" |
46 | mod __gl_imports {{ |
47 | pub use std::mem; |
48 | pub use std::marker::Send; |
49 | pub use std::os::raw; |
50 | }} |
51 | "# |
52 | ) |
53 | } |
54 | |
55 | /// Creates a `types` module which contains all the type aliases. |
56 | /// |
57 | /// See also `generators::gen_types`. |
58 | fn write_type_aliases<W>(registry: &Registry, dest: &mut W) -> io::Result<()> |
59 | where |
60 | W: io::Write, |
61 | { |
62 | try!(writeln!( |
63 | dest, |
64 | r#" |
65 | pub mod types {{ |
66 | #![allow(non_camel_case_types, non_snake_case, dead_code, missing_copy_implementations)] |
67 | "# |
68 | )); |
69 | |
70 | try!(super::gen_types(registry.api, dest)); |
71 | |
72 | writeln!(dest, " }}" ) |
73 | } |
74 | |
75 | /// Creates all the `<enum>` elements at the root of the bindings. |
76 | fn write_enums<W>(registry: &Registry, dest: &mut W) -> io::Result<()> |
77 | where |
78 | W: io::Write, |
79 | { |
80 | for enm: &Enum in ®istry.enums { |
81 | try!(super::gen_enum_item(enm, "types::" , dest)); |
82 | } |
83 | |
84 | Ok(()) |
85 | } |
86 | |
87 | /// Creates a `FnPtr` structure which contains the store for a single binding. |
88 | fn write_fnptr_struct_def<W>(dest: &mut W) -> io::Result<()> |
89 | where |
90 | W: io::Write, |
91 | { |
92 | writeln!( |
93 | dest, |
94 | " |
95 | #[allow(dead_code, missing_copy_implementations)] |
96 | #[derive(Clone)] |
97 | pub struct FnPtr {{ |
98 | /// The function pointer that will be used when calling the function. |
99 | f: *const __gl_imports::raw::c_void, |
100 | /// True if the pointer points to a real function, false if points to a `panic!` fn. |
101 | is_loaded: bool, |
102 | }} |
103 | |
104 | impl FnPtr {{ |
105 | /// Creates a `FnPtr` from a load attempt. |
106 | fn new(ptr: *const __gl_imports::raw::c_void) -> FnPtr {{ |
107 | if ptr.is_null() {{ |
108 | FnPtr {{ |
109 | f: missing_fn_panic as *const __gl_imports::raw::c_void, |
110 | is_loaded: false |
111 | }} |
112 | }} else {{ |
113 | FnPtr {{ f: ptr, is_loaded: true }} |
114 | }} |
115 | }} |
116 | |
117 | /// Returns `true` if the function has been successfully loaded. |
118 | /// |
119 | /// If it returns `false`, calling the corresponding function will fail. |
120 | #[inline] |
121 | #[allow(dead_code)] |
122 | pub fn is_loaded(&self) -> bool {{ |
123 | self.is_loaded |
124 | }} |
125 | }} |
126 | " |
127 | ) |
128 | } |
129 | |
130 | /// Creates a `panicking` module which contains one function per GL command. |
131 | /// |
132 | /// These functions are the mocks that are called if the real function could not be loaded. |
133 | fn write_panicking_fns<W>(registry: &Registry, dest: &mut W) -> io::Result<()> |
134 | where |
135 | W: io::Write, |
136 | { |
137 | writeln!( |
138 | dest, |
139 | "#[inline(never)] |
140 | fn missing_fn_panic() -> ! {{ |
141 | panic!( \"{api} function was not loaded \") |
142 | }}" , |
143 | api = registry.api |
144 | ) |
145 | } |
146 | |
147 | /// Creates a structure which stores all the `FnPtr` of the bindings. |
148 | /// |
149 | /// The name of the struct corresponds to the namespace. |
150 | fn write_struct<W>(registry: &Registry, dest: &mut W) -> io::Result<()> |
151 | where |
152 | W: io::Write, |
153 | { |
154 | try!(writeln!( |
155 | dest, |
156 | " |
157 | #[allow(non_camel_case_types, non_snake_case, dead_code)] |
158 | #[derive(Clone)] |
159 | pub struct {api} {{" , |
160 | api = super::gen_struct_name(registry.api) |
161 | )); |
162 | |
163 | for cmd: &Cmd in ®istry.cmds { |
164 | if let Some(v: &Vec) = registry.aliases.get(&cmd.proto.ident) { |
165 | try!(writeln!(dest, "/// Fallbacks: {}" , v.join(", " ))); |
166 | } |
167 | try!(writeln!(dest, "pub {name}: FnPtr," , name = cmd.proto.ident)); |
168 | } |
169 | try!(writeln!(dest, "_priv: ()" )); |
170 | |
171 | writeln!(dest, " }}" ) |
172 | } |
173 | |
174 | /// Creates the `impl` of the structure created by `write_struct`. |
175 | fn write_impl<W>(registry: &Registry, dest: &mut W) -> io::Result<()> |
176 | where |
177 | W: io::Write, |
178 | { |
179 | try!(writeln!(dest, |
180 | "impl {api} {{ |
181 | /// Load each OpenGL symbol using a custom load function. This allows for the |
182 | /// use of functions like `glfwGetProcAddress` or `SDL_GL_GetProcAddress`. |
183 | /// |
184 | /// ~~~ignore |
185 | /// let gl = Gl::load_with(|s| glfw.get_proc_address(s)); |
186 | /// ~~~ |
187 | #[allow(dead_code, unused_variables)] |
188 | pub fn load_with<F>(mut loadfn: F) -> {api} where F: FnMut(&'static str) -> *const __gl_imports::raw::c_void {{ |
189 | #[inline(never)] |
190 | fn do_metaloadfn(loadfn: &mut dyn FnMut(&'static str) -> *const __gl_imports::raw::c_void, |
191 | symbol: &'static str, |
192 | symbols: &[&'static str]) |
193 | -> *const __gl_imports::raw::c_void {{ |
194 | let mut ptr = loadfn(symbol); |
195 | if ptr.is_null() {{ |
196 | for &sym in symbols {{ |
197 | ptr = loadfn(sym); |
198 | if !ptr.is_null() {{ break; }} |
199 | }} |
200 | }} |
201 | ptr |
202 | }} |
203 | let mut metaloadfn = |symbol: &'static str, symbols: &[&'static str]| {{ |
204 | do_metaloadfn(&mut loadfn, symbol, symbols) |
205 | }}; |
206 | {api} {{" , |
207 | api = super::gen_struct_name(registry.api))); |
208 | |
209 | for cmd in ®istry.cmds { |
210 | try!(writeln!( |
211 | dest, |
212 | " {name}: FnPtr::new(metaloadfn( \"{symbol}\", &[ {fallbacks}]))," , |
213 | name = cmd.proto.ident, |
214 | symbol = super::gen_symbol_name(registry.api, &cmd.proto.ident), |
215 | fallbacks = match registry.aliases.get(&cmd.proto.ident) { |
216 | Some(fbs) => fbs |
217 | .iter() |
218 | .map(|name| format!(" \"{}\"" , super::gen_symbol_name(registry.api, &name))) |
219 | .collect::<Vec<_>>() |
220 | .join(", " ), |
221 | None => format!("" ), |
222 | }, |
223 | )) |
224 | } |
225 | try!(writeln!(dest, "_priv: ()" )); |
226 | |
227 | try!(writeln!( |
228 | dest, |
229 | " }} |
230 | }}" |
231 | )); |
232 | |
233 | for cmd in ®istry.cmds { |
234 | let idents = super::gen_parameters(cmd, true, false); |
235 | let typed_params = super::gen_parameters(cmd, false, true); |
236 | let println = format!( |
237 | "println!( \"[OpenGL] {}( {}) \" {});" , |
238 | cmd.proto.ident, |
239 | (0..idents.len()) |
240 | .map(|_| "{:?}" .to_string()) |
241 | .collect::<Vec<_>>() |
242 | .join(", " ), |
243 | idents |
244 | .iter() |
245 | .zip(typed_params.iter()) |
246 | .map(|(name, ty)| if ty.contains("GLDEBUGPROC" ) { |
247 | format!(", \"<callback> \"" ) |
248 | } else { |
249 | format!(", {}" , name) |
250 | }).collect::<Vec<_>>() |
251 | .concat() |
252 | ); |
253 | |
254 | try!(writeln!(dest, |
255 | "#[allow(non_snake_case, unused_variables, dead_code)] |
256 | #[inline] pub unsafe fn {name}(&self, {params}) -> {return_suffix} {{ \ |
257 | {println} |
258 | let r = __gl_imports::mem::transmute::<_, extern \"system \" fn( {typed_params}) -> {return_suffix}>\ |
259 | (self. {name}.f)( {idents}); |
260 | {print_err} |
261 | r |
262 | }}" , |
263 | name = cmd.proto.ident, |
264 | params = super::gen_parameters(cmd, true, true).join(", " ), |
265 | typed_params = typed_params.join(", " ), |
266 | return_suffix = cmd.proto.ty, |
267 | idents = idents.join(", " ), |
268 | println = println, |
269 | print_err = if cmd.proto.ident != "GetError" && |
270 | registry |
271 | .cmds |
272 | .iter() |
273 | .find(|cmd| cmd.proto.ident == "GetError" ) |
274 | .is_some() { |
275 | format!(r#"match __gl_imports::mem::transmute::<_, extern "system" fn() -> u32> |
276 | (self.GetError.f)() {{ 0 => (), r => println!("[OpenGL] ^ GL error triggered: {{}}", r) }}"# ) |
277 | } else { |
278 | format!("" ) |
279 | })) |
280 | } |
281 | |
282 | writeln!( |
283 | dest, |
284 | " }} |
285 | |
286 | unsafe impl __gl_imports::Send for {api} {{}}" , |
287 | api = super::gen_struct_name(registry.api) |
288 | ) |
289 | } |
290 | |