Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

538 linhas
16 KiB

  1. #![allow(clippy::trivial_regex)]
  2. #![allow(clippy::useless_format)]
  3. extern crate gl_generator;
  4. use std::env::var;
  5. use std::fs::File;
  6. use std::io::{Error as IoError, Write};
  7. use std::path::Path;
  8. use gl_generator::{
  9. generators::{gen_struct_name, gen_symbol_name, gen_types},
  10. Api, Cmd, Fallbacks, Generator as GlGenerator, Profile, Registry,
  11. };
  12. use lazy_static::lazy_static;
  13. use regex::{Captures, Regex};
  14. fn main() {
  15. let out_dir = var("OUT_DIR").unwrap();
  16. let mut file = File::create(&Path::new(&out_dir).join("bindings.rs")).unwrap();
  17. let generator = Generator {
  18. generate_debug: var("CARGO_FEATURE_GENERATE_DEBUG").is_ok(),
  19. generate_global: var("CARGO_FEATURE_GENERATE_GLOBAL").is_ok(),
  20. generate_struct: var("CARGO_FEATURE_GENERATE_STRUCT").is_ok(),
  21. log_fn: if var("CARGO_FEATURE_USE_LOG_CRATE").is_ok() {
  22. "log::trace!"
  23. } else {
  24. "println!"
  25. },
  26. };
  27. Registry::new(Api::Gl, (4, 5), Profile::Compatibility, Fallbacks::All, [])
  28. .write_bindings(generator, &mut file)
  29. .unwrap();
  30. }
  31. pub struct Generator {
  32. generate_debug: bool,
  33. generate_global: bool,
  34. generate_struct: bool,
  35. log_fn: &'static str,
  36. }
  37. impl GlGenerator for Generator {
  38. fn write<W>(&self, registry: &Registry, dest: &mut W) -> Result<(), IoError>
  39. where
  40. W: Write,
  41. {
  42. self.write_header(dest)?;
  43. self.write_type_aliases(registry, dest)?;
  44. self.write_enums(registry, dest)?;
  45. self.write_fnptr_struct_def(registry, dest)?;
  46. if self.generate_global {
  47. self.write_load_fn(registry, dest)?;
  48. self.write_fns(registry, dest)?;
  49. self.write_ptrs(registry, dest)?;
  50. self.write_fn_mods(registry, dest)?;
  51. }
  52. if self.generate_struct {
  53. self.write_struct_def(registry, dest)?;
  54. self.write_struct_impl(registry, dest)?;
  55. }
  56. Ok(())
  57. }
  58. }
  59. impl Generator {
  60. fn write_header<W>(&self, dest: &mut W) -> Result<(), IoError>
  61. where
  62. W: Write,
  63. {
  64. writeln!(
  65. dest,
  66. r#"
  67. mod __gl_imports {{
  68. pub use std::os::raw;
  69. pub use std::mem::transmute;
  70. }}"#
  71. )?;
  72. Ok(())
  73. }
  74. fn write_type_aliases<W>(&self, registry: &Registry, dest: &mut W) -> Result<(), IoError>
  75. where
  76. W: Write,
  77. {
  78. writeln!(
  79. dest,
  80. r#"
  81. pub mod types {{"#
  82. )?;
  83. gen_types(registry.api, dest)?;
  84. writeln!(
  85. dest,
  86. r#"
  87. }}"#
  88. )?;
  89. Ok(())
  90. }
  91. fn write_enums<W>(&self, registry: &Registry, dest: &mut W) -> Result<(), IoError>
  92. where
  93. W: Write,
  94. {
  95. for enm in &registry.enums {
  96. writeln!(
  97. dest,
  98. r#"pub const {ident}: {types_prefix}{ty} = {value}{cast_suffix};"#,
  99. ident = enm.ident,
  100. types_prefix = if enm.ty == "&'static str" {
  101. ""
  102. } else {
  103. "types::"
  104. },
  105. ty = enm.ty,
  106. value = enm.value,
  107. cast_suffix = match enm.cast {
  108. true => format!(" as types::{}", enm.ty),
  109. false => String::new(),
  110. },
  111. )?;
  112. }
  113. Ok(())
  114. }
  115. fn write_fnptr_struct_def<W>(&self, registry: &Registry, dest: &mut W) -> Result<(), IoError>
  116. where
  117. W: Write,
  118. {
  119. writeln!(
  120. dest,
  121. r#"
  122. #[derive(Clone)]
  123. pub struct FnPtr {{
  124. f: *const std::os::raw::c_void,
  125. is_loaded: bool,
  126. }}
  127. impl FnPtr {{
  128. fn new(ptr: *const std::os::raw::c_void) -> FnPtr {{
  129. if ptr.is_null() {{
  130. FnPtr {{
  131. f: missing_fn_panic as *const std::os::raw::c_void,
  132. is_loaded: false
  133. }}
  134. }} else {{
  135. FnPtr {{ f: ptr, is_loaded: true }}
  136. }}
  137. }}
  138. #[inline]
  139. pub fn is_loaded(&self) -> bool {{
  140. self.is_loaded
  141. }}
  142. }}
  143. #[inline(never)]
  144. fn missing_fn_panic() -> ! {{
  145. panic!("{api} function was not loaded")
  146. }}
  147. #[inline(never)]
  148. fn metaloadfn(
  149. loadfn: &mut dyn FnMut(&'static str) -> *const std::os::raw::c_void,
  150. symbol: &'static str,
  151. fallbacks: &[&'static str]) -> *const std::os::raw::c_void
  152. {{
  153. let mut ptr = loadfn(symbol);
  154. if ptr.is_null() {{
  155. for &sym in fallbacks {{
  156. ptr = loadfn(sym);
  157. if !ptr.is_null() {{ break; }}
  158. }}
  159. }}
  160. ptr
  161. }}"#,
  162. api = registry.api,
  163. )
  164. }
  165. fn write_load_fn<W>(&self, registry: &Registry, dest: &mut W) -> Result<(), IoError>
  166. where
  167. W: Write,
  168. {
  169. write!(
  170. dest,
  171. r#"
  172. pub fn load_with<F>(mut loadfn: F) where F: FnMut(&'static str) -> *const __gl_imports::raw::c_void {{
  173. #[inline(never)]
  174. fn inner(loadfn: &mut dyn FnMut(&'static str) -> *const __gl_imports::raw::c_void) {{"#
  175. )?;
  176. for c in &registry.cmds {
  177. write!(
  178. dest,
  179. r#"
  180. {cmd_name}::load_with(&mut *loadfn);"#,
  181. cmd_name = to_snake_case(&c.proto.ident),
  182. )?;
  183. }
  184. writeln!(
  185. dest,
  186. r#"
  187. }}
  188. inner(&mut loadfn)
  189. }}"#
  190. )?;
  191. Ok(())
  192. }
  193. fn write_fns<W>(&self, registry: &Registry, dest: &mut W) -> Result<(), IoError>
  194. where
  195. W: Write,
  196. {
  197. let has_get_error = registry
  198. .cmds
  199. .iter()
  200. .any(|cmd| cmd.proto.ident == "GetError");
  201. for cmd in &registry.cmds {
  202. self.gen_func(dest, cmd, has_get_error, true)?;
  203. }
  204. Ok(())
  205. }
  206. fn write_ptrs<W>(&self, registry: &Registry, dest: &mut W) -> Result<(), IoError>
  207. where
  208. W: Write,
  209. {
  210. writeln!(
  211. dest,
  212. r#"
  213. mod storage {{
  214. use super::__gl_imports::raw;
  215. use super::FnPtr;"#
  216. )?;
  217. for c in &registry.cmds {
  218. writeln!(
  219. dest,
  220. r#"
  221. pub static mut {name}: FnPtr = FnPtr {{
  222. f: super::missing_fn_panic as *const raw::c_void,
  223. is_loaded: false
  224. }};"#,
  225. name = to_snake_case(&c.proto.ident)
  226. )?;
  227. }
  228. writeln!(
  229. dest,
  230. r#"
  231. }}"#
  232. )?;
  233. Ok(())
  234. }
  235. fn write_fn_mods<W>(&self, registry: &Registry, dest: &mut W) -> Result<(), IoError>
  236. where
  237. W: Write,
  238. {
  239. for c in &registry.cmds {
  240. let fallbacks = match registry.aliases.get(&c.proto.ident) {
  241. Some(v) => {
  242. let names = v
  243. .iter()
  244. .map(|name| format!("\"{}\"", gen_symbol_name(registry.api, &name)))
  245. .collect::<Vec<_>>();
  246. format!("&[{}]", names.join(", "))
  247. }
  248. None => "&[]".to_string(),
  249. };
  250. let fnname = to_snake_case(&c.proto.ident);
  251. let symbol = gen_symbol_name(registry.api, &c.proto.ident);
  252. let symbol = &symbol;
  253. writeln!(
  254. dest,
  255. r##"
  256. pub mod {fnname} {{
  257. use super::{{storage, metaloadfn}};
  258. use super::__gl_imports::raw;
  259. use super::FnPtr;
  260. #[inline]
  261. pub fn is_loaded() -> bool {{
  262. unsafe {{ storage::{fnname}.is_loaded }}
  263. }}
  264. pub fn load_with<F>(mut loadfn: F) where F: FnMut(&'static str) -> *const raw::c_void {{
  265. unsafe {{
  266. storage::{fnname} = FnPtr::new(metaloadfn(&mut loadfn, "{symbol}", {fallbacks}))
  267. }}
  268. }}
  269. }}"##,
  270. fnname = fnname,
  271. fallbacks = fallbacks,
  272. symbol = symbol
  273. )?;
  274. }
  275. Ok(())
  276. }
  277. fn write_struct_def<W>(&self, registry: &Registry, dest: &mut W) -> Result<(), IoError>
  278. where
  279. W: Write,
  280. {
  281. writeln!(
  282. dest,
  283. r#"
  284. #[derive(Clone)]
  285. pub struct {api} {{"#,
  286. api = gen_struct_name(registry.api)
  287. )?;
  288. for cmd in &registry.cmds {
  289. writeln!(
  290. dest,
  291. r#" pub {name}: FnPtr,"#,
  292. name = to_snake_case(&cmd.proto.ident)
  293. )?;
  294. }
  295. writeln!(dest, r#" }}"#)?;
  296. Ok(())
  297. }
  298. fn write_struct_impl<W>(&self, registry: &Registry, dest: &mut W) -> Result<(), IoError>
  299. where
  300. W: Write,
  301. {
  302. write!(
  303. dest,
  304. r#"
  305. impl {api} {{
  306. pub fn load_with<F>(mut loadfn: F) -> {api} where F: FnMut(&'static str) -> *const std::os::raw::c_void {{
  307. let mut do_loadfn = |symbol: &'static str, symbols: &[&'static str]| {{
  308. metaloadfn(&mut loadfn, symbol, symbols)
  309. }};
  310. {api} {{"#,
  311. api = gen_struct_name(registry.api)
  312. )?;
  313. for cmd in &registry.cmds {
  314. write!(
  315. dest,
  316. r#"
  317. {name}: FnPtr::new(do_loadfn("{symbol}", &[{fallbacks}])),"#,
  318. name = to_snake_case(&cmd.proto.ident),
  319. symbol = gen_symbol_name(registry.api, &cmd.proto.ident),
  320. fallbacks = match registry.aliases.get(&cmd.proto.ident) {
  321. Some(fbs) => fbs
  322. .iter()
  323. .map(|name| format!(r#""{}""#, gen_symbol_name(registry.api, &name)))
  324. .collect::<Vec<_>>()
  325. .join(", "),
  326. None => format!(""),
  327. },
  328. )?
  329. }
  330. writeln!(
  331. dest,
  332. r#"
  333. }}
  334. }}"#
  335. )?;
  336. let has_get_error = registry
  337. .cmds
  338. .iter()
  339. .any(|cmd| cmd.proto.ident == "GetError");
  340. for cmd in &registry.cmds {
  341. self.gen_func(dest, cmd, has_get_error, false)?;
  342. }
  343. writeln!(
  344. dest,
  345. r#"
  346. }}
  347. unsafe impl std::marker::Send for {api} {{}}"#,
  348. api = gen_struct_name(registry.api)
  349. )
  350. }
  351. fn gen_func<W>(
  352. &self,
  353. dest: &mut W,
  354. cmd: &Cmd,
  355. has_get_error: bool,
  356. is_global: bool,
  357. ) -> Result<(), IoError>
  358. where
  359. W: Write,
  360. {
  361. let ident = to_snake_case(&cmd.proto.ident);
  362. let idents = gen_parameters(cmd, true, false);
  363. let typed_params = gen_parameters(cmd, false, true);
  364. let mut print_ln = String::new();
  365. let mut print_err = String::new();
  366. if self.generate_debug {
  367. print_ln = format!(
  368. r#"
  369. {log_fn}("[OpenGL] {}({})" {});
  370. "#,
  371. ident,
  372. (0..idents.len())
  373. .map(|_| "{:?}".to_string())
  374. .collect::<Vec<_>>()
  375. .join(", "),
  376. idents
  377. .iter()
  378. .zip(typed_params.iter())
  379. .map(|(name, ty)| if ty.contains("GLDEBUGPROC") {
  380. format!(r#", "<callback>""#)
  381. } else {
  382. format!(r#", {}"#, name)
  383. })
  384. .collect::<Vec<_>>()
  385. .concat(),
  386. log_fn = self.log_fn,
  387. );
  388. if cmd.proto.ident != "GetError" && has_get_error {
  389. print_err = format!(
  390. r#"
  391. let __get_err = __gl_imports::transmute::<_, extern "system" fn() -> u32>({this}get_error.f);
  392. match __get_err() {{
  393. 0 => (),
  394. r => {log_fn}("[OpenGL] ^ GL error triggered: {{}}", r),
  395. }}
  396. "#,
  397. this = if is_global { "storage::" } else { "self." },
  398. log_fn = self.log_fn,
  399. );
  400. }
  401. }
  402. write!(
  403. dest,
  404. r#"
  405. #[inline]
  406. pub fn {name}({this_ty}{params}) -> {return_suffix} {{
  407. unsafe {{{print_ln}
  408. let __f = __gl_imports::transmute::<_, extern "system" fn({typed_params}) -> {return_suffix}>({this}{name}.f);
  409. let __r = __f({idents});
  410. {print_err}
  411. __r
  412. }}
  413. }}"#,
  414. this_ty = if is_global { "" } else { "&self, " },
  415. this = if is_global { "storage::" } else { "self." },
  416. name = ident,
  417. params = gen_parameters(cmd, true, true).join(", "),
  418. typed_params = typed_params.join(", "),
  419. return_suffix = cmd.proto.ty,
  420. idents = idents.join(", "),
  421. print_ln = print_ln,
  422. print_err = print_err,
  423. )
  424. }
  425. }
  426. pub fn gen_parameters(cmd: &Cmd, with_idents: bool, with_types: bool) -> Vec<String> {
  427. cmd.params
  428. .iter()
  429. .map(|binding| {
  430. if with_idents && with_types {
  431. format!("{}: {}", to_snake_case(&binding.ident), binding.ty)
  432. } else if with_types {
  433. format!("{}", binding.ty)
  434. } else if with_idents {
  435. format!("{}", to_snake_case(&binding.ident))
  436. } else {
  437. panic!()
  438. }
  439. })
  440. .collect()
  441. }
  442. fn to_snake_case(s: &str) -> String {
  443. lazy_static! {
  444. static ref RX01: Regex = Regex::new(r"([a-z])([A-Z])").unwrap();
  445. static ref RX02: Regex = Regex::new(r"([a-z])([0-9][0-9A-Za-z]+)$").unwrap();
  446. static ref RX03: Regex = Regex::new(r"([A-Z])([A-Z][a-z]+)").unwrap();
  447. static ref RX04: Regex = Regex::new(r"([A-Z])([0-9])").unwrap();
  448. static ref RX05: Regex = Regex::new(r"([A-Z][a-z]*)(uiv|usv)$").unwrap();
  449. static ref RX06: Regex = Regex::new(r"([A-Z][a-z]*)(dv|fv|iv)$").unwrap();
  450. static ref RX07: Regex = Regex::new(r"([A-Z][a-z]*)(v|f|i)$").unwrap();
  451. static ref RX08: Regex = Regex::new(r"i_64").unwrap();
  452. static ref RX09: Regex = Regex::new(r"u_i64").unwrap();
  453. static ref RX10: Regex = Regex::new(r"f_i").unwrap();
  454. static ref RX11: Regex = Regex::new(r"([a-z]{3,})i$").unwrap();
  455. static ref RX12: Regex = Regex::new(r"([a-z])i_v").unwrap();
  456. static ref RX13: Regex = Regex::new(r"([a-z])i64_v").unwrap();
  457. static ref RX14: Regex = Regex::new(r"[Ii]nteger_64").unwrap();
  458. }
  459. let s = RX01.replace_all(s, |c: &Captures| format!("{}_{}", &c[1], &c[2]));
  460. let s = RX02.replace_all(&s, |c: &Captures| format!("{}_{}", &c[1], &c[2]));
  461. let s = RX03.replace_all(&s, |c: &Captures| format!("{}_{}", &c[1], &c[2]));
  462. let s = RX04.replace_all(&s, |c: &Captures| format!("{}_{}", &c[1], &c[2]));
  463. let s = RX05.replace_all(&s, |c: &Captures| format!("{}_{}", &c[1], &c[2]));
  464. let s = RX06.replace_all(&s, |c: &Captures| format!("{}_{}", &c[1], &c[2]));
  465. let s = RX07.replace_all(&s, |c: &Captures| format!("{}_{}", &c[1], &c[2]));
  466. let s = RX08.replace_all(&s, "_i64");
  467. let s = RX09.replace_all(&s, "_ui64");
  468. let s = RX10.replace_all(&s, "_fi");
  469. let s = RX11.replace_all(&s, |c: &Captures| format!("{}_i", &c[1]));
  470. let s = RX12.replace_all(&s, |c: &Captures| format!("{}_i_v", &c[1]));
  471. let s = RX13.replace_all(&s, |c: &Captures| format!("{}_i64_v", &c[1]));
  472. let s = RX14.replace_all(&s, "Integer64");
  473. s.into_owned().to_lowercase()
  474. }