bindgen/codegen/
dyngen.rs
1use crate::codegen;
2use crate::ir::context::BindgenContext;
3use crate::ir::function::ClangAbi;
4use proc_macro2::{Ident, TokenStream};
5
6#[derive(Default)]
8pub(crate) struct DynamicItems {
9 struct_members: Vec<TokenStream>,
18
19 struct_implementation: Vec<TokenStream>,
30
31 constructor_inits: Vec<TokenStream>,
49
50 init_fields: Vec<TokenStream>,
69}
70
71impl DynamicItems {
72 pub(crate) fn new() -> Self {
73 Self::default()
74 }
75
76 pub(crate) fn get_tokens(
77 &self,
78 lib_ident: Ident,
79 ctx: &BindgenContext,
80 ) -> TokenStream {
81 let struct_members = &self.struct_members;
82 let constructor_inits = &self.constructor_inits;
83 let init_fields = &self.init_fields;
84 let struct_implementation = &self.struct_implementation;
85
86 let library_new = if ctx.options().wrap_unsafe_ops {
87 quote!(unsafe { ::libloading::Library::new(path) })
88 } else {
89 quote!(::libloading::Library::new(path))
90 };
91
92 let from_library = if ctx.options().wrap_unsafe_ops {
93 quote!(unsafe { Self::from_library(library) })
94 } else {
95 quote!(Self::from_library(library))
96 };
97
98 quote! {
99 pub struct #lib_ident {
100 __library: ::libloading::Library,
101 #(#struct_members)*
102 }
103
104 impl #lib_ident {
105 pub unsafe fn new<P>(
106 path: P
107 ) -> Result<Self, ::libloading::Error>
108 where P: AsRef<::std::ffi::OsStr> {
109 let library = #library_new?;
110 #from_library
111 }
112
113 pub unsafe fn from_library<L>(
114 library: L
115 ) -> Result<Self, ::libloading::Error>
116 where L: Into<::libloading::Library> {
117 let __library = library.into();
118 #( #constructor_inits )*
119 Ok(#lib_ident {
120 __library,
121 #( #init_fields ),*
122 })
123 }
124
125 #( #struct_implementation )*
126 }
127 }
128 }
129
130 #[allow(clippy::too_many_arguments)]
131 pub(crate) fn push_func(
132 &mut self,
133 ident: Ident,
134 abi: ClangAbi,
135 is_variadic: bool,
136 is_required: bool,
137 args: Vec<TokenStream>,
138 args_identifiers: Vec<TokenStream>,
139 ret: TokenStream,
140 ret_ty: TokenStream,
141 attributes: Vec<TokenStream>,
142 ctx: &BindgenContext,
143 ) {
144 if !is_variadic {
145 assert_eq!(args.len(), args_identifiers.len());
146 }
147
148 let signature = quote! { unsafe extern #abi fn ( #( #args),* ) #ret };
149 let member = if is_required {
150 signature
151 } else {
152 quote! { Result<#signature, ::libloading::Error> }
153 };
154
155 self.struct_members.push(quote! {
156 pub #ident: #member,
157 });
158
159 let fn_ = if is_required {
162 quote! { self.#ident }
163 } else {
164 quote! { self.#ident.as_ref().expect("Expected function, got error.") }
165 };
166 let call_body = if ctx.options().wrap_unsafe_ops {
167 quote!(unsafe { (#fn_)(#( #args_identifiers ),*) })
168 } else {
169 quote!((#fn_)(#( #args_identifiers ),*) )
170 };
171
172 if !is_variadic {
175 self.struct_implementation.push(quote! {
176 #(#attributes)*
177 pub unsafe fn #ident ( &self, #( #args ),* ) #ret_ty {
178 #call_body
179 }
180 });
181 }
182
183 let ident_str = codegen::helpers::ast_ty::cstr_expr(ident.to_string());
185 let library_get = if ctx.options().wrap_unsafe_ops {
186 quote!(unsafe { __library.get(#ident_str) })
187 } else {
188 quote!(__library.get(#ident_str))
189 };
190
191 self.constructor_inits.push(if is_required {
192 quote! {
193 let #ident = #library_get.map(|sym| *sym)?;
194 }
195 } else {
196 quote! {
197 let #ident = #library_get.map(|sym| *sym);
198 }
199 });
200
201 self.init_fields.push(quote! {
202 #ident
203 });
204 }
205
206 pub fn push_var(
207 &mut self,
208 ident: Ident,
209 ty: TokenStream,
210 is_required: bool,
211 wrap_unsafe_ops: bool,
212 ) {
213 let member = if is_required {
214 quote! { *mut #ty }
215 } else {
216 quote! { Result<*mut #ty, ::libloading::Error> }
217 };
218
219 self.struct_members.push(quote! {
220 pub #ident: #member,
221 });
222
223 let deref = if is_required {
224 quote! { self.#ident }
225 } else {
226 quote! { *self.#ident.as_ref().expect("Expected variable, got error.") }
227 };
228 self.struct_implementation.push(quote! {
229 pub unsafe fn #ident (&self) -> *mut #ty {
230 #deref
231 }
232 });
233
234 let ident_str = codegen::helpers::ast_ty::cstr_expr(ident.to_string());
235
236 let library_get = if wrap_unsafe_ops {
237 quote!(unsafe { __library.get::<*mut #ty>(#ident_str) })
238 } else {
239 quote!(__library.get::<*mut #ty>(#ident_str))
240 };
241
242 let qmark = if is_required { quote!(?) } else { quote!() };
243
244 let var_get = quote! {
245 let #ident = #library_get.map(|sym| *sym)#qmark;
246 };
247
248 self.constructor_inits.push(var_get);
249
250 self.init_fields.push(quote! {
251 #ident
252 });
253 }
254}