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