1use std::path::PathBuf;
2use std::{
3 error::Error,
4 fs::{File, OpenOptions},
5 io::{self, Write},
6 path::Path,
7};
8use std::convert::identity;
9
10use crate::{generate, GenerateKind};
11
12pub struct Builder {
13 options: BindgenOptions,
14}
15
16pub struct BindgenOptions {
17 pub input_bindgen_files: Vec<PathBuf>,
18 pub input_extern_files: Vec<PathBuf>,
19 pub method_filter: fn(method_name: String) -> bool,
20 pub rust_method_type_path: String,
21 pub rust_method_prefix: String,
22 pub rust_file_header: String,
23 pub csharp_namespace: String,
24 pub csharp_class_name: String,
25 pub csharp_dll_name: String,
26 pub csharp_disable_emit_dll_name: bool,
27 pub csharp_class_accessibility: String,
28 pub csharp_entry_point_prefix: String,
29 pub csharp_method_prefix: String,
30 pub csharp_if_symbol: String,
31 pub csharp_if_dll_name: String,
32 pub csharp_use_function_pointer: bool,
33 pub csharp_use_nint_types: bool,
34 pub csharp_imported_namespaces: Vec<String>,
35 pub csharp_generate_const_filter: fn(const_name: &str) -> bool,
36 pub csharp_type_rename: fn(type_name: String) -> String,
37 pub csharp_file_header: String,
38 pub csharp_file_footer: String,
39 pub always_included_types: Vec<String>,
40}
41
42impl Default for Builder {
43 fn default() -> Self {
44 Self {
45 options: BindgenOptions {
46 input_bindgen_files: vec![],
47 input_extern_files: vec![],
48 method_filter: |x| !x.starts_with('_'),
49 rust_method_type_path: "".to_string(),
50 rust_method_prefix: "csbindgen_".to_string(),
51 rust_file_header: "".to_string(),
52 csharp_namespace: "CsBindgen".to_string(),
53 csharp_class_name: "NativeMethods".to_string(),
54 csharp_dll_name: "".to_string(),
55 csharp_disable_emit_dll_name: false,
56 csharp_entry_point_prefix: "".to_string(),
57 csharp_method_prefix: "".to_string(),
58 csharp_class_accessibility: "internal".to_string(),
59 csharp_if_symbol: "".to_string(),
60 csharp_if_dll_name: "".to_string(),
61 csharp_use_function_pointer: true,
62 csharp_use_nint_types: true,
63 csharp_imported_namespaces: vec![],
64 csharp_generate_const_filter: |_| false,
65 csharp_type_rename: identity,
66 csharp_file_header: "".to_string(),
67 csharp_file_footer: "".to_string(),
68 always_included_types: vec![],
69 },
70 }
71 }
72}
73
74impl Builder {
75 pub fn new() -> Self {
76 Self::default()
77 }
78
79 pub fn input_bindgen_file<T: AsRef<Path>>(mut self, input_bindgen_file: T) -> Builder {
81 self.options.input_bindgen_files.push(input_bindgen_file.as_ref().to_path_buf());
82 self
83 }
84
85 pub fn input_extern_file<T: AsRef<Path>>(mut self, input_extern_file: T) -> Builder {
87 self.options
88 .input_extern_files
89 .push(input_extern_file.as_ref().to_path_buf());
90 self
91 }
92
93 pub fn method_filter(mut self, method_filter: fn(method_name: String) -> bool) -> Builder {
95 self.options.method_filter = method_filter;
96 self
97 }
98
99 pub fn always_included_types<I, S>(mut self, always_included_types: I) -> Builder
102 where I: IntoIterator<Item = S>, S: ToString
103 {
104 self.options.always_included_types.extend(always_included_types.into_iter().map(|v| v.to_string()));
105 self
106 }
107
108 pub fn rust_method_type_path<T: Into<String>>(mut self, rust_method_type_path: T) -> Builder {
111 self.options.rust_method_type_path = rust_method_type_path.into();
112 self
113 }
114
115 pub fn rust_method_prefix<T: Into<String>>(mut self, rust_method_prefix: T) -> Builder {
118 self.options.rust_method_prefix = rust_method_prefix.into();
119 self
120 }
121
122 pub fn rust_file_header<T: Into<String>>(mut self, rust_file_header: T) -> Builder {
125 self.options.rust_file_header = rust_file_header.into();
126 self
127 }
128
129 pub fn csharp_namespace<T: Into<String>>(mut self, csharp_namespace: T) -> Builder {
132 self.options.csharp_namespace = csharp_namespace.into();
133 self
134 }
135
136 pub fn csharp_import_namespace<T: Into<String>>(mut self, csharp_namespace: T) -> Builder {
139 self.options
140 .csharp_imported_namespaces
141 .push(csharp_namespace.into());
142 self
143 }
144
145 pub fn csharp_class_name<T: Into<String>>(mut self, csharp_class_name: T) -> Builder {
148 self.options.csharp_class_name = csharp_class_name.into();
149 self
150 }
151
152 pub fn csharp_dll_name<T: Into<String>>(mut self, csharp_dll_name: T) -> Builder {
155 self.options.csharp_dll_name = csharp_dll_name.into();
156 self
157 }
158
159 pub fn csharp_disable_emit_dll_name(mut self, csharp_disable_emit_dll_name: bool) -> Builder {
161 self.options.csharp_disable_emit_dll_name = csharp_disable_emit_dll_name;
162 self
163 }
164
165 pub fn csharp_entry_point_prefix<T: Into<String>>(
168 mut self,
169 csharp_entry_point_prefix: T,
170 ) -> Builder {
171 self.options.csharp_entry_point_prefix = csharp_entry_point_prefix.into();
172 self
173 }
174
175 pub fn csharp_method_prefix<T: Into<String>>(mut self, csharp_method_prefix: T) -> Builder {
178 self.options.csharp_method_prefix = csharp_method_prefix.into();
179 self
180 }
181
182 pub fn csharp_class_accessibility<T: Into<String>>(
185 mut self,
186 csharp_class_accessibility: T,
187 ) -> Builder {
188 self.options.csharp_class_accessibility = csharp_class_accessibility.into();
189 self
190 }
191
192 pub fn csharp_dll_name_if<T: Into<String>>(mut self, if_symbol: T, if_dll_name: T) -> Builder {
195 self.options.csharp_if_symbol = if_symbol.into();
196 self.options.csharp_if_dll_name = if_dll_name.into();
197 self
198 }
199
200 pub fn csharp_use_function_pointer(mut self, csharp_use_function_pointer: bool) -> Builder {
202 self.options.csharp_use_function_pointer = csharp_use_function_pointer;
203 self
204 }
205
206 pub fn csharp_use_nint_types(mut self, csharp_use_nint_types: bool) -> Builder {
209 self.options.csharp_use_nint_types = csharp_use_nint_types;
210 self
211 }
212
213 #[deprecated(note = "User csharp_generate_const_filter instead")]
216 pub fn csharp_generate_const(self, csharp_generate_const: bool) -> Builder {
217 self.csharp_generate_const_filter(if csharp_generate_const { |_| true } else { |_| false })
218 }
219
220 pub fn csharp_generate_const_filter(mut self, csharp_generate_const_filter: fn(const_name: &str) -> bool) -> Builder {
222 self.options.csharp_generate_const_filter = csharp_generate_const_filter;
223 self
224 }
225
226 pub fn csharp_type_rename(mut self, csharp_type_rename: fn(rust_type_name: String) -> String) -> Builder {
228 self.options.csharp_type_rename = csharp_type_rename;
229 self
230 }
231
232 pub fn csharp_file_header<T: Into<String>>(mut self, csharp_file_header: T) -> Builder {
234 self.options.csharp_file_header = csharp_file_header.into();
235 self
236 }
237
238 pub fn csharp_file_footer<T: Into<String>>(mut self, csharp_file_footer: T) -> Builder {
240 self.options.csharp_file_footer = csharp_file_footer.into();
241 self
242 }
243
244 pub fn generate_csharp_file<P: AsRef<Path>>(
245 &self,
246 csharp_output_path: P,
247 ) -> Result<(), Box<dyn Error>> {
248 if !self.options.input_bindgen_files.is_empty() {
249 let (_, csharp) = generate(GenerateKind::InputBindgen, &self.options)?;
250
251 let mut csharp_file = make_file(csharp_output_path.as_ref())?;
252 csharp_file.write_all(csharp.as_bytes())?;
253 csharp_file.flush()?;
254 }
255
256 if self.has_input_externals() {
257 let (_, csharp) = generate(GenerateKind::InputExtern, &self.options)?;
258
259 let mut csharp_file = make_file(csharp_output_path.as_ref())?;
260 csharp_file.write_all(csharp.as_bytes())?;
261 csharp_file.flush()?;
262 }
263
264 Ok(())
265 }
266
267 fn has_input_files(&self) -> bool {
268 !self.options.input_bindgen_files.is_empty()
269 }
270 fn has_input_externals(&self) -> bool {
271 !self.options.input_extern_files.is_empty()
272 }
273
274 pub fn generate_to_file<P: AsRef<Path>>(
275 &self,
276 rust_output_path: P,
277 csharp_output_path: P,
278 ) -> Result<(), Box<dyn Error>> {
279 if self.has_input_files() {
280 let (rust, csharp) = generate(GenerateKind::InputBindgen, &self.options)?;
281
282 if let Some(rust) = rust {
283 let mut rust_file = make_file(rust_output_path.as_ref())?;
284
285 rust_file.write_all(rust.as_bytes())?;
286 rust_file.flush()?;
287 }
288
289 let mut csharp_file = make_file(csharp_output_path.as_ref())?;
290 csharp_file.write_all(csharp.as_bytes())?;
291 csharp_file.flush()?;
292 }
293
294 if self.has_input_externals() {
295 let (rust, csharp) = generate(GenerateKind::InputExtern, &self.options)?;
296
297 if let Some(rust) = rust {
298 let mut rust_file = make_file(rust_output_path.as_ref())?;
299
300 rust_file.write_all(rust.as_bytes())?;
301 rust_file.flush()?;
302 }
303
304 let mut csharp_file = make_file(csharp_output_path.as_ref())?;
305 csharp_file.write_all(csharp.as_bytes())?;
306 csharp_file.flush()?;
307 }
308
309 Ok(())
310 }
311}
312
313fn make_file<P: AsRef<Path>>(path: P) -> io::Result<File> {
314 let path = path.as_ref();
315 if let Some(parent) = path.parent() {
316 std::fs::create_dir_all(parent)?;
317 }
318 let file = OpenOptions::new()
319 .write(true)
320 .truncate(true)
321 .create(true)
322 .open(path)?;
323 Ok(file)
324}