diff options
Diffstat (limited to 'src/repeat.rs')
-rw-r--r-- | src/repeat.rs | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/src/repeat.rs b/src/repeat.rs new file mode 100644 index 0000000..2f55ee8 --- /dev/null +++ b/src/repeat.rs @@ -0,0 +1,217 @@ +use std::str::FromStr; + +use convert_case::{Case, Casing}; +use opengl_registry::Registry; +use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree}; + +use crate::str::c_ptr_to_rust_ptr; +use crate::token_stream::TokenStreamExt; +use crate::{ + OPENGL_CMD_ARGS_REPLACE, + OPENGL_CMD_ARG_NAMES_REPLACE, + OPENGL_CMD_ARG_TYPES_REPLACE, + OPENGL_CMD_IDENT_REPLACE, + OPENGL_CMD_RET_TYPE_REPLACE, +}; + +pub fn for_each_opengl_command_impl( + input_stream: &TokenStream, + opengl_registry: &Registry, +) -> TokenStream +{ + let gl_func_ident_index_paths = input_stream + .find_all_ident(&Ident::new(OPENGL_CMD_IDENT_REPLACE, Span::call_site())); + + let gl_func_ret_type_index_paths = input_stream + .find_all_ident(&Ident::new(OPENGL_CMD_RET_TYPE_REPLACE, Span::call_site())); + + let out: TokenStream = opengl_registry + .commands() + .iter() + .map(|gl_command| { + let stream = input_stream.replace_tokens( + &gl_func_ident_index_paths, + &TokenTree::Ident(Ident::new( + gl_command.prototype().name(), + Span::call_site(), + )), + ); + + let return_type = gl_command.prototype().return_type(); + + let stream = stream.replace_tokens( + &gl_func_ret_type_index_paths, + &TokenTree::Group(Group::new( + Delimiter::None, + TokenStream::from_str(&fix_type(return_type)).unwrap(), + )), + ); + + let gl_func_args_paths = stream + .find_all_ident(&Ident::new(OPENGL_CMD_ARGS_REPLACE, Span::call_site())); + + let stream = stream.replace_tokens( + &gl_func_args_paths, + &TokenTree::Group(Group::new( + Delimiter::None, + TokenStream::from_str( + &gl_command + .parameters() + .iter() + .map(|param| { + let param_name = clean_param_name(param.name()); + let param_type = fix_type(param.get_type()); + + format!("{param_name}: {param_type}") + }) + .collect::<Vec<_>>() + .join(","), + ) + .unwrap(), + )), + ); + + let gl_func_arg_names_paths = stream.find_all_ident(&Ident::new( + OPENGL_CMD_ARG_NAMES_REPLACE, + Span::call_site(), + )); + + let stream = stream.replace_tokens( + &gl_func_arg_names_paths, + &TokenTree::Group(Group::new( + Delimiter::None, + TokenStream::from_str( + &gl_command + .parameters() + .iter() + .map(|param| clean_param_name(param.name())) + .collect::<Vec<_>>() + .join(","), + ) + .unwrap(), + )), + ); + + let gl_func_arg_types_paths = stream.find_all_ident(&Ident::new( + OPENGL_CMD_ARG_TYPES_REPLACE, + Span::call_site(), + )); + + stream.replace_tokens( + &gl_func_arg_types_paths, + &TokenTree::Group(Group::new( + Delimiter::None, + TokenStream::from_str( + &gl_command + .parameters() + .iter() + .map(|param| fix_type(param.get_type())) + .collect::<Vec<_>>() + .join(","), + ) + .unwrap(), + )), + ) + }) + .collect(); + + out +} + +fn clean_param_name(param_name: &str) -> String +{ + match param_name { + "ref" => "reference", + "type" => "ty", + "in" => "inside", + "box" => "a_box", + name => name, + } + .to_case(Case::Snake) +} + +fn fix_type(ty: &str) -> String +{ + let ty = ty.replace("struct", ""); + + let ty = c_ptr_to_rust_ptr(&ty); + + ty.replace("void", "std::ffi::c_void") +} + +#[cfg(test)] +mod tests +{ + use opengl_registry::command::{Command, Parameter, Prototype}; + use pretty_assertions::assert_eq; + use quote::quote; + + use super::*; + + #[test] + fn for_each_opengl_command_impl_works() + { + let registry = Registry::new(vec![ + Command::new(Prototype::new("glBindBuffer", "void"), vec![]), + Command::new( + Prototype::new("glActiveTexture", "void"), + vec![ + Parameter::new("abc", "GLuint"), + Parameter::new("xyz", "GLshort"), + ], + ), + Command::new( + Prototype::new("glDrawArrays", "GLint"), + vec![Parameter::new("foo", "GLubyte")], + ), + ]); + + assert_eq!( + for_each_opengl_command_impl( + "e! { + unsafe { + functions::_gl_command_ = FunctionPtr::new_initialized( + get_proc_addr(stringify!(_gl_command_)) + ); + } + }, + ®istry, + ) + .to_string(), + quote! { + unsafe { + functions::glBindBuffer = FunctionPtr::new_initialized( + get_proc_addr(stringify!(glBindBuffer)) + ); + } + unsafe { + functions::glActiveTexture = FunctionPtr::new_initialized( + get_proc_addr(stringify!(glActiveTexture)) + ); + } + unsafe { + functions::glDrawArrays = FunctionPtr::new_initialized( + get_proc_addr(stringify!(glDrawArrays)) + ); + } + } + .to_string() + ); + + assert_eq!( + for_each_opengl_command_impl( + "e! { + fn _gl_command_(_gl_command_args_) -> _gl_command_ret_type_ {} + }, + ®istry, + ) + .to_string(), + quote! { + fn glBindBuffer() -> std::ffi::c_void {} + fn glActiveTexture(abc: GLuint, xyz: GLshort) -> std::ffi::c_void {} + fn glDrawArrays(foo: GLubyte) -> GLint {} + } + .to_string(), + ); + } +} |