1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 use std::path;
6 
7 use crate::bindgen::bindings::Bindings;
8 use crate::bindgen::cargo::Cargo;
9 use crate::bindgen::config::{Braces, Config, Language, Profile, Style};
10 use crate::bindgen::error::Error;
11 use crate::bindgen::library::Library;
12 use crate::bindgen::parser::{self, Parse};
13 
14 /// A builder for generating a bindings header.
15 #[derive(Debug, Clone)]
16 pub struct Builder {
17     config: Config,
18     srcs: Vec<path::PathBuf>,
19     lib: Option<(path::PathBuf, Option<String>)>,
20     lib_cargo: Option<Cargo>,
21     std_types: bool,
22     lockfile: Option<path::PathBuf>,
23 }
24 
25 impl Builder {
26     #[allow(clippy::new_without_default)]
new() -> Builder27     pub fn new() -> Builder {
28         Builder {
29             config: Config::default(),
30             srcs: Vec::new(),
31             lib: None,
32             lib_cargo: None,
33             std_types: true,
34             lockfile: None,
35         }
36     }
37 
38     #[allow(unused)]
with_header<S: AsRef<str>>(mut self, header: S) -> Builder39     pub fn with_header<S: AsRef<str>>(mut self, header: S) -> Builder {
40         self.config.header = Some(String::from(header.as_ref()));
41         self
42     }
43 
44     #[allow(unused)]
with_no_includes(mut self) -> Builder45     pub fn with_no_includes(mut self) -> Builder {
46         self.config.no_includes = true;
47         self
48     }
49 
50     #[allow(unused)]
with_include<S: AsRef<str>>(mut self, include: S) -> Builder51     pub fn with_include<S: AsRef<str>>(mut self, include: S) -> Builder {
52         self.config.includes.push(String::from(include.as_ref()));
53         self
54     }
55 
56     #[allow(unused)]
with_sys_include<S: AsRef<str>>(mut self, include: S) -> Builder57     pub fn with_sys_include<S: AsRef<str>>(mut self, include: S) -> Builder {
58         self.config
59             .sys_includes
60             .push(String::from(include.as_ref()));
61         self
62     }
63 
64     #[allow(unused)]
with_after_include<S: AsRef<str>>(mut self, line: S) -> Builder65     pub fn with_after_include<S: AsRef<str>>(mut self, line: S) -> Builder {
66         self.config.after_includes = Some(String::from(line.as_ref()));
67         self
68     }
69 
70     #[allow(unused)]
with_trailer<S: AsRef<str>>(mut self, trailer: S) -> Builder71     pub fn with_trailer<S: AsRef<str>>(mut self, trailer: S) -> Builder {
72         self.config.trailer = Some(String::from(trailer.as_ref()));
73         self
74     }
75 
76     #[allow(unused)]
with_include_guard<S: AsRef<str>>(mut self, include_guard: S) -> Builder77     pub fn with_include_guard<S: AsRef<str>>(mut self, include_guard: S) -> Builder {
78         self.config.include_guard = Some(String::from(include_guard.as_ref()));
79         self
80     }
81 
82     #[allow(unused)]
with_pragma_once(mut self, pragma_once: bool) -> Builder83     pub fn with_pragma_once(mut self, pragma_once: bool) -> Builder {
84         self.config.pragma_once = pragma_once;
85         self
86     }
87 
88     #[allow(unused)]
with_autogen_warning<S: AsRef<str>>(mut self, autogen_warning: S) -> Builder89     pub fn with_autogen_warning<S: AsRef<str>>(mut self, autogen_warning: S) -> Builder {
90         self.config.autogen_warning = Some(String::from(autogen_warning.as_ref()));
91         self
92     }
93 
94     #[allow(unused)]
with_include_version(mut self, include_version: bool) -> Builder95     pub fn with_include_version(mut self, include_version: bool) -> Builder {
96         self.config.include_version = include_version;
97         self
98     }
99 
100     #[allow(unused)]
with_namespace<S: AsRef<str>>(mut self, namespace: S) -> Builder101     pub fn with_namespace<S: AsRef<str>>(mut self, namespace: S) -> Builder {
102         self.config.namespace = Some(String::from(namespace.as_ref()));
103         self
104     }
105 
106     #[allow(unused)]
with_namespaces<S: AsRef<str>>(mut self, namespaces: &[S]) -> Builder107     pub fn with_namespaces<S: AsRef<str>>(mut self, namespaces: &[S]) -> Builder {
108         self.config.namespaces = Some(
109             namespaces
110                 .iter()
111                 .map(|x| String::from(x.as_ref()))
112                 .collect(),
113         );
114         self
115     }
116 
117     #[allow(unused)]
with_using_namespaces<S: AsRef<str>>(mut self, namespaces: &[S]) -> Builder118     pub fn with_using_namespaces<S: AsRef<str>>(mut self, namespaces: &[S]) -> Builder {
119         self.config.using_namespaces = Some(
120             namespaces
121                 .iter()
122                 .map(|x| String::from(x.as_ref()))
123                 .collect(),
124         );
125         self
126     }
127 
128     #[allow(unused)]
with_braces(mut self, braces: Braces) -> Builder129     pub fn with_braces(mut self, braces: Braces) -> Builder {
130         self.config.braces = braces;
131         self
132     }
133 
134     #[allow(unused)]
with_line_length(mut self, line_length: usize) -> Builder135     pub fn with_line_length(mut self, line_length: usize) -> Builder {
136         self.config.line_length = line_length;
137         self
138     }
139 
140     #[allow(unused)]
with_tab_width(mut self, tab_width: usize) -> Builder141     pub fn with_tab_width(mut self, tab_width: usize) -> Builder {
142         self.config.tab_width = tab_width;
143         self
144     }
145 
146     #[allow(unused)]
with_language(mut self, language: Language) -> Builder147     pub fn with_language(mut self, language: Language) -> Builder {
148         self.config.language = language;
149         self
150     }
151 
152     #[allow(unused)]
with_style(mut self, style: Style) -> Builder153     pub fn with_style(mut self, style: Style) -> Builder {
154         self.config.style = style;
155         self
156     }
157 
158     #[allow(unused)]
include_item<S: AsRef<str>>(mut self, item_name: S) -> Builder159     pub fn include_item<S: AsRef<str>>(mut self, item_name: S) -> Builder {
160         self.config
161             .export
162             .include
163             .push(String::from(item_name.as_ref()));
164         self
165     }
166 
167     #[allow(unused)]
exclude_item<S: AsRef<str>>(mut self, item_name: S) -> Builder168     pub fn exclude_item<S: AsRef<str>>(mut self, item_name: S) -> Builder {
169         self.config
170             .export
171             .exclude
172             .push(String::from(item_name.as_ref()));
173         self
174     }
175 
176     #[allow(unused)]
rename_item<S: AsRef<str>>(mut self, from: S, to: S) -> Builder177     pub fn rename_item<S: AsRef<str>>(mut self, from: S, to: S) -> Builder {
178         self.config
179             .export
180             .rename
181             .insert(String::from(from.as_ref()), String::from(to.as_ref()));
182         self
183     }
184 
185     #[allow(unused)]
with_item_prefix<S: AsRef<str>>(mut self, prefix: S) -> Builder186     pub fn with_item_prefix<S: AsRef<str>>(mut self, prefix: S) -> Builder {
187         self.config.export.prefix = Some(String::from(prefix.as_ref()));
188         self
189     }
190 
191     #[allow(unused)]
with_parse_deps(mut self, parse_deps: bool) -> Builder192     pub fn with_parse_deps(mut self, parse_deps: bool) -> Builder {
193         self.config.parse.parse_deps = parse_deps;
194         self
195     }
196 
197     #[allow(unused)]
with_parse_include<S: AsRef<str>>(mut self, include: &[S]) -> Builder198     pub fn with_parse_include<S: AsRef<str>>(mut self, include: &[S]) -> Builder {
199         self.config.parse.include =
200             Some(include.iter().map(|x| String::from(x.as_ref())).collect());
201         self
202     }
203 
204     #[allow(unused)]
with_parse_exclude<S: AsRef<str>>(mut self, exclude: &[S]) -> Builder205     pub fn with_parse_exclude<S: AsRef<str>>(mut self, exclude: &[S]) -> Builder {
206         self.config.parse.exclude = exclude.iter().map(|x| String::from(x.as_ref())).collect();
207         self
208     }
209 
210     #[allow(unused)]
with_parse_expand<S: AsRef<str>>(mut self, expand: &[S]) -> Builder211     pub fn with_parse_expand<S: AsRef<str>>(mut self, expand: &[S]) -> Builder {
212         self.config.parse.expand.crates = expand.iter().map(|x| String::from(x.as_ref())).collect();
213         self
214     }
215 
216     #[allow(unused)]
with_parse_expand_all_features(mut self, expand_all_features: bool) -> Builder217     pub fn with_parse_expand_all_features(mut self, expand_all_features: bool) -> Builder {
218         self.config.parse.expand.all_features = expand_all_features;
219         self
220     }
221 
222     #[allow(unused)]
with_parse_expand_default_features(mut self, expand_default_features: bool) -> Builder223     pub fn with_parse_expand_default_features(mut self, expand_default_features: bool) -> Builder {
224         self.config.parse.expand.default_features = expand_default_features;
225         self
226     }
227 
228     #[allow(unused)]
with_parse_expand_features<S: AsRef<str>>(mut self, expand_features: &[S]) -> Builder229     pub fn with_parse_expand_features<S: AsRef<str>>(mut self, expand_features: &[S]) -> Builder {
230         self.config.parse.expand.features = Some(
231             expand_features
232                 .iter()
233                 .map(|x| String::from(x.as_ref()))
234                 .collect(),
235         );
236         self
237     }
238 
239     #[allow(unused)]
with_parse_expand_profile(mut self, profile: Profile) -> Builder240     pub fn with_parse_expand_profile(mut self, profile: Profile) -> Builder {
241         self.config.parse.expand.profile = profile;
242         self
243     }
244 
245     #[allow(unused)]
with_parse_extra_bindings<S: AsRef<str>>(mut self, extra_bindings: &[S]) -> Builder246     pub fn with_parse_extra_bindings<S: AsRef<str>>(mut self, extra_bindings: &[S]) -> Builder {
247         self.config.parse.extra_bindings = extra_bindings
248             .iter()
249             .map(|x| String::from(x.as_ref()))
250             .collect();
251         self
252     }
253 
254     #[allow(unused)]
with_only_target_dependencies(mut self, only_target_dependencies: bool) -> Builder255     pub fn with_only_target_dependencies(mut self, only_target_dependencies: bool) -> Builder {
256         self.config.only_target_dependencies = only_target_dependencies;
257         self
258     }
259 
260     #[allow(unused)]
with_documentation(mut self, documentation: bool) -> Builder261     pub fn with_documentation(mut self, documentation: bool) -> Builder {
262         self.config.documentation = documentation;
263         self
264     }
265 
266     #[allow(unused)]
with_target_os_define(mut self, platform: &str, preprocessor_define: &str) -> Builder267     pub fn with_target_os_define(mut self, platform: &str, preprocessor_define: &str) -> Builder {
268         self.config.defines.insert(
269             format!("target_os = {}", platform),
270             preprocessor_define.to_owned(),
271         );
272         self
273     }
274 
275     #[allow(unused)]
with_define(mut self, key: &str, value: &str, preprocessor_define: &str) -> Builder276     pub fn with_define(mut self, key: &str, value: &str, preprocessor_define: &str) -> Builder {
277         self.config.defines.insert(
278             format!("{} = {}", key, value),
279             preprocessor_define.to_owned(),
280         );
281         self
282     }
283 
284     #[allow(unused)]
with_config(mut self, config: Config) -> Builder285     pub fn with_config(mut self, config: Config) -> Builder {
286         self.config = config;
287         self
288     }
289 
290     #[allow(unused)]
with_std_types(mut self, std_types: bool) -> Builder291     pub fn with_std_types(mut self, std_types: bool) -> Builder {
292         self.std_types = std_types;
293         self
294     }
295 
296     #[allow(unused)]
with_src<P: AsRef<path::Path>>(mut self, src: P) -> Builder297     pub fn with_src<P: AsRef<path::Path>>(mut self, src: P) -> Builder {
298         self.srcs.push(src.as_ref().to_owned());
299         self
300     }
301 
302     #[allow(unused)]
with_crate<P: AsRef<path::Path>>(mut self, lib_dir: P) -> Builder303     pub fn with_crate<P: AsRef<path::Path>>(mut self, lib_dir: P) -> Builder {
304         debug_assert!(self.lib.is_none());
305         debug_assert!(self.lib_cargo.is_none());
306         self.lib = Some((path::PathBuf::from(lib_dir.as_ref()), None));
307         self
308     }
309 
310     #[allow(unused)]
with_crate_and_name<P: AsRef<path::Path>, S: AsRef<str>>( mut self, lib_dir: P, binding_lib_name: S, ) -> Builder311     pub fn with_crate_and_name<P: AsRef<path::Path>, S: AsRef<str>>(
312         mut self,
313         lib_dir: P,
314         binding_lib_name: S,
315     ) -> Builder {
316         debug_assert!(self.lib.is_none());
317         debug_assert!(self.lib_cargo.is_none());
318         self.lib = Some((
319             path::PathBuf::from(lib_dir.as_ref()),
320             Some(String::from(binding_lib_name.as_ref())),
321         ));
322         self
323     }
324 
325     #[allow(unused)]
with_cargo(mut self, lib: Cargo) -> Builder326     pub(crate) fn with_cargo(mut self, lib: Cargo) -> Builder {
327         debug_assert!(self.lib.is_none());
328         debug_assert!(self.lib_cargo.is_none());
329         self.lib_cargo = Some(lib);
330         self
331     }
332 
333     #[allow(unused)]
with_lockfile<P: AsRef<path::Path>>(mut self, lockfile: P) -> Builder334     pub fn with_lockfile<P: AsRef<path::Path>>(mut self, lockfile: P) -> Builder {
335         debug_assert!(self.lockfile.is_none());
336         debug_assert!(self.lib_cargo.is_none());
337         self.lockfile = Some(path::PathBuf::from(lockfile.as_ref()));
338         self
339     }
340 
generate(self) -> Result<Bindings, Error>341     pub fn generate(self) -> Result<Bindings, Error> {
342         let mut result = Parse::new();
343 
344         if self.std_types {
345             result.add_std_types();
346         }
347 
348         for x in &self.srcs {
349             result.extend_with(&parser::parse_src(x, &self.config)?);
350         }
351 
352         if let Some((lib_dir, binding_lib_name)) = self.lib.clone() {
353             let lockfile = self.lockfile.as_ref().and_then(|p| p.to_str());
354 
355             let cargo = Cargo::load(
356                 &lib_dir,
357                 lockfile,
358                 binding_lib_name.as_deref(),
359                 self.config.parse.parse_deps,
360                 self.config.parse.clean,
361                 self.config.only_target_dependencies,
362                 /* existing_metadata = */ None,
363             )?;
364 
365             result.extend_with(&parser::parse_lib(cargo, &self.config)?);
366         } else if let Some(cargo) = self.lib_cargo.clone() {
367             result.extend_with(&parser::parse_lib(cargo, &self.config)?);
368         }
369 
370         Library::new(
371             self.config,
372             result.constants,
373             result.globals,
374             result.enums,
375             result.structs,
376             result.unions,
377             result.opaque_items,
378             result.typedefs,
379             result.functions,
380         )
381         .generate()
382     }
383 }
384 
385 #[cfg(test)]
386 mod tests {
387     use super::*;
388 
389     #[test]
with_style()390     fn with_style() {
391         assert_eq!(
392             Style::Tag,
393             Builder::new().with_style(Style::Tag).config.style
394         );
395     }
396 }
397