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::{BTreeMap, HashMap};
6 use std::default::Default;
7 use std::str::FromStr;
8 use std::{fmt, fs, path::Path as StdPath};
9 
10 use serde::de::value::{MapAccessDeserializer, SeqAccessDeserializer};
11 use serde::de::{Deserialize, Deserializer, MapAccess, SeqAccess, Visitor};
12 
13 use crate::bindgen::ir::annotation::AnnotationSet;
14 use crate::bindgen::ir::path::Path;
15 use crate::bindgen::ir::repr::ReprAlign;
16 pub use crate::bindgen::rename::RenameRule;
17 
18 pub const VERSION: &str = env!("CARGO_PKG_VERSION");
19 
20 /// A language type to generate bindings for.
21 #[derive(Debug, Copy, Clone, PartialEq)]
22 pub enum Language {
23     Cxx,
24     C,
25     Cython,
26 }
27 
28 impl FromStr for Language {
29     type Err = String;
30 
from_str(s: &str) -> Result<Language, Self::Err>31     fn from_str(s: &str) -> Result<Language, Self::Err> {
32         match s {
33             "cxx" => Ok(Language::Cxx),
34             "Cxx" => Ok(Language::Cxx),
35             "CXX" => Ok(Language::Cxx),
36             "cpp" => Ok(Language::Cxx),
37             "Cpp" => Ok(Language::Cxx),
38             "CPP" => Ok(Language::Cxx),
39             "c++" => Ok(Language::Cxx),
40             "C++" => Ok(Language::Cxx),
41             "c" => Ok(Language::C),
42             "C" => Ok(Language::C),
43             "cython" => Ok(Language::Cython),
44             "Cython" => Ok(Language::Cython),
45             _ => Err(format!("Unrecognized Language: '{}'.", s)),
46         }
47     }
48 }
49 
50 deserialize_enum_str!(Language);
51 
52 impl Language {
typedef(self) -> &'static str53     pub(crate) fn typedef(self) -> &'static str {
54         match self {
55             Language::Cxx | Language::C => "typedef",
56             Language::Cython => "ctypedef",
57         }
58     }
59 }
60 
61 /// Controls what type of line endings are used in the generated code.
62 #[derive(Debug, Clone, Copy)]
63 #[allow(clippy::upper_case_acronyms)]
64 pub enum LineEndingStyle {
65     /// Use Unix-style linefeed characters
66     LF,
67     /// Use classic Mac-style carriage-return characters
68     CR,
69     /// Use Windows-style carriage-return and linefeed characters
70     CRLF,
71     /// Use the native mode for the platform: CRLF on Windows, LF everywhere else.
72     Native,
73 }
74 
75 impl Default for LineEndingStyle {
default() -> Self76     fn default() -> Self {
77         LineEndingStyle::LF
78     }
79 }
80 
81 impl LineEndingStyle {
as_str(&self) -> &'static str82     pub fn as_str(&self) -> &'static str {
83         match self {
84             Self::LF => "\n",
85             Self::CR => "\r",
86             Self::CRLF => "\r\n",
87             Self::Native => {
88                 #[cfg(target_os = "windows")]
89                 {
90                     Self::CRLF.as_str()
91                 }
92                 #[cfg(not(target_os = "windows"))]
93                 {
94                     Self::LF.as_str()
95                 }
96             }
97         }
98     }
99 }
100 
101 impl FromStr for LineEndingStyle {
102     type Err = String;
103 
from_str(s: &str) -> Result<Self, Self::Err>104     fn from_str(s: &str) -> Result<Self, Self::Err> {
105         match s.to_lowercase().as_ref() {
106             "native" => Ok(Self::Native),
107             "lf" => Ok(Self::LF),
108             "crlf" => Ok(Self::CRLF),
109             "cr" => Ok(Self::CR),
110             _ => Err(format!("Unrecognized line ending style: '{}'.", s)),
111         }
112     }
113 }
114 
115 deserialize_enum_str!(LineEndingStyle);
116 
117 /// A style of braces to use for generating code.
118 #[derive(Debug, Clone, PartialEq)]
119 pub enum Braces {
120     SameLine,
121     NextLine,
122 }
123 
124 impl FromStr for Braces {
125     type Err = String;
126 
from_str(s: &str) -> Result<Braces, Self::Err>127     fn from_str(s: &str) -> Result<Braces, Self::Err> {
128         match s {
129             "SameLine" => Ok(Braces::SameLine),
130             "same_line" => Ok(Braces::SameLine),
131             "NextLine" => Ok(Braces::NextLine),
132             "next_line" => Ok(Braces::NextLine),
133             _ => Err(format!("Unrecognized Braces: '{}'.", s)),
134         }
135     }
136 }
137 
138 deserialize_enum_str!(Braces);
139 
140 /// A type of layout to use when generating long lines of code.
141 #[derive(Debug, Clone, PartialEq)]
142 pub enum Layout {
143     Horizontal,
144     Vertical,
145     Auto,
146 }
147 
148 impl FromStr for Layout {
149     type Err = String;
150 
from_str(s: &str) -> Result<Layout, Self::Err>151     fn from_str(s: &str) -> Result<Layout, Self::Err> {
152         match s {
153             "Horizontal" => Ok(Layout::Horizontal),
154             "horizontal" => Ok(Layout::Horizontal),
155             "Vertical" => Ok(Layout::Vertical),
156             "vertical" => Ok(Layout::Vertical),
157             "Auto" => Ok(Layout::Auto),
158             "auto" => Ok(Layout::Auto),
159             _ => Err(format!("Unrecognized Layout: '{}'.", s)),
160         }
161     }
162 }
163 
164 deserialize_enum_str!(Layout);
165 
166 /// How the comments containing documentation should be styled.
167 #[derive(Debug, Clone, PartialEq, Copy)]
168 pub enum DocumentationStyle {
169     C,
170     C99,
171     Doxy,
172     Cxx,
173     Auto,
174 }
175 
176 impl FromStr for DocumentationStyle {
177     type Err = String;
178 
from_str(s: &str) -> Result<DocumentationStyle, Self::Err>179     fn from_str(s: &str) -> Result<DocumentationStyle, Self::Err> {
180         match s.to_lowercase().as_ref() {
181             "c" => Ok(DocumentationStyle::C),
182             "c99" => Ok(DocumentationStyle::C99),
183             "cxx" => Ok(DocumentationStyle::Cxx),
184             "c++" => Ok(DocumentationStyle::Cxx),
185             "doxy" => Ok(DocumentationStyle::Doxy),
186             "auto" => Ok(DocumentationStyle::Auto),
187             _ => Err(format!("Unrecognized documentation style: '{}'.", s)),
188         }
189     }
190 }
191 
192 deserialize_enum_str!(DocumentationStyle);
193 
194 /// A style of Style to use when generating structs and enums.
195 #[derive(Debug, Copy, Clone, PartialEq)]
196 pub enum Style {
197     Both,
198     Tag,
199     Type,
200 }
201 
202 impl Style {
generate_tag(self) -> bool203     pub fn generate_tag(self) -> bool {
204         match self {
205             Style::Both | Style::Tag => true,
206             Style::Type => false,
207         }
208     }
209 
generate_typedef(self) -> bool210     pub fn generate_typedef(self) -> bool {
211         match self {
212             Style::Both | Style::Type => true,
213             Style::Tag => false,
214         }
215     }
216 
217     // https://cython.readthedocs.io/en/latest/src/userguide/external_C_code.html#styles-of-struct-union-and-enum-declaration
cython_def(self) -> &'static str218     pub fn cython_def(self) -> &'static str {
219         if self.generate_tag() {
220             "cdef "
221         } else {
222             "ctypedef "
223         }
224     }
225 }
226 
227 impl Default for Style {
default() -> Self228     fn default() -> Self {
229         Style::Both
230     }
231 }
232 
233 impl FromStr for Style {
234     type Err = String;
235 
from_str(s: &str) -> Result<Style, Self::Err>236     fn from_str(s: &str) -> Result<Style, Self::Err> {
237         match s {
238             "Both" => Ok(Style::Both),
239             "both" => Ok(Style::Both),
240             "Tag" => Ok(Style::Tag),
241             "tag" => Ok(Style::Tag),
242             "Type" => Ok(Style::Type),
243             "type" => Ok(Style::Type),
244             _ => Err(format!("Unrecognized Style: '{}'.", s)),
245         }
246     }
247 }
248 
249 deserialize_enum_str!(Style);
250 
251 /// Different item types that we can generate and filter.
252 #[derive(Debug, Clone, PartialEq)]
253 pub enum ItemType {
254     Constants,
255     Globals,
256     Enums,
257     Structs,
258     Unions,
259     Typedefs,
260     OpaqueItems,
261     Functions,
262 }
263 
264 impl FromStr for ItemType {
265     type Err = String;
266 
from_str(s: &str) -> Result<Self, Self::Err>267     fn from_str(s: &str) -> Result<Self, Self::Err> {
268         use self::ItemType::*;
269         Ok(match &*s.to_lowercase() {
270             "constants" => Constants,
271             "globals" => Globals,
272             "enums" => Enums,
273             "structs" => Structs,
274             "unions" => Unions,
275             "typedefs" => Typedefs,
276             "opaque" => OpaqueItems,
277             "functions" => Functions,
278             _ => return Err(format!("Unrecognized Style: '{}'.", s)),
279         })
280     }
281 }
282 
283 deserialize_enum_str!(ItemType);
284 
285 /// Type which specifies the sort order of functions
286 #[derive(Debug, Clone, Copy, PartialEq)]
287 pub enum SortKey {
288     Name,
289     None,
290 }
291 
292 impl FromStr for SortKey {
293     type Err = String;
294 
from_str(s: &str) -> Result<Self, Self::Err>295     fn from_str(s: &str) -> Result<Self, Self::Err> {
296         use self::SortKey::*;
297         Ok(match &*s.to_lowercase() {
298             "name" => Name,
299             "none" => None,
300             _ => return Err(format!("Unrecognized sort option: '{}'.", s)),
301         })
302     }
303 }
304 
305 deserialize_enum_str!(SortKey);
306 
307 /// Settings to apply when exporting items.
308 #[derive(Debug, Clone, Deserialize, Default)]
309 #[serde(rename_all = "snake_case")]
310 #[serde(deny_unknown_fields)]
311 #[serde(default)]
312 pub struct ExportConfig {
313     /// A list of additional items not used by exported functions to include in
314     /// the generated bindings
315     pub include: Vec<String>,
316     /// A list of items to not include in the generated bindings
317     pub exclude: Vec<String>,
318     /// Table of name conversions to apply to item names
319     pub rename: HashMap<String, String>,
320     /// Table of raw strings to prepend to the body of items.
321     pub pre_body: HashMap<String, String>,
322     /// Table of raw strings to append to the body of items.
323     pub body: HashMap<String, String>,
324     /// A prefix to add before the name of every item
325     pub prefix: Option<String>,
326     /// Types of items to generate.
327     pub item_types: Vec<ItemType>,
328     /// Whether renaming overrides or extends prefixing.
329     pub renaming_overrides_prefixing: bool,
330     /// Mangling configuration.
331     pub mangle: MangleConfig,
332 }
333 
334 /// Mangling-specific configuration.
335 #[derive(Debug, Clone, Deserialize, Default)]
336 #[serde(rename_all = "snake_case")]
337 #[serde(deny_unknown_fields)]
338 #[serde(default)]
339 pub struct MangleConfig {
340     /// The rename rule to apply to the type names mangled.
341     pub rename_types: RenameRule,
342     /// Remove the underscores used for name mangling.
343     pub remove_underscores: bool,
344 }
345 
346 impl ExportConfig {
should_generate(&self, item_type: ItemType) -> bool347     pub(crate) fn should_generate(&self, item_type: ItemType) -> bool {
348         self.item_types.is_empty() || self.item_types.contains(&item_type)
349     }
350 
pre_body(&self, path: &Path) -> Option<&str>351     pub(crate) fn pre_body(&self, path: &Path) -> Option<&str> {
352         self.pre_body.get(path.name()).map(|s| s.trim_matches('\n'))
353     }
354 
post_body(&self, path: &Path) -> Option<&str>355     pub(crate) fn post_body(&self, path: &Path) -> Option<&str> {
356         self.body.get(path.name()).map(|s| s.trim_matches('\n'))
357     }
358 
rename(&self, item_name: &mut String)359     pub(crate) fn rename(&self, item_name: &mut String) {
360         if let Some(name) = self.rename.get(item_name) {
361             *item_name = name.clone();
362             if self.renaming_overrides_prefixing {
363                 return;
364             }
365         }
366         if let Some(ref prefix) = self.prefix {
367             item_name.insert_str(0, prefix);
368         }
369     }
370 }
371 
372 /// Settings to apply to generated types with layout modifiers.
373 #[derive(Debug, Default, Clone, Deserialize)]
374 #[serde(rename_all = "snake_case")]
375 #[serde(deny_unknown_fields)]
376 #[serde(default)]
377 pub struct LayoutConfig {
378     /// The way to annotate C types as #[repr(packed)].
379     pub packed: Option<String>,
380     /// The way to annotate C types as #[repr(align(...))]. This is assumed to be a functional
381     /// macro which takes a single argument (the alignment).
382     pub aligned_n: Option<String>,
383 }
384 
385 impl LayoutConfig {
ensure_safe_to_represent(&self, align: &ReprAlign) -> Result<(), String>386     pub(crate) fn ensure_safe_to_represent(&self, align: &ReprAlign) -> Result<(), String> {
387         match (align, &self.packed, &self.aligned_n) {
388             (ReprAlign::Packed, None, _) => Err("Cannot safely represent #[repr(packed)] type without configured 'packed' annotation.".to_string()),
389             (ReprAlign::Align(_), _, None) => Err("Cannot safely represent #[repr(aligned(...))] type without configured 'aligned_n' annotation.".to_string()),
390             _ => Ok(()),
391         }
392     }
393 }
394 
395 /// Settings to apply to generated functions.
396 #[derive(Debug, Clone, Deserialize)]
397 #[serde(rename_all = "snake_case")]
398 #[serde(deny_unknown_fields)]
399 #[serde(default)]
400 pub struct FunctionConfig {
401     /// Optional text to output before each function declaration
402     pub prefix: Option<String>,
403     /// Optional text to output after each function declaration
404     pub postfix: Option<String>,
405     /// The way to annotation this function as #[must_use]
406     pub must_use: Option<String>,
407     /// The style to layout the args
408     pub args: Layout,
409     /// The rename rule to apply to function args
410     pub rename_args: RenameRule,
411     /// An optional macro to use when generating Swift function name attributes
412     pub swift_name_macro: Option<String>,
413     /// Sort key for functions
414     pub sort_by: Option<SortKey>,
415     /// Optional text to output after functions which return `!`.
416     pub no_return: Option<String>,
417 }
418 
419 impl Default for FunctionConfig {
default() -> FunctionConfig420     fn default() -> FunctionConfig {
421         FunctionConfig {
422             prefix: None,
423             postfix: None,
424             must_use: None,
425             args: Layout::Auto,
426             rename_args: RenameRule::None,
427             swift_name_macro: None,
428             sort_by: None,
429             no_return: None,
430         }
431     }
432 }
433 
434 impl FunctionConfig {
prefix(&self, annotations: &AnnotationSet) -> Option<String>435     pub(crate) fn prefix(&self, annotations: &AnnotationSet) -> Option<String> {
436         if let Some(x) = annotations.atom("prefix") {
437             return x;
438         }
439         self.prefix.clone()
440     }
441 
postfix(&self, annotations: &AnnotationSet) -> Option<String>442     pub(crate) fn postfix(&self, annotations: &AnnotationSet) -> Option<String> {
443         if let Some(x) = annotations.atom("postfix") {
444             return x;
445         }
446         self.postfix.clone()
447     }
448 }
449 
450 /// Settings to apply to generated structs.
451 #[derive(Debug, Default, Clone, Deserialize)]
452 #[serde(rename_all = "snake_case")]
453 #[serde(deny_unknown_fields)]
454 #[serde(default)]
455 pub struct StructConfig {
456     /// The rename rule to apply to the name of struct fields
457     pub rename_fields: RenameRule,
458     /// Whether to generate a constructor for the struct (which takes
459     /// arguments to initialize all the members)
460     pub derive_constructor: bool,
461     /// Whether to generate a piecewise equality operator
462     pub derive_eq: bool,
463     /// Whether to generate a piecewise inequality operator
464     pub derive_neq: bool,
465     /// Whether to generate a less than operator on structs with one field
466     pub derive_lt: bool,
467     /// Whether to generate a less than or equal to operator on structs with one field
468     pub derive_lte: bool,
469     /// Whether to generate a greater than operator on structs with one field
470     pub derive_gt: bool,
471     /// Whether to generate a greater than or equal to operator on structs with one field
472     pub derive_gte: bool,
473     /// Whether to generate a ostream serializer for the struct
474     pub derive_ostream: bool,
475     /// Whether associated constants should be in the body. Only applicable to
476     /// non-transparent structs, and in C++-only.
477     pub associated_constants_in_body: bool,
478     /// The way to annotate this struct as #[must_use].
479     pub must_use: Option<String>,
480 }
481 
482 impl StructConfig {
derive_constructor(&self, annotations: &AnnotationSet) -> bool483     pub(crate) fn derive_constructor(&self, annotations: &AnnotationSet) -> bool {
484         if let Some(x) = annotations.bool("derive-constructor") {
485             return x;
486         }
487         self.derive_constructor
488     }
derive_eq(&self, annotations: &AnnotationSet) -> bool489     pub(crate) fn derive_eq(&self, annotations: &AnnotationSet) -> bool {
490         if let Some(x) = annotations.bool("derive-eq") {
491             return x;
492         }
493         self.derive_eq
494     }
derive_neq(&self, annotations: &AnnotationSet) -> bool495     pub(crate) fn derive_neq(&self, annotations: &AnnotationSet) -> bool {
496         if let Some(x) = annotations.bool("derive-neq") {
497             return x;
498         }
499         self.derive_neq
500     }
derive_lt(&self, annotations: &AnnotationSet) -> bool501     pub(crate) fn derive_lt(&self, annotations: &AnnotationSet) -> bool {
502         if let Some(x) = annotations.bool("derive-lt") {
503             return x;
504         }
505         self.derive_lt
506     }
derive_lte(&self, annotations: &AnnotationSet) -> bool507     pub(crate) fn derive_lte(&self, annotations: &AnnotationSet) -> bool {
508         if let Some(x) = annotations.bool("derive-lte") {
509             return x;
510         }
511         self.derive_lte
512     }
derive_gt(&self, annotations: &AnnotationSet) -> bool513     pub(crate) fn derive_gt(&self, annotations: &AnnotationSet) -> bool {
514         if let Some(x) = annotations.bool("derive-gt") {
515             return x;
516         }
517         self.derive_gt
518     }
derive_gte(&self, annotations: &AnnotationSet) -> bool519     pub(crate) fn derive_gte(&self, annotations: &AnnotationSet) -> bool {
520         if let Some(x) = annotations.bool("derive-gte") {
521             return x;
522         }
523         self.derive_gte
524     }
derive_ostream(&self, annotations: &AnnotationSet) -> bool525     pub(crate) fn derive_ostream(&self, annotations: &AnnotationSet) -> bool {
526         if let Some(x) = annotations.bool("derive-ostream") {
527             return x;
528         }
529         self.derive_ostream
530     }
531 }
532 
533 /// Settings to apply to generated enums.
534 #[derive(Debug, Clone, Deserialize)]
535 #[serde(rename_all = "snake_case")]
536 #[serde(deny_unknown_fields)]
537 #[serde(default)]
538 pub struct EnumConfig {
539     /// The rename rule to apply to the name of enum variants
540     pub rename_variants: RenameRule,
541     /// Whether to add a `Sentinel` value at the end of every enum
542     /// This is useful in Gecko for IPC serialization
543     pub add_sentinel: bool,
544     /// Whether the enum variants should be prefixed with the enum name
545     pub prefix_with_name: bool,
546     /// Whether to generate static `::X(..)` constructors and `IsX()`
547     /// methods for tagged enums.
548     pub derive_helper_methods: bool,
549     /// Whether to generate `AsX() const` methods for tagged enums.
550     pub derive_const_casts: bool,
551     /// Whether to generate `AsX()` methods for tagged enums.
552     pub derive_mut_casts: bool,
553     /// The name of the macro to use for `derive_{const,mut}casts`. If custom, you're
554     /// responsible to provide the necessary header, otherwise `assert` will be
555     /// used, and `<cassert>` will be included.
556     pub cast_assert_name: Option<String>,
557     /// The way to annotation this enum as #[must_use].
558     pub must_use: Option<String>,
559     /// Whether to generate destructors of tagged enums.
560     pub derive_tagged_enum_destructor: bool,
561     /// Whether to generate copy-constructors of tagged enums.
562     pub derive_tagged_enum_copy_constructor: bool,
563     /// Whether to generate copy-assignment operators of tagged enums.
564     ///
565     /// This is only generated if a copy constructor for the same tagged enum is
566     /// generated as well.
567     pub derive_tagged_enum_copy_assignment: bool,
568     /// Whether to generate a ostream serializer for the struct
569     pub derive_ostream: bool,
570     /// Declare the enum as an enum class.
571     /// Only relevant when targeting C++.
572     pub enum_class: bool,
573     /// Whether to generate empty, private default-constructors for tagged
574     /// enums.
575     pub private_default_tagged_enum_constructor: bool,
576 }
577 
578 impl Default for EnumConfig {
default() -> EnumConfig579     fn default() -> EnumConfig {
580         EnumConfig {
581             rename_variants: RenameRule::None,
582             add_sentinel: false,
583             prefix_with_name: false,
584             derive_helper_methods: false,
585             derive_const_casts: false,
586             derive_mut_casts: false,
587             cast_assert_name: None,
588             must_use: None,
589             derive_tagged_enum_destructor: false,
590             derive_tagged_enum_copy_constructor: false,
591             derive_tagged_enum_copy_assignment: false,
592             derive_ostream: false,
593             enum_class: true,
594             private_default_tagged_enum_constructor: false,
595         }
596     }
597 }
598 
599 impl EnumConfig {
add_sentinel(&self, annotations: &AnnotationSet) -> bool600     pub(crate) fn add_sentinel(&self, annotations: &AnnotationSet) -> bool {
601         if let Some(x) = annotations.bool("add-sentinel") {
602             return x;
603         }
604         self.add_sentinel
605     }
derive_helper_methods(&self, annotations: &AnnotationSet) -> bool606     pub(crate) fn derive_helper_methods(&self, annotations: &AnnotationSet) -> bool {
607         if let Some(x) = annotations.bool("derive-helper-methods") {
608             return x;
609         }
610         self.derive_helper_methods
611     }
derive_const_casts(&self, annotations: &AnnotationSet) -> bool612     pub(crate) fn derive_const_casts(&self, annotations: &AnnotationSet) -> bool {
613         if let Some(x) = annotations.bool("derive-const-casts") {
614             return x;
615         }
616         self.derive_const_casts
617     }
derive_mut_casts(&self, annotations: &AnnotationSet) -> bool618     pub(crate) fn derive_mut_casts(&self, annotations: &AnnotationSet) -> bool {
619         if let Some(x) = annotations.bool("derive-mut-casts") {
620             return x;
621         }
622         self.derive_mut_casts
623     }
derive_tagged_enum_destructor(&self, annotations: &AnnotationSet) -> bool624     pub(crate) fn derive_tagged_enum_destructor(&self, annotations: &AnnotationSet) -> bool {
625         if let Some(x) = annotations.bool("derive-tagged-enum-destructor") {
626             return x;
627         }
628         self.derive_tagged_enum_destructor
629     }
derive_tagged_enum_copy_constructor(&self, annotations: &AnnotationSet) -> bool630     pub(crate) fn derive_tagged_enum_copy_constructor(&self, annotations: &AnnotationSet) -> bool {
631         if let Some(x) = annotations.bool("derive-tagged-enum-copy-constructor") {
632             return x;
633         }
634         self.derive_tagged_enum_copy_constructor
635     }
derive_tagged_enum_copy_assignment(&self, annotations: &AnnotationSet) -> bool636     pub(crate) fn derive_tagged_enum_copy_assignment(&self, annotations: &AnnotationSet) -> bool {
637         if let Some(x) = annotations.bool("derive-tagged-enum-copy-assignment") {
638             return x;
639         }
640         self.derive_tagged_enum_copy_assignment
641     }
derive_ostream(&self, annotations: &AnnotationSet) -> bool642     pub(crate) fn derive_ostream(&self, annotations: &AnnotationSet) -> bool {
643         if let Some(x) = annotations.bool("derive-ostream") {
644             return x;
645         }
646         self.derive_ostream
647     }
enum_class(&self, annotations: &AnnotationSet) -> bool648     pub(crate) fn enum_class(&self, annotations: &AnnotationSet) -> bool {
649         if let Some(x) = annotations.bool("enum-class") {
650             return x;
651         }
652         self.enum_class
653     }
private_default_tagged_enum_constructor( &self, annotations: &AnnotationSet, ) -> bool654     pub(crate) fn private_default_tagged_enum_constructor(
655         &self,
656         annotations: &AnnotationSet,
657     ) -> bool {
658         if let Some(x) = annotations.bool("private-default-tagged-enum-constructor") {
659             return x;
660         }
661         self.private_default_tagged_enum_constructor
662     }
663 }
664 
665 /// Settings to apply to generated constants.
666 #[derive(Debug, Clone, Deserialize)]
667 #[serde(rename_all = "snake_case")]
668 #[serde(deny_unknown_fields)]
669 #[serde(default)]
670 pub struct ConstantConfig {
671     /// Whether a generated constant can be a static const in C++ mode.
672     pub allow_static_const: bool,
673     /// Whether a generated constant should be constexpr in C++ mode.
674     pub allow_constexpr: bool,
675     /// Sort key for constants
676     pub sort_by: Option<SortKey>,
677 }
678 
679 impl Default for ConstantConfig {
default() -> ConstantConfig680     fn default() -> ConstantConfig {
681         ConstantConfig {
682             allow_static_const: true,
683             allow_constexpr: false,
684             sort_by: None,
685         }
686     }
687 }
688 
689 /// Settings for custom macro expansion.
690 #[derive(Debug, Clone, Deserialize, Default)]
691 #[serde(rename_all = "snake_case")]
692 #[serde(deny_unknown_fields)]
693 #[serde(default)]
694 pub struct MacroExpansionConfig {
695     /// Whether the `bitflags` macro should be expanded.
696     pub bitflags: bool,
697 }
698 
699 /// Controls which Cargo profile is used for macro expansion.
700 #[derive(Debug, Copy, Clone, PartialEq)]
701 pub enum Profile {
702     Debug,
703     Release,
704 }
705 
706 impl FromStr for Profile {
707     type Err = String;
708 
from_str(s: &str) -> Result<Profile, Self::Err>709     fn from_str(s: &str) -> Result<Profile, Self::Err> {
710         match s {
711             "debug" | "Debug" => Ok(Profile::Debug),
712             "release" | "Release" => Ok(Profile::Release),
713             _ => Err(format!("Unrecognized Profile: '{}'.", s)),
714         }
715     }
716 }
717 
718 deserialize_enum_str!(Profile);
719 
720 /// Settings to apply when running `rustc -Zunpretty=expanded`
721 #[derive(Debug, Clone, Deserialize)]
722 #[serde(rename_all = "snake_case")]
723 #[serde(deny_unknown_fields)]
724 #[serde(default)]
725 pub struct ParseExpandConfig {
726     /// The names of crates to parse with `rustc -Zunpretty=expanded`
727     pub crates: Vec<String>,
728     /// Whether to enable all the features when expanding.
729     pub all_features: bool,
730     /// Whether to use the default feature set when expanding.
731     pub default_features: bool,
732     /// List of features to use when expanding. Combines with `default_features` like in
733     /// `Cargo.toml`.
734     pub features: Option<Vec<String>>,
735     /// Controls whether or not to pass `--release` when expanding.
736     pub profile: Profile,
737 }
738 
739 impl Default for ParseExpandConfig {
default() -> ParseExpandConfig740     fn default() -> ParseExpandConfig {
741         ParseExpandConfig {
742             crates: Vec::new(),
743             all_features: false,
744             default_features: true,
745             features: None,
746             profile: Profile::Debug,
747         }
748     }
749 }
750 
751 // Backwards-compatibility deserializer for ParseExpandConfig. This allows accepting both the
752 // simple `expand = ["crate"]` and the more complex `expand = {"crates": ["crate"],
753 // "default_features": false}` format for the `expand` key.
754 //
755 // Note that one (major) difference between the two forms is that, for backwards-compatibility
756 // reasons, the `expand = ["crate"]` form will enable the `--all-features` flag by default while
757 // 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>758 fn retrocomp_parse_expand_config_deserialize<'de, D: Deserializer<'de>>(
759     deserializer: D,
760 ) -> Result<ParseExpandConfig, D::Error> {
761     struct ParseExpandVisitor;
762 
763     impl<'de> Visitor<'de> for ParseExpandVisitor {
764         type Value = ParseExpandConfig;
765 
766         fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
767             formatter.write_str("a map or sequence of string")
768         }
769 
770         fn visit_seq<A: SeqAccess<'de>>(self, seq: A) -> Result<Self::Value, A::Error> {
771             let crates =
772                 <Vec<String> as Deserialize>::deserialize(SeqAccessDeserializer::new(seq))?;
773             Ok(ParseExpandConfig {
774                 crates,
775                 all_features: true,
776                 default_features: true,
777                 features: None,
778                 profile: Profile::Debug,
779             })
780         }
781 
782         fn visit_map<A: MapAccess<'de>>(self, map: A) -> Result<Self::Value, A::Error> {
783             <ParseExpandConfig as Deserialize>::deserialize(MapAccessDeserializer::new(map))
784         }
785     }
786 
787     deserializer.deserialize_any(ParseExpandVisitor)
788 }
789 
790 /// Settings to apply when parsing.
791 #[derive(Debug, Default, Clone, Deserialize)]
792 #[serde(rename_all = "snake_case")]
793 #[serde(deny_unknown_fields)]
794 #[serde(default)]
795 pub struct ParseConfig {
796     /// Whether to parse dependencies when generating bindings. When this is true,
797     /// each dependent crate is found using a combination of `cargo metadata` and
798     /// `Cargo.lock`. To further control this behavior, crates can be whitelisted or
799     /// blacklisted using `include` and `exclude` respectively. Additionally in cases
800     /// where crates have types to expose in bindings hidden in macros, a crate can
801     /// be marked in `expand` and `cargo expand` will be used to expand the macros
802     /// before parsing. A crate marked in `expand` doesn't need to be added to any
803     /// whitelist.
804     pub parse_deps: bool,
805     /// An optional whitelist of names of crates to parse
806     pub include: Option<Vec<String>>,
807     /// The names of crates to not parse
808     pub exclude: Vec<String>,
809     /// The configuration options for `rustc -Zunpretty=expanded`
810     #[serde(deserialize_with = "retrocomp_parse_expand_config_deserialize")]
811     pub expand: ParseExpandConfig,
812     /// Whether to use a new temporary target directory when running `rustc -Zunpretty=expanded`.
813     /// This may be required for some build processes.
814     pub clean: bool,
815     /// List of crate names which generate consts, statics, and fns. By default
816     /// no dependent crates generate them.
817     pub extra_bindings: Vec<String>,
818 }
819 
820 impl ParseConfig {
should_generate_top_level_item( &self, crate_name: &str, binding_crate_name: &str, ) -> bool821     pub(crate) fn should_generate_top_level_item(
822         &self,
823         crate_name: &str,
824         binding_crate_name: &str,
825     ) -> bool {
826         if crate_name == binding_crate_name {
827             // Always generate items for the binding crate.
828             return true;
829         }
830 
831         self.extra_bindings.iter().any(|dep| dep == crate_name)
832     }
833 }
834 
835 /// Settings to apply to pointers
836 #[derive(Debug, Clone, Default, Deserialize)]
837 #[serde(rename_all = "snake_case")]
838 #[serde(deny_unknown_fields)]
839 #[serde(default)]
840 pub struct PtrConfig {
841     /// Optional attribute to apply to pointers that are required to not be null
842     pub non_null_attribute: Option<String>,
843 }
844 
845 /// Settings specific to Cython bindings.
846 #[derive(Debug, Clone, Default, Deserialize)]
847 #[serde(rename_all = "snake_case")]
848 #[serde(deny_unknown_fields)]
849 #[serde(default)]
850 pub struct CythonConfig {
851     /// Header specified in the top level `cdef extern from header:` declaration.
852     pub header: Option<String>,
853     /// `from module cimport name1, name2, ...` declarations added in the same place
854     /// where you'd get includes in C.
855     pub cimports: BTreeMap<String, Vec<String>>,
856 }
857 
858 /// A collection of settings to customize the generated bindings.
859 #[derive(Debug, Clone, Deserialize)]
860 #[serde(rename_all = "snake_case")]
861 #[serde(deny_unknown_fields)]
862 #[serde(default)]
863 pub struct Config {
864     /// Optional text to output at the beginning of the file
865     pub header: Option<String>,
866     /// A list of additional includes to put at the beginning of the generated header
867     pub includes: Vec<String>,
868     /// A list of additional system includes to put at the beginning of the generated header
869     pub sys_includes: Vec<String>,
870     /// Optional verbatim code added after the include blocks
871     pub after_includes: Option<String>,
872     /// Optional text to output at the end of the file
873     pub trailer: Option<String>,
874     /// Optional name to use for an include guard
875     pub include_guard: Option<String>,
876     /// Add a `#pragma once` guard
877     pub pragma_once: bool,
878     /// Generates no includes at all. Overrides all other include options
879     ///
880     /// This option is useful when using cbindgen with tools such as python's cffi which
881     /// doesn't understand include directives
882     pub no_includes: bool,
883     /// Optional text to output at major sections to deter manual editing
884     pub autogen_warning: Option<String>,
885     /// Include a comment with the version of cbindgen used to generate the file
886     pub include_version: bool,
887     /// An optional name for the root namespace. Only applicable when language="C++"
888     pub namespace: Option<String>,
889     /// An optional list of namespaces. Only applicable when language="C++"
890     pub namespaces: Option<Vec<String>>,
891     /// An optional list of namespaces to declare as using. Only applicable when language="C++"
892     pub using_namespaces: Option<Vec<String>>,
893     /// The style to use for braces
894     pub braces: Braces,
895     /// The preferred length of a line, used for auto breaking function arguments
896     pub line_length: usize,
897     /// The amount of spaces in a tab
898     pub tab_width: usize,
899     /// The type of line endings to generate
900     pub line_endings: LineEndingStyle,
901     /// The language to output bindings for
902     pub language: Language,
903     /// Include preprocessor defines in C bindings to ensure C++ compatibility
904     pub cpp_compat: bool,
905     /// The style to declare structs, enums and unions in for C
906     pub style: Style,
907     /// Default sort key for functions and constants.
908     pub sort_by: SortKey,
909     /// If this option is true `usize` and `isize` will be converted into `size_t` and `ptrdiff_t`
910     /// instead of `uintptr_t` and `intptr_t` respectively.
911     pub usize_is_size_t: bool,
912     /// The configuration options for parsing
913     pub parse: ParseConfig,
914     /// The configuration options for exporting
915     pub export: ExportConfig,
916     /// The configuration options for macros.
917     pub macro_expansion: MacroExpansionConfig,
918     /// The configuration options for type layouts.
919     pub layout: LayoutConfig,
920     /// The configuration options for functions
921     #[serde(rename = "fn")]
922     pub function: FunctionConfig,
923     /// The configuration options for structs
924     #[serde(rename = "struct")]
925     pub structure: StructConfig,
926     /// The configuration options for enums
927     #[serde(rename = "enum")]
928     pub enumeration: EnumConfig,
929     /// The configuration options for constants
930     #[serde(rename = "const")]
931     pub constant: ConstantConfig,
932     /// Preprocessor defines to use when generating #ifdef's for #[cfg]
933     pub defines: HashMap<String, String>,
934     /// Include doc comments from Rust as documentation
935     pub documentation: bool,
936     /// How documentation comments should be styled.
937     pub documentation_style: DocumentationStyle,
938     /// Configuration options for pointers
939     #[serde(rename = "ptr")]
940     pub pointer: PtrConfig,
941     /// Only download sources for dependencies needed for the target platform.
942     ///
943     /// By default, cbindgen will fetch sources for dependencies used on any platform so that if a
944     /// type is defined in terms of a type from a dependency on another target (probably behind a
945     /// `#[cfg]`), cbindgen will be able to generate the appropriate binding as it can see the
946     /// nested type's definition. However, this makes calling cbindgen slower, as it may have to
947     /// download a number of additional dependencies.
948     ///
949     /// As an example, consider this Cargo.toml:
950     ///
951     /// ```toml
952     /// [target.'cfg(windows)'.dependencies]
953     /// windows = "0.7"
954     /// ```
955     ///
956     /// with this declaration in one of the `.rs` files that cbindgen is asked to generate bindings
957     /// for:
958     ///
959     /// ```rust,ignore
960     /// #[cfg(windows)]
961     /// pub struct Error(windows::ErrorCode);
962     /// ```
963     ///
964     /// With the default value (`false`), cbindgen will download the `windows` dependency even when
965     /// not compiling for Windows, and will thus be able to generate the binding for `Error`
966     /// (behind a `#define`).
967     ///
968     /// If this value is instead to `true`, cbindgen will _not_ download the `windows` dependency
969     /// if it's not compiling for Windows, but will also fail to generate a Windows binding for
970     /// `Error` as it does not know the definition for `ErrorCode`.
971     ///
972     /// The target can be chosen via the `TARGET` environment variable (if used
973     /// via the CLI, when ran from a build script cargo sets this variable
974     /// appropriately).
975     pub only_target_dependencies: bool,
976     /// Configuration options specific to Cython.
977     pub cython: CythonConfig,
978 }
979 
980 impl Default for Config {
default() -> Config981     fn default() -> Config {
982         Config {
983             header: None,
984             includes: Vec::new(),
985             sys_includes: Vec::new(),
986             after_includes: None,
987             trailer: None,
988             include_guard: None,
989             pragma_once: false,
990             autogen_warning: None,
991             include_version: false,
992             no_includes: false,
993             namespace: None,
994             namespaces: None,
995             using_namespaces: None,
996             braces: Braces::SameLine,
997             line_length: 100,
998             tab_width: 2,
999             line_endings: LineEndingStyle::default(),
1000             language: Language::Cxx,
1001             cpp_compat: false,
1002             style: Style::default(),
1003             usize_is_size_t: false,
1004             sort_by: SortKey::None,
1005             macro_expansion: Default::default(),
1006             parse: ParseConfig::default(),
1007             export: ExportConfig::default(),
1008             layout: LayoutConfig::default(),
1009             function: FunctionConfig::default(),
1010             structure: StructConfig::default(),
1011             enumeration: EnumConfig::default(),
1012             constant: ConstantConfig::default(),
1013             defines: HashMap::new(),
1014             documentation: true,
1015             documentation_style: DocumentationStyle::Auto,
1016             pointer: PtrConfig::default(),
1017             only_target_dependencies: false,
1018             cython: CythonConfig::default(),
1019         }
1020     }
1021 }
1022 
1023 impl Config {
cpp_compatible_c(&self) -> bool1024     pub(crate) fn cpp_compatible_c(&self) -> bool {
1025         self.language == Language::C && self.cpp_compat
1026     }
1027 
include_guard(&self) -> Option<&str>1028     pub(crate) fn include_guard(&self) -> Option<&str> {
1029         if self.language == Language::Cython {
1030             None
1031         } else {
1032             self.include_guard.as_deref()
1033         }
1034     }
1035 
includes(&self) -> &[String]1036     pub(crate) fn includes(&self) -> &[String] {
1037         if self.language == Language::Cython {
1038             &[]
1039         } else {
1040             &self.includes
1041         }
1042     }
1043 
sys_includes(&self) -> &[String]1044     pub(crate) fn sys_includes(&self) -> &[String] {
1045         if self.language == Language::Cython {
1046             &[]
1047         } else {
1048             &self.sys_includes
1049         }
1050     }
1051 
from_file<P: AsRef<StdPath>>(file_name: P) -> Result<Config, String>1052     pub fn from_file<P: AsRef<StdPath>>(file_name: P) -> Result<Config, String> {
1053         let config_text = fs::read_to_string(file_name.as_ref()).map_err(|_| {
1054             format!(
1055                 "Couldn't open config file: {}.",
1056                 file_name.as_ref().display()
1057             )
1058         })?;
1059 
1060         match toml::from_str::<Config>(&config_text) {
1061             Ok(x) => Ok(x),
1062             Err(e) => Err(format!("Couldn't parse config file: {}.", e)),
1063         }
1064     }
1065 
from_root_or_default<P: AsRef<StdPath>>(root: P) -> Config1066     pub fn from_root_or_default<P: AsRef<StdPath>>(root: P) -> Config {
1067         let c = root.as_ref().join("cbindgen.toml");
1068 
1069         if c.exists() {
1070             Config::from_file(c).unwrap()
1071         } else {
1072             Config::default()
1073         }
1074     }
1075 }
1076