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_dll_imports: Vec<(String, String)>,
31 pub csharp_use_function_pointer: bool,
32 pub csharp_use_nint_types: bool,
33 pub csharp_imported_namespaces: Vec<String>,
34 pub csharp_generate_const_filter: fn(const_name: &str) -> bool,
35 pub csharp_type_rename: fn(type_name: String) -> String,
36 pub csharp_file_header: String,
37 pub csharp_file_footer: String,
38 pub always_included_types: Vec<String>,
39}
40
41impl Default for Builder {
42 fn default() -> Self {
43 Self {
44 options: BindgenOptions {
45 input_bindgen_files: vec![],
46 input_extern_files: vec![],
47 method_filter: |x| !x.starts_with('_'),
48 rust_method_type_path: "".to_string(),
49 rust_method_prefix: "csbindgen_".to_string(),
50 rust_file_header: "".to_string(),
51 csharp_namespace: "CsBindgen".to_string(),
52 csharp_class_name: "NativeMethods".to_string(),
53 csharp_dll_name: "".to_string(),
54 csharp_disable_emit_dll_name: false,
55 csharp_entry_point_prefix: "".to_string(),
56 csharp_method_prefix: "".to_string(),
57 csharp_class_accessibility: "internal".to_string(),
58 csharp_if_dll_imports: vec![],
59 csharp_use_function_pointer: true,
60 csharp_use_nint_types: true,
61 csharp_imported_namespaces: vec![],
62 csharp_generate_const_filter: |_| false,
63 csharp_type_rename: identity,
64 csharp_file_header: "".to_string(),
65 csharp_file_footer: "".to_string(),
66 always_included_types: vec![],
67 },
68 }
69 }
70}
71
72impl Builder {
73 pub fn new() -> Self {
74 Self::default()
75 }
76
77 pub fn input_bindgen_file<T: AsRef<Path>>(mut self, input_bindgen_file: T) -> Builder {
79 self.options.input_bindgen_files.push(input_bindgen_file.as_ref().to_path_buf());
80 self
81 }
82
83 pub fn input_extern_file<T: AsRef<Path>>(mut self, input_extern_file: T) -> Builder {
85 self.options
86 .input_extern_files
87 .push(input_extern_file.as_ref().to_path_buf());
88 self
89 }
90
91 pub fn method_filter(mut self, method_filter: fn(method_name: String) -> bool) -> Builder {
93 self.options.method_filter = method_filter;
94 self
95 }
96
97 pub fn always_included_types<I, S>(mut self, always_included_types: I) -> Builder
100 where I: IntoIterator<Item = S>, S: ToString
101 {
102 self.options.always_included_types.extend(always_included_types.into_iter().map(|v| v.to_string()));
103 self
104 }
105
106 pub fn rust_method_type_path<T: Into<String>>(mut self, rust_method_type_path: T) -> Builder {
109 self.options.rust_method_type_path = rust_method_type_path.into();
110 self
111 }
112
113 pub fn rust_method_prefix<T: Into<String>>(mut self, rust_method_prefix: T) -> Builder {
116 self.options.rust_method_prefix = rust_method_prefix.into();
117 self
118 }
119
120 pub fn rust_file_header<T: Into<String>>(mut self, rust_file_header: T) -> Builder {
123 self.options.rust_file_header = rust_file_header.into();
124 self
125 }
126
127 pub fn csharp_namespace<T: Into<String>>(mut self, csharp_namespace: T) -> Builder {
130 self.options.csharp_namespace = csharp_namespace.into();
131 self
132 }
133
134 pub fn csharp_import_namespace<T: Into<String>>(mut self, csharp_namespace: T) -> Builder {
137 self.options
138 .csharp_imported_namespaces
139 .push(csharp_namespace.into());
140 self
141 }
142
143 pub fn csharp_class_name<T: Into<String>>(mut self, csharp_class_name: T) -> Builder {
146 self.options.csharp_class_name = csharp_class_name.into();
147 self
148 }
149
150 pub fn csharp_dll_name<T: Into<String>>(mut self, csharp_dll_name: T) -> Builder {
153 self.options.csharp_dll_name = csharp_dll_name.into();
154 self
155 }
156
157 pub fn csharp_disable_emit_dll_name(mut self, csharp_disable_emit_dll_name: bool) -> Builder {
159 self.options.csharp_disable_emit_dll_name = csharp_disable_emit_dll_name;
160 self
161 }
162
163 pub fn csharp_entry_point_prefix<T: Into<String>>(
166 mut self,
167 csharp_entry_point_prefix: T,
168 ) -> Builder {
169 self.options.csharp_entry_point_prefix = csharp_entry_point_prefix.into();
170 self
171 }
172
173 pub fn csharp_method_prefix<T: Into<String>>(mut self, csharp_method_prefix: T) -> Builder {
176 self.options.csharp_method_prefix = csharp_method_prefix.into();
177 self
178 }
179
180 pub fn csharp_class_accessibility<T: Into<String>>(
183 mut self,
184 csharp_class_accessibility: T,
185 ) -> Builder {
186 self.options.csharp_class_accessibility = csharp_class_accessibility.into();
187 self
188 }
189
190 pub fn csharp_dll_name_if<T: Into<String>>(mut self, if_symbol: T, if_dll_name: T) -> Builder {
193 self.options.csharp_if_dll_imports.push((if_symbol.into(), if_dll_name.into()));
194 self
195 }
196
197 pub fn csharp_use_function_pointer(mut self, csharp_use_function_pointer: bool) -> Builder {
199 self.options.csharp_use_function_pointer = csharp_use_function_pointer;
200 self
201 }
202
203 pub fn csharp_use_nint_types(mut self, csharp_use_nint_types: bool) -> Builder {
206 self.options.csharp_use_nint_types = csharp_use_nint_types;
207 self
208 }
209
210 #[deprecated(note = "User csharp_generate_const_filter instead")]
213 pub fn csharp_generate_const(self, csharp_generate_const: bool) -> Builder {
214 self.csharp_generate_const_filter(if csharp_generate_const { |_| true } else { |_| false })
215 }
216
217 pub fn csharp_generate_const_filter(mut self, csharp_generate_const_filter: fn(const_name: &str) -> bool) -> Builder {
219 self.options.csharp_generate_const_filter = csharp_generate_const_filter;
220 self
221 }
222
223 pub fn csharp_type_rename(mut self, csharp_type_rename: fn(rust_type_name: String) -> String) -> Builder {
225 self.options.csharp_type_rename = csharp_type_rename;
226 self
227 }
228
229 pub fn csharp_file_header<T: Into<String>>(mut self, csharp_file_header: T) -> Builder {
231 self.options.csharp_file_header = csharp_file_header.into();
232 self
233 }
234
235 pub fn csharp_file_footer<T: Into<String>>(mut self, csharp_file_footer: T) -> Builder {
237 self.options.csharp_file_footer = csharp_file_footer.into();
238 self
239 }
240
241 pub fn generate_csharp_file<P: AsRef<Path>>(
242 &self,
243 csharp_output_path: P,
244 ) -> Result<(), Box<dyn Error>> {
245 if !self.options.input_bindgen_files.is_empty() {
246 let (_, csharp) = generate(GenerateKind::InputBindgen, &self.options)?;
247
248 let mut csharp_file = make_file(csharp_output_path.as_ref())?;
249 csharp_file.write_all(csharp.as_bytes())?;
250 csharp_file.flush()?;
251 }
252
253 if self.has_input_externals() {
254 let (_, csharp) = generate(GenerateKind::InputExtern, &self.options)?;
255
256 let mut csharp_file = make_file(csharp_output_path.as_ref())?;
257 csharp_file.write_all(csharp.as_bytes())?;
258 csharp_file.flush()?;
259 }
260
261 Ok(())
262 }
263
264 fn has_input_files(&self) -> bool {
265 !self.options.input_bindgen_files.is_empty()
266 }
267 fn has_input_externals(&self) -> bool {
268 !self.options.input_extern_files.is_empty()
269 }
270
271 pub fn generate_to_file<P: AsRef<Path>>(
272 &self,
273 rust_output_path: P,
274 csharp_output_path: P,
275 ) -> Result<(), Box<dyn Error>> {
276 if self.has_input_files() {
277 let (rust, csharp) = generate(GenerateKind::InputBindgen, &self.options)?;
278
279 if let Some(rust) = rust {
280 let mut rust_file = make_file(rust_output_path.as_ref())?;
281
282 rust_file.write_all(rust.as_bytes())?;
283 rust_file.flush()?;
284 }
285
286 let mut csharp_file = make_file(csharp_output_path.as_ref())?;
287 csharp_file.write_all(csharp.as_bytes())?;
288 csharp_file.flush()?;
289 }
290
291 if self.has_input_externals() {
292 let (rust, csharp) = generate(GenerateKind::InputExtern, &self.options)?;
293
294 if let Some(rust) = rust {
295 let mut rust_file = make_file(rust_output_path.as_ref())?;
296
297 rust_file.write_all(rust.as_bytes())?;
298 rust_file.flush()?;
299 }
300
301 let mut csharp_file = make_file(csharp_output_path.as_ref())?;
302 csharp_file.write_all(csharp.as_bytes())?;
303 csharp_file.flush()?;
304 }
305
306 Ok(())
307 }
308}
309
310fn make_file<P: AsRef<Path>>(path: P) -> io::Result<File> {
311 let path = path.as_ref();
312 if let Some(parent) = path.parent() {
313 std::fs::create_dir_all(parent)?;
314 }
315 let file = OpenOptions::new()
316 .write(true)
317 .truncate(true)
318 .create(true)
319 .open(path)?;
320 Ok(file)
321}