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::collections::HashMap;
6 use std::default::Default;
7 use std::fmt;
8 use std::fs::File;
9 use std::io::prelude::*;
10 use std::io::{self, BufReader};
11 use std::path::Path as StdPath;
12 use std::str::FromStr;
13 
14 use serde::de::value::{MapAccessDeserializer, SeqAccessDeserializer};
15 use serde::de::{Deserialize, Deserializer, MapAccess, SeqAccess, Visitor};
16 
17 use toml;
18 
19 use bindgen::ir::annotation::AnnotationSet;
20 use bindgen::ir::path::Path;
21 pub use bindgen::rename::RenameRule;
22 
23 pub const VERSION: &str = env!("CARGO_PKG_VERSION");
24 
25 /// A language type to generate bindings for.
26 #[derive(Debug, Copy, Clone, PartialEq)]
27 pub enum Language {
28     Cxx,
29     C,
30 }
31 
32 impl FromStr for Language {
33     type Err = String;
34 
from_str(s: &str) -> Result<Language, Self::Err>35     fn from_str(s: &str) -> Result<Language, Self::Err> {
36         match s {
37             "cxx" => Ok(Language::Cxx),
38             "Cxx" => Ok(Language::Cxx),
39             "CXX" => Ok(Language::Cxx),
40             "cpp" => Ok(Language::Cxx),
41             "Cpp" => Ok(Language::Cxx),
42             "CPP" => Ok(Language::Cxx),
43             "c++" => Ok(Language::Cxx),
44             "C++" => Ok(Language::Cxx),
45             "c" => Ok(Language::C),
46             "C" => Ok(Language::C),
47             _ => Err(format!("Unrecognized Language: '{}'.", s)),
48         }
49     }
50 }
51 
52 deserialize_enum_str!(Language);
53 
54 /// A style of braces to use for generating code.
55 #[derive(Debug, Clone, PartialEq)]
56 pub enum Braces {
57     SameLine,
58     NextLine,
59 }
60 
61 impl FromStr for Braces {
62     type Err = String;
63 
from_str(s: &str) -> Result<Braces, Self::Err>64     fn from_str(s: &str) -> Result<Braces, Self::Err> {
65         match s {
66             "SameLine" => Ok(Braces::SameLine),
67             "same_line" => Ok(Braces::SameLine),
68             "NextLine" => Ok(Braces::NextLine),
69             "next_line" => Ok(Braces::NextLine),
70             _ => Err(format!("Unrecognized Braces: '{}'.", s)),
71         }
72     }
73 }
74 
75 deserialize_enum_str!(Braces);
76 
77 /// A type of layout to use when generating long lines of code.
78 #[derive(Debug, Clone, PartialEq)]
79 pub enum Layout {
80     Horizontal,
81     Vertical,
82     Auto,
83 }
84 
85 impl FromStr for Layout {
86     type Err = String;
87 
from_str(s: &str) -> Result<Layout, Self::Err>88     fn from_str(s: &str) -> Result<Layout, Self::Err> {
89         match s {
90             "Horizontal" => Ok(Layout::Horizontal),
91             "horizontal" => Ok(Layout::Horizontal),
92             "Vertical" => Ok(Layout::Vertical),
93             "vertical" => Ok(Layout::Vertical),
94             "Auto" => Ok(Layout::Auto),
95             "auto" => Ok(Layout::Auto),
96             _ => Err(format!("Unrecognized Layout: '{}'.", s)),
97         }
98     }
99 }
100 
101 deserialize_enum_str!(Layout);
102 
103 /// How the comments containing documentation should be styled.
104 #[derive(Debug, Clone, PartialEq, Copy)]
105 pub enum DocumentationStyle {
106     C,
107     C99,
108     Doxy,
109     Cxx,
110     Auto,
111 }
112 
113 impl FromStr for DocumentationStyle {
114     type Err = String;
115 
from_str(s: &str) -> Result<DocumentationStyle, Self::Err>116     fn from_str(s: &str) -> Result<DocumentationStyle, Self::Err> {
117         match s.to_lowercase().as_ref() {
118             "c" => Ok(DocumentationStyle::C),
119             "c99" => Ok(DocumentationStyle::C99),
120             "cxx" => Ok(DocumentationStyle::Cxx),
121             "c++" => Ok(DocumentationStyle::Cxx),
122             "doxy" => Ok(DocumentationStyle::Doxy),
123             "auto" => Ok(DocumentationStyle::Auto),
124             _ => Err(format!("Unrecognized documentation style: '{}'.", s)),
125         }
126     }
127 }
128 
129 deserialize_enum_str!(DocumentationStyle);
130 
131 /// A style of Style to use when generating structs and enums.
132 #[derive(Debug, Copy, Clone, PartialEq)]
133 pub enum Style {
134     Both,
135     Tag,
136     Type,
137 }
138 
139 impl Style {
generate_tag(self) -> bool140     pub fn generate_tag(self) -> bool {
141         match self {
142             Style::Both | Style::Tag => true,
143             Style::Type => false,
144         }
145     }
146 
generate_typedef(self) -> bool147     pub fn generate_typedef(self) -> bool {
148         match self {
149             Style::Both | Style::Type => true,
150             Style::Tag => false,
151         }
152     }
153 }
154 
155 impl FromStr for Style {
156     type Err = String;
157 
from_str(s: &str) -> Result<Style, Self::Err>158     fn from_str(s: &str) -> Result<Style, Self::Err> {
159         match s {
160             "Both" => Ok(Style::Both),
161             "both" => Ok(Style::Both),
162             "Tag" => Ok(Style::Tag),
163             "tag" => Ok(Style::Tag),
164             "Type" => Ok(Style::Type),
165             "type" => Ok(Style::Type),
166             _ => Err(format!("Unrecognized Style: '{}'.", s)),
167         }
168     }
169 }
170 
171 deserialize_enum_str!(Style);
172 
173 /// Different item types that we can generate and filter.
174 #[derive(Debug, Clone, PartialEq)]
175 pub enum ItemType {
176     Constants,
177     Globals,
178     Enums,
179     Structs,
180     Unions,
181     Typedefs,
182     OpaqueItems,
183     Functions,
184 }
185 
186 impl FromStr for ItemType {
187     type Err = String;
188 
from_str(s: &str) -> Result<Self, Self::Err>189     fn from_str(s: &str) -> Result<Self, Self::Err> {
190         use self::ItemType::*;
191         Ok(match &*s.to_lowercase() {
192             "constants" => Constants,
193             "globals" => Globals,
194             "enums" => Enums,
195             "structs" => Structs,
196             "unions" => Unions,
197             "typedefs" => Typedefs,
198             "opaque" => OpaqueItems,
199             "functions" => Functions,
200             _ => return Err(format!("Unrecognized Style: '{}'.", s)),
201         })
202     }
203 }
204 
205 deserialize_enum_str!(ItemType);
206 
207 /// Settings to apply when exporting items.
208 #[derive(Debug, Clone, Deserialize, Default)]
209 #[serde(rename_all = "snake_case")]
210 #[serde(deny_unknown_fields)]
211 #[serde(default)]
212 pub struct ExportConfig {
213     /// A list of additional items not used by exported functions to include in
214     /// the generated bindings
215     pub include: Vec<String>,
216     /// A list of items to not include in the generated bindings
217     pub exclude: Vec<String>,
218     /// Table of name conversions to apply to item names
219     pub rename: HashMap<String, String>,
220     /// Table of raw strings to append to the body of items.
221     pub body: HashMap<String, String>,
222     /// A prefix to add before the name of every item
223     pub prefix: Option<String>,
224     /// Types of items to generate.
225     pub item_types: Vec<ItemType>,
226     /// Whether renaming overrides or extends prefixing.
227     pub renaming_overrides_prefixing: bool,
228 }
229 
230 impl ExportConfig {
should_generate(&self, item_type: ItemType) -> bool231     pub(crate) fn should_generate(&self, item_type: ItemType) -> bool {
232         self.item_types.is_empty() || self.item_types.contains(&item_type)
233     }
234 
extra_body(&self, path: &Path) -> Option<&str>235     pub(crate) fn extra_body(&self, path: &Path) -> Option<&str> {
236         self.body.get(path.name()).map(|s| s.trim_matches('\n'))
237     }
238 
rename(&self, item_name: &mut String)239     pub(crate) fn rename(&self, item_name: &mut String) {
240         if let Some(name) = self.rename.get(item_name) {
241             *item_name = name.clone();
242             if self.renaming_overrides_prefixing {
243                 return;
244             }
245         }
246         if let Some(ref prefix) = self.prefix {
247             item_name.insert_str(0, &prefix);
248         }
249     }
250 }
251 
252 /// Settings to apply to generated functions.
253 #[derive(Debug, Clone, Deserialize)]
254 #[serde(rename_all = "snake_case")]
255 #[serde(deny_unknown_fields)]
256 #[serde(default)]
257 pub struct FunctionConfig {
258     /// Optional text to output before each function declaration
259     pub prefix: Option<String>,
260     /// Optional text to output after each function declaration
261     pub postfix: Option<String>,
262     /// The way to annotation this function as #[must_use].
263     pub must_use: Option<String>,
264     /// The style to layout the args
265     pub args: Layout,
266     /// The rename rule to apply to function args
267     pub rename_args: Option<RenameRule>,
268 }
269 
270 impl Default for FunctionConfig {
default() -> FunctionConfig271     fn default() -> FunctionConfig {
272         FunctionConfig {
273             prefix: None,
274             postfix: None,
275             must_use: None,
276             args: Layout::Auto,
277             rename_args: None,
278         }
279     }
280 }
281 
282 impl FunctionConfig {
prefix(&self, annotations: &AnnotationSet) -> Option<String>283     pub(crate) fn prefix(&self, annotations: &AnnotationSet) -> Option<String> {
284         if let Some(x) = annotations.atom("prefix") {
285             return x;
286         }
287         self.prefix.clone()
288     }
289 
postfix(&self, annotations: &AnnotationSet) -> Option<String>290     pub(crate) fn postfix(&self, annotations: &AnnotationSet) -> Option<String> {
291         if let Some(x) = annotations.atom("postfix") {
292             return x;
293         }
294         self.postfix.clone()
295     }
296 }
297 
298 /// Settings to apply to generated structs.
299 #[derive(Debug, Default, Clone, Deserialize)]
300 #[serde(rename_all = "snake_case")]
301 #[serde(deny_unknown_fields)]
302 #[serde(default)]
303 pub struct StructConfig {
304     /// The rename rule to apply to the name of struct fields
305     pub rename_fields: Option<RenameRule>,
306     /// Whether to generate a constructor for the struct (which takes
307     /// arguments to initialize all the members)
308     pub derive_constructor: bool,
309     /// Whether to generate a piecewise equality operator
310     pub derive_eq: bool,
311     /// Whether to generate a piecewise inequality operator
312     pub derive_neq: bool,
313     /// Whether to generate a less than operator on structs with one field
314     pub derive_lt: bool,
315     /// Whether to generate a less than or equal to operator on structs with one field
316     pub derive_lte: bool,
317     /// Whether to generate a greater than operator on structs with one field
318     pub derive_gt: bool,
319     /// Whether to generate a greater than or equal to operator on structs with one field
320     pub derive_gte: bool,
321     /// Whether associated constants should be in the body. Only applicable to
322     /// non-transparent structs, and in C++-only.
323     pub associated_constants_in_body: bool,
324     /// The way to annotation this struct as #[must_use].
325     pub must_use: Option<String>,
326 }
327 
328 impl StructConfig {
derive_constructor(&self, annotations: &AnnotationSet) -> bool329     pub(crate) fn derive_constructor(&self, annotations: &AnnotationSet) -> bool {
330         if let Some(x) = annotations.bool("derive-constructor") {
331             return x;
332         }
333         self.derive_constructor
334     }
derive_eq(&self, annotations: &AnnotationSet) -> bool335     pub(crate) fn derive_eq(&self, annotations: &AnnotationSet) -> bool {
336         if let Some(x) = annotations.bool("derive-eq") {
337             return x;
338         }
339         self.derive_eq
340     }
derive_neq(&self, annotations: &AnnotationSet) -> bool341     pub(crate) fn derive_neq(&self, annotations: &AnnotationSet) -> bool {
342         if let Some(x) = annotations.bool("derive-neq") {
343             return x;
344         }
345         self.derive_neq
346     }
derive_lt(&self, annotations: &AnnotationSet) -> bool347     pub(crate) fn derive_lt(&self, annotations: &AnnotationSet) -> bool {
348         if let Some(x) = annotations.bool("derive-lt") {
349             return x;
350         }
351         self.derive_lt
352     }
derive_lte(&self, annotations: &AnnotationSet) -> bool353     pub(crate) fn derive_lte(&self, annotations: &AnnotationSet) -> bool {
354         if let Some(x) = annotations.bool("derive-lte") {
355             return x;
356         }
357         self.derive_lte
358     }
derive_gt(&self, annotations: &AnnotationSet) -> bool359     pub(crate) fn derive_gt(&self, annotations: &AnnotationSet) -> bool {
360         if let Some(x) = annotations.bool("derive-gt") {
361             return x;
362         }
363         self.derive_gt
364     }
derive_gte(&self, annotations: &AnnotationSet) -> bool365     pub(crate) fn derive_gte(&self, annotations: &AnnotationSet) -> bool {
366         if let Some(x) = annotations.bool("derive-gte") {
367             return x;
368         }
369         self.derive_gte
370     }
371 }
372 
373 /// Settings to apply to generated enums.
374 #[derive(Debug, Clone, Default, Deserialize)]
375 #[serde(rename_all = "snake_case")]
376 #[serde(deny_unknown_fields)]
377 #[serde(default)]
378 pub struct EnumConfig {
379     /// The rename rule to apply to the name of enum variants
380     pub rename_variants: Option<RenameRule>,
381     /// Whether to add a `Sentinel` value at the end of every enum
382     /// This is useful in Gecko for IPC serialization
383     pub add_sentinel: bool,
384     /// Whether the enum variants should be prefixed with the enum name
385     pub prefix_with_name: bool,
386     /// Whether to generate static `::X(..)` constructors and `IsX()`
387     /// methods for tagged enums.
388     pub derive_helper_methods: bool,
389     /// Whether to generate `AsX() const` methods for tagged enums.
390     pub derive_const_casts: bool,
391     /// Whether to generate `AsX()` methods for tagged enums.
392     pub derive_mut_casts: bool,
393     /// The name of the macro to use for `derive_{const,mut}casts`. If custom, you're
394     /// responsible to provide the necessary header, otherwise `assert` will be
395     /// used, and `<cassert>` will be included.
396     pub cast_assert_name: Option<String>,
397     /// The way to annotation this enum as #[must_use].
398     pub must_use: Option<String>,
399     /// Whether to generate destructors of tagged enums.
400     pub derive_tagged_enum_destructor: bool,
401     /// Whether to generate copy-constructors of tagged enums.
402     pub derive_tagged_enum_copy_constructor: bool,
403     /// Whether to generate empty, private default-constructors for tagged
404     /// enums.
405     pub private_default_tagged_enum_constructor: bool,
406 }
407 
408 impl EnumConfig {
add_sentinel(&self, annotations: &AnnotationSet) -> bool409     pub(crate) fn add_sentinel(&self, annotations: &AnnotationSet) -> bool {
410         if let Some(x) = annotations.bool("add-sentinel") {
411             return x;
412         }
413         self.add_sentinel
414     }
derive_helper_methods(&self, annotations: &AnnotationSet) -> bool415     pub(crate) fn derive_helper_methods(&self, annotations: &AnnotationSet) -> bool {
416         if let Some(x) = annotations.bool("derive-helper-methods") {
417             return x;
418         }
419         self.derive_helper_methods
420     }
derive_const_casts(&self, annotations: &AnnotationSet) -> bool421     pub(crate) fn derive_const_casts(&self, annotations: &AnnotationSet) -> bool {
422         if let Some(x) = annotations.bool("derive-const-casts") {
423             return x;
424         }
425         self.derive_const_casts
426     }
derive_mut_casts(&self, annotations: &AnnotationSet) -> bool427     pub(crate) fn derive_mut_casts(&self, annotations: &AnnotationSet) -> bool {
428         if let Some(x) = annotations.bool("derive-mut-casts") {
429             return x;
430         }
431         self.derive_mut_casts
432     }
derive_tagged_enum_destructor(&self, annotations: &AnnotationSet) -> bool433     pub(crate) fn derive_tagged_enum_destructor(&self, annotations: &AnnotationSet) -> bool {
434         if let Some(x) = annotations.bool("derive-tagged-enum-destructor") {
435             return x;
436         }
437         self.derive_tagged_enum_destructor
438     }
derive_tagged_enum_copy_constructor(&self, annotations: &AnnotationSet) -> bool439     pub(crate) fn derive_tagged_enum_copy_constructor(&self, annotations: &AnnotationSet) -> bool {
440         if let Some(x) = annotations.bool("derive-tagged-enum-copy-constructor") {
441             return x;
442         }
443         self.derive_tagged_enum_copy_constructor
444     }
private_default_tagged_enum_constructor( &self, annotations: &AnnotationSet, ) -> bool445     pub(crate) fn private_default_tagged_enum_constructor(
446         &self,
447         annotations: &AnnotationSet,
448     ) -> bool {
449         if let Some(x) = annotations.bool("private-default-tagged-enum-constructor") {
450             return x;
451         }
452         self.private_default_tagged_enum_constructor
453     }
454 }
455 
456 /// Settings to apply to generated constants.
457 #[derive(Debug, Clone, Deserialize)]
458 #[serde(rename_all = "snake_case")]
459 #[serde(deny_unknown_fields)]
460 #[serde(default)]
461 pub struct ConstantConfig {
462     /// Whether a generated constant can be a static const in C++ mode.
463     pub allow_static_const: bool,
464 }
465 
466 impl Default for ConstantConfig {
default() -> ConstantConfig467     fn default() -> ConstantConfig {
468         ConstantConfig {
469             allow_static_const: true,
470         }
471     }
472 }
473 
474 /// Settings for custom macro expansion.
475 #[derive(Debug, Clone, Deserialize, Default)]
476 #[serde(rename_all = "snake_case")]
477 #[serde(deny_unknown_fields)]
478 #[serde(default)]
479 pub struct MacroExpansionConfig {
480     /// Whether the `bitflags` macro should be expanded.
481     pub bitflags: bool,
482 }
483 
484 /// Settings to apply when running `rustc --pretty=expanded`
485 #[derive(Debug, Clone, Deserialize)]
486 #[serde(rename_all = "snake_case")]
487 #[serde(deny_unknown_fields)]
488 #[serde(default)]
489 pub struct ParseExpandConfig {
490     /// The names of crates to parse with `rustc --pretty=expanded`
491     pub crates: Vec<String>,
492     /// Whether to enable all the features when expanding.
493     pub all_features: bool,
494     /// Whether to use the default feature set when expanding.
495     pub default_features: bool,
496     /// List of features to use when expanding. Combines with `default_features` like in
497     /// `Cargo.toml`.
498     pub features: Option<Vec<String>>,
499 }
500 
501 impl Default for ParseExpandConfig {
default() -> ParseExpandConfig502     fn default() -> ParseExpandConfig {
503         ParseExpandConfig {
504             crates: Vec::new(),
505             all_features: false,
506             default_features: true,
507             features: None,
508         }
509     }
510 }
511 
512 // Backwards-compatibility deserializer for ParseExpandConfig. This allows accepting both the
513 // simple `expand = ["crate"]` and the more complex `expand = {"crates": ["crate"],
514 // "default_features": false}` format for the `expand` key.
515 //
516 // Note that one (major) difference between the two forms is that, for backwards-compatibility
517 // reasons, the `expand = ["crate"]` form will enable the `--all-features` flag by default while
518 // the `expand = {"crates": ["crate"]}` form will use the default feature set by default.
retrocomp_parse_expand_config_deserialize<'de, D: Deserializer<'de>>( deserializer: D, ) -> Result<ParseExpandConfig, D::Error>519 fn retrocomp_parse_expand_config_deserialize<'de, D: Deserializer<'de>>(
520     deserializer: D,
521 ) -> Result<ParseExpandConfig, D::Error> {
522     struct ParseExpandVisitor;
523 
524     impl<'de> Visitor<'de> for ParseExpandVisitor {
525         type Value = ParseExpandConfig;
526 
527         fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
528             formatter.write_str("a map or sequence of string")
529         }
530 
531         fn visit_seq<A: SeqAccess<'de>>(self, seq: A) -> Result<Self::Value, A::Error> {
532             let crates =
533                 <Vec<String> as Deserialize>::deserialize(SeqAccessDeserializer::new(seq))?;
534             Ok(ParseExpandConfig {
535                 crates,
536                 all_features: true,
537                 default_features: true,
538                 features: None,
539             })
540         }
541 
542         fn visit_map<A: MapAccess<'de>>(self, map: A) -> Result<Self::Value, A::Error> {
543             <ParseExpandConfig as Deserialize>::deserialize(MapAccessDeserializer::new(map))
544         }
545     }
546 
547     deserializer.deserialize_any(ParseExpandVisitor)
548 }
549 
550 /// Settings to apply when parsing.
551 #[derive(Debug, Default, Clone, Deserialize)]
552 #[serde(rename_all = "snake_case")]
553 #[serde(deny_unknown_fields)]
554 #[serde(default)]
555 pub struct ParseConfig {
556     /// Whether to parse dependencies when generating bindings. When this is true,
557     /// each dependent crate is found using a combination of `cargo metadata` and
558     /// `Cargo.lock`. To further control this behavior, crates can be whitelisted or
559     /// blacklisted using `include` and `exclude` respectively. Additionally in cases
560     /// where crates have types to expose in bindings hidden in macros, a crate can
561     /// be marked in `expand` and `cargo expand` will be used to expand the macros
562     /// before parsing. A crate marked in `expand` doesn't need to be added to any
563     /// whitelist.
564     pub parse_deps: bool,
565     /// An optional whitelist of names of crates to parse
566     pub include: Option<Vec<String>>,
567     /// The names of crates to not parse
568     pub exclude: Vec<String>,
569     /// The configuration options for `rustc --pretty=expanded`
570     #[serde(deserialize_with = "retrocomp_parse_expand_config_deserialize")]
571     pub expand: ParseExpandConfig,
572     /// Whether to use a new temporary target directory when running `rustc --pretty=expanded`.
573     /// This may be required for some build processes.
574     pub clean: bool,
575     /// List of crate names which generate consts, statics, and fns. By default
576     /// no dependent crates generate them.
577     pub extra_bindings: Vec<String>,
578 }
579 
580 impl ParseConfig {
should_generate_top_level_item( &self, crate_name: &str, binding_crate_name: &str, ) -> bool581     pub(crate) fn should_generate_top_level_item(
582         &self,
583         crate_name: &str,
584         binding_crate_name: &str,
585     ) -> bool {
586         if crate_name == binding_crate_name {
587             // Always generate items for the binding crate.
588             return true;
589         }
590 
591         self.extra_bindings.iter().any(|dep| dep == crate_name)
592     }
593 }
594 
595 /// A collection of settings to customize the generated bindings.
596 #[derive(Debug, Clone, Deserialize)]
597 #[serde(rename_all = "snake_case")]
598 #[serde(deny_unknown_fields)]
599 #[serde(default)]
600 pub struct Config {
601     /// Optional text to output at the beginning of the file
602     pub header: Option<String>,
603     /// A list of additional includes to put at the beginning of the generated header
604     pub includes: Vec<String>,
605     /// A list of additional system includes to put at the beginning of the generated header
606     pub sys_includes: Vec<String>,
607     /// Optional text to output at the end of the file
608     pub trailer: Option<String>,
609     /// Optional name to use for an include guard
610     pub include_guard: Option<String>,
611     /// Generates no includes at all. Overrides all other include options
612     ///
613     /// This option is useful when using cbindgen with tools such as python's cffi which
614     /// doesn't understand include directives
615     pub no_includes: bool,
616     /// Optional text to output at major sections to deter manual editing
617     pub autogen_warning: Option<String>,
618     /// Include a comment with the version of cbindgen used to generate the file
619     pub include_version: bool,
620     /// An optional name for the root namespace. Only applicable when language="C++"
621     pub namespace: Option<String>,
622     /// An optional list of namespaces. Only applicable when language="C++"
623     pub namespaces: Option<Vec<String>>,
624     /// The style to use for braces
625     pub braces: Braces,
626     /// The preferred length of a line, used for auto breaking function arguments
627     pub line_length: usize,
628     /// The amount of spaces in a tab
629     pub tab_width: usize,
630     /// The language to output bindings for
631     pub language: Language,
632     /// Include preprocessor defines in C bindings to ensure C++ compatibility
633     pub cpp_compat: bool,
634     /// The style to declare structs, enums and unions in for C
635     pub style: Style,
636     /// The configuration options for parsing
637     pub parse: ParseConfig,
638     /// The configuration options for exporting
639     pub export: ExportConfig,
640     /// The configuration options for macros.
641     pub macro_expansion: MacroExpansionConfig,
642     /// The configuration options for functions
643     #[serde(rename = "fn")]
644     pub function: FunctionConfig,
645     /// The configuration options for structs
646     #[serde(rename = "struct")]
647     pub structure: StructConfig,
648     /// The configuration options for enums
649     #[serde(rename = "enum")]
650     pub enumeration: EnumConfig,
651     /// The configuration options for constants
652     #[serde(rename = "const")]
653     pub constant: ConstantConfig,
654     /// Preprocessor defines to use when generating #ifdef's for #[cfg]
655     pub defines: HashMap<String, String>,
656     /// Include doc comments from rust as documentation
657     pub documentation: bool,
658     /// How documentation comments should be styled.
659     pub documentation_style: DocumentationStyle,
660 }
661 
662 impl Default for Config {
default() -> Config663     fn default() -> Config {
664         Config {
665             header: None,
666             includes: Vec::new(),
667             sys_includes: Vec::new(),
668             trailer: None,
669             include_guard: None,
670             autogen_warning: None,
671             include_version: false,
672             no_includes: false,
673             namespace: None,
674             namespaces: None,
675             braces: Braces::SameLine,
676             line_length: 100,
677             tab_width: 2,
678             language: Language::Cxx,
679             cpp_compat: false,
680             style: Style::Type,
681             macro_expansion: Default::default(),
682             parse: ParseConfig::default(),
683             export: ExportConfig::default(),
684             function: FunctionConfig::default(),
685             structure: StructConfig::default(),
686             enumeration: EnumConfig::default(),
687             constant: ConstantConfig::default(),
688             defines: HashMap::new(),
689             documentation: true,
690             documentation_style: DocumentationStyle::Auto,
691         }
692     }
693 }
694 
695 impl Config {
from_file<P: AsRef<StdPath>>(file_name: P) -> Result<Config, String>696     pub fn from_file<P: AsRef<StdPath>>(file_name: P) -> Result<Config, String> {
697         fn read(file_name: &StdPath) -> io::Result<String> {
698             let file = File::open(file_name)?;
699             let mut reader = BufReader::new(&file);
700             let mut contents = String::new();
701             reader.read_to_string(&mut contents)?;
702             Ok(contents)
703         }
704 
705         let config_text = read(file_name.as_ref()).unwrap();
706 
707         match toml::from_str::<Config>(&config_text) {
708             Ok(x) => Ok(x),
709             Err(e) => Err(format!("Couldn't parse config file: {}.", e)),
710         }
711     }
712 
from_root_or_default<P: AsRef<StdPath>>(root: P) -> Config713     pub fn from_root_or_default<P: AsRef<StdPath>>(root: P) -> Config {
714         let c = root.as_ref().join("cbindgen.toml");
715 
716         if c.exists() {
717             Config::from_file(c).unwrap()
718         } else {
719             Config::default()
720         }
721     }
722 }
723