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 StructGenerator; |
20 | |
21 | impl super::Generator for StructGenerator { |
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 | |
226 | try!(writeln!(dest, "_priv: ()" )); |
227 | |
228 | try!(writeln!( |
229 | dest, |
230 | " }} |
231 | }}" |
232 | )); |
233 | |
234 | for cmd in ®istry.cmds { |
235 | try!(writeln!(dest, |
236 | "#[allow(non_snake_case, unused_variables, dead_code)] |
237 | #[inline] pub unsafe fn {name}(&self, {params}) -> {return_suffix} {{ \ |
238 | __gl_imports::mem::transmute::<_, extern \"system \" fn( {typed_params}) -> {return_suffix}>\ |
239 | (self. {name}.f)( {idents}) \ |
240 | }}" , |
241 | name = cmd.proto.ident, |
242 | params = super::gen_parameters(cmd, true, true).join(", " ), |
243 | typed_params = super::gen_parameters(cmd, false, true).join(", " ), |
244 | return_suffix = cmd.proto.ty, |
245 | idents = super::gen_parameters(cmd, true, false).join(", " ), |
246 | )) |
247 | } |
248 | |
249 | writeln!( |
250 | dest, |
251 | " }} |
252 | |
253 | unsafe impl __gl_imports::Send for {api} {{}}" , |
254 | api = super::gen_struct_name(registry.api) |
255 | ) |
256 | } |
257 | |