cbindgen/bindgen/
config.rs

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, Copy, 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.clone_from(name);
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) = annotations.atom("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) = annotations.atom("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 rename rule to apply to the struct name used for prefixing associated
497    /// constants
498    pub rename_associated_constant: RenameRule,
499    /// The way to annotate this struct as #[must_use].
500    pub must_use: Option<String>,
501    /// The way to annotation this function as #[deprecated] without notes
502    pub deprecated: Option<String>,
503    /// The way to annotation this function as #[deprecated] with notes
504    pub deprecated_with_note: Option<String>,
505}
506
507impl StructConfig {
508    pub(crate) fn derive_constructor(&self, annotations: &AnnotationSet) -> bool {
509        if let Some(x) = annotations.bool("derive-constructor") {
510            return x;
511        }
512        self.derive_constructor
513    }
514    pub(crate) fn derive_eq(&self, annotations: &AnnotationSet) -> bool {
515        if let Some(x) = annotations.bool("derive-eq") {
516            return x;
517        }
518        self.derive_eq
519    }
520    pub(crate) fn derive_neq(&self, annotations: &AnnotationSet) -> bool {
521        if let Some(x) = annotations.bool("derive-neq") {
522            return x;
523        }
524        self.derive_neq
525    }
526    pub(crate) fn derive_lt(&self, annotations: &AnnotationSet) -> bool {
527        if let Some(x) = annotations.bool("derive-lt") {
528            return x;
529        }
530        self.derive_lt
531    }
532    pub(crate) fn derive_lte(&self, annotations: &AnnotationSet) -> bool {
533        if let Some(x) = annotations.bool("derive-lte") {
534            return x;
535        }
536        self.derive_lte
537    }
538    pub(crate) fn derive_gt(&self, annotations: &AnnotationSet) -> bool {
539        if let Some(x) = annotations.bool("derive-gt") {
540            return x;
541        }
542        self.derive_gt
543    }
544    pub(crate) fn derive_gte(&self, annotations: &AnnotationSet) -> bool {
545        if let Some(x) = annotations.bool("derive-gte") {
546            return x;
547        }
548        self.derive_gte
549    }
550    pub(crate) fn derive_ostream(&self, annotations: &AnnotationSet) -> bool {
551        if let Some(x) = annotations.bool("derive-ostream") {
552            return x;
553        }
554        self.derive_ostream
555    }
556}
557
558/// Settings to apply to generated enums.
559#[derive(Debug, Clone, Deserialize)]
560#[serde(rename_all = "snake_case")]
561#[serde(deny_unknown_fields)]
562#[serde(default)]
563pub struct EnumConfig {
564    /// The rename rule to apply to the name of enum variants
565    pub rename_variants: RenameRule,
566    /// The rename rule to apply to the names of the union fields in C/C++
567    /// generated from the Rust enum. Applied before rename_variants
568    /// rename rule. Defaults to SnakeCase.
569    pub rename_variant_name_fields: RenameRule,
570    /// Whether to add a `Sentinel` value at the end of every enum
571    /// This is useful in Gecko for IPC serialization
572    pub add_sentinel: bool,
573    /// Whether the enum variants should be prefixed with the enum name
574    pub prefix_with_name: bool,
575    /// Whether to generate static `::X(..)` constructors and `IsX()`
576    /// methods for tagged enums.
577    pub derive_helper_methods: bool,
578    /// Whether to generate `AsX() const` methods for tagged enums.
579    pub derive_const_casts: bool,
580    /// Whether to generate `AsX()` methods for tagged enums.
581    pub derive_mut_casts: bool,
582    /// The name of the macro to use for `derive_{const,mut}casts`. If custom, you're
583    /// responsible to provide the necessary header, otherwise `assert` will be
584    /// used, and `<cassert>` will be included.
585    pub cast_assert_name: Option<String>,
586    /// The way to annotation this enum as #[must_use].
587    pub must_use: Option<String>,
588    /// The way to annotation this function as #[deprecated] without notes
589    pub deprecated: Option<String>,
590    /// The way to annotation this function as #[deprecated] with notes
591    pub deprecated_with_note: Option<String>,
592    /// The way to annotate this enum variant as #[deprecated] without notes
593    pub deprecated_variant: Option<String>,
594    /// The way to annotate this enum variant as #[deprecated] with notes
595    pub deprecated_variant_with_note: Option<String>,
596    /// Whether to generate destructors of tagged enums.
597    pub derive_tagged_enum_destructor: bool,
598    /// Whether to generate copy-constructors of tagged enums.
599    pub derive_tagged_enum_copy_constructor: bool,
600    /// Whether to generate copy-assignment operators of tagged enums.
601    ///
602    /// This is only generated if a copy constructor for the same tagged enum is
603    /// generated as well.
604    pub derive_tagged_enum_copy_assignment: bool,
605    /// Whether to generate a ostream serializer for the struct
606    pub derive_ostream: bool,
607    /// Declare the enum as an enum class.
608    /// Only relevant when targeting C++.
609    pub enum_class: bool,
610    /// Whether to generate empty, private default-constructors for tagged
611    /// enums.
612    pub private_default_tagged_enum_constructor: bool,
613}
614
615impl Default for EnumConfig {
616    fn default() -> EnumConfig {
617        EnumConfig {
618            rename_variants: RenameRule::None,
619            rename_variant_name_fields: RenameRule::SnakeCase,
620            add_sentinel: false,
621            prefix_with_name: false,
622            derive_helper_methods: false,
623            derive_const_casts: false,
624            derive_mut_casts: false,
625            cast_assert_name: None,
626            must_use: None,
627            deprecated: None,
628            deprecated_with_note: None,
629            deprecated_variant: None,
630            deprecated_variant_with_note: None,
631            derive_tagged_enum_destructor: false,
632            derive_tagged_enum_copy_constructor: false,
633            derive_tagged_enum_copy_assignment: false,
634            derive_ostream: false,
635            enum_class: true,
636            private_default_tagged_enum_constructor: false,
637        }
638    }
639}
640
641impl EnumConfig {
642    pub(crate) fn add_sentinel(&self, annotations: &AnnotationSet) -> bool {
643        if let Some(x) = annotations.bool("add-sentinel") {
644            return x;
645        }
646        self.add_sentinel
647    }
648    pub(crate) fn derive_helper_methods(&self, annotations: &AnnotationSet) -> bool {
649        if let Some(x) = annotations.bool("derive-helper-methods") {
650            return x;
651        }
652        self.derive_helper_methods
653    }
654    pub(crate) fn derive_const_casts(&self, annotations: &AnnotationSet) -> bool {
655        if let Some(x) = annotations.bool("derive-const-casts") {
656            return x;
657        }
658        self.derive_const_casts
659    }
660    pub(crate) fn derive_mut_casts(&self, annotations: &AnnotationSet) -> bool {
661        if let Some(x) = annotations.bool("derive-mut-casts") {
662            return x;
663        }
664        self.derive_mut_casts
665    }
666    pub(crate) fn derive_tagged_enum_destructor(&self, annotations: &AnnotationSet) -> bool {
667        if let Some(x) = annotations.bool("derive-tagged-enum-destructor") {
668            return x;
669        }
670        self.derive_tagged_enum_destructor
671    }
672    pub(crate) fn derive_tagged_enum_copy_constructor(&self, annotations: &AnnotationSet) -> bool {
673        if let Some(x) = annotations.bool("derive-tagged-enum-copy-constructor") {
674            return x;
675        }
676        self.derive_tagged_enum_copy_constructor
677    }
678    pub(crate) fn derive_tagged_enum_copy_assignment(&self, annotations: &AnnotationSet) -> bool {
679        if let Some(x) = annotations.bool("derive-tagged-enum-copy-assignment") {
680            return x;
681        }
682        self.derive_tagged_enum_copy_assignment
683    }
684    pub(crate) fn derive_ostream(&self, annotations: &AnnotationSet) -> bool {
685        if let Some(x) = annotations.bool("derive-ostream") {
686            return x;
687        }
688        self.derive_ostream
689    }
690    pub(crate) fn enum_class(&self, annotations: &AnnotationSet) -> bool {
691        if let Some(x) = annotations.bool("enum-class") {
692            return x;
693        }
694        self.enum_class
695    }
696    pub(crate) fn private_default_tagged_enum_constructor(
697        &self,
698        annotations: &AnnotationSet,
699    ) -> bool {
700        if let Some(x) = annotations.bool("private-default-tagged-enum-constructor") {
701            return x;
702        }
703        self.private_default_tagged_enum_constructor
704    }
705}
706
707/// Settings to apply to generated constants.
708#[derive(Debug, Clone, Deserialize)]
709#[serde(rename_all = "snake_case")]
710#[serde(deny_unknown_fields)]
711#[serde(default)]
712pub struct ConstantConfig {
713    /// Whether a generated constant can be a static const in C++ mode.
714    pub allow_static_const: bool,
715    /// Whether a generated constant should be constexpr in C++ mode.
716    pub allow_constexpr: bool,
717    /// Sort key for constants
718    pub sort_by: Option<SortKey>,
719}
720
721impl Default for ConstantConfig {
722    fn default() -> ConstantConfig {
723        ConstantConfig {
724            allow_static_const: true,
725            allow_constexpr: true,
726            sort_by: None,
727        }
728    }
729}
730
731/// Settings for custom macro expansion.
732#[derive(Debug, Clone, Deserialize, Default)]
733#[serde(rename_all = "snake_case")]
734#[serde(deny_unknown_fields)]
735#[serde(default)]
736pub struct MacroExpansionConfig {
737    /// Whether the `bitflags` macro should be expanded.
738    pub bitflags: bool,
739}
740
741/// Controls which Cargo profile is used for macro expansion.
742#[derive(Debug, Copy, Clone, PartialEq, Eq)]
743pub enum Profile {
744    Debug,
745    Release,
746}
747
748impl FromStr for Profile {
749    type Err = String;
750
751    fn from_str(s: &str) -> Result<Profile, Self::Err> {
752        match s {
753            "debug" | "Debug" => Ok(Profile::Debug),
754            "release" | "Release" => Ok(Profile::Release),
755            _ => Err(format!("Unrecognized Profile: '{}'.", s)),
756        }
757    }
758}
759
760deserialize_enum_str!(Profile);
761
762/// Settings to apply when running `rustc -Zunpretty=expanded`
763#[derive(Debug, Clone, Deserialize)]
764#[serde(rename_all = "snake_case")]
765#[serde(deny_unknown_fields)]
766#[serde(default)]
767pub struct ParseExpandConfig {
768    /// The names of crates to parse with `rustc -Zunpretty=expanded`
769    pub crates: Vec<String>,
770    /// Whether to enable all the features when expanding.
771    pub all_features: bool,
772    /// Whether to use the default feature set when expanding.
773    pub default_features: bool,
774    /// List of features to use when expanding. Combines with `default_features` like in
775    /// `Cargo.toml`.
776    pub features: Option<Vec<String>>,
777    /// Controls whether or not to pass `--release` when expanding.
778    pub profile: Profile,
779}
780
781impl Default for ParseExpandConfig {
782    fn default() -> ParseExpandConfig {
783        ParseExpandConfig {
784            crates: Vec::new(),
785            all_features: false,
786            default_features: true,
787            features: None,
788            profile: Profile::Debug,
789        }
790    }
791}
792
793// Backwards-compatibility deserializer for ParseExpandConfig. This allows accepting both the
794// simple `expand = ["crate"]` and the more complex `expand = {"crates": ["crate"],
795// "default_features": false}` format for the `expand` key.
796//
797// Note that one (major) difference between the two forms is that, for backwards-compatibility
798// reasons, the `expand = ["crate"]` form will enable the `--all-features` flag by default while
799// the `expand = {"crates": ["crate"]}` form will use the default feature set by default.
800fn retrocomp_parse_expand_config_deserialize<'de, D: Deserializer<'de>>(
801    deserializer: D,
802) -> Result<ParseExpandConfig, D::Error> {
803    struct ParseExpandVisitor;
804
805    impl<'de> Visitor<'de> for ParseExpandVisitor {
806        type Value = ParseExpandConfig;
807
808        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
809            formatter.write_str("a map or sequence of string")
810        }
811
812        fn visit_seq<A: SeqAccess<'de>>(self, seq: A) -> Result<Self::Value, A::Error> {
813            let crates =
814                <Vec<String> as Deserialize>::deserialize(SeqAccessDeserializer::new(seq))?;
815            Ok(ParseExpandConfig {
816                crates,
817                all_features: true,
818                default_features: true,
819                features: None,
820                profile: Profile::Debug,
821            })
822        }
823
824        fn visit_map<A: MapAccess<'de>>(self, map: A) -> Result<Self::Value, A::Error> {
825            <ParseExpandConfig as Deserialize>::deserialize(MapAccessDeserializer::new(map))
826        }
827    }
828
829    deserializer.deserialize_any(ParseExpandVisitor)
830}
831
832/// Settings to apply when parsing.
833#[derive(Debug, Default, Clone, Deserialize)]
834#[serde(rename_all = "snake_case")]
835#[serde(deny_unknown_fields)]
836#[serde(default)]
837pub struct ParseConfig {
838    /// Whether to parse dependencies when generating bindings. When this is true,
839    /// each dependent crate is found using a combination of `cargo metadata` and
840    /// `Cargo.lock`. To further control this behavior, crates can be whitelisted or
841    /// blacklisted using `include` and `exclude` respectively. Additionally in cases
842    /// where crates have types to expose in bindings hidden in macros, a crate can
843    /// be marked in `expand` and `cargo expand` will be used to expand the macros
844    /// before parsing. A crate marked in `expand` doesn't need to be added to any
845    /// whitelist.
846    pub parse_deps: bool,
847    /// An optional whitelist of names of crates to parse
848    pub include: Option<Vec<String>>,
849    /// The names of crates to not parse
850    pub exclude: Vec<String>,
851    /// The configuration options for `rustc -Zunpretty=expanded`
852    #[serde(deserialize_with = "retrocomp_parse_expand_config_deserialize")]
853    pub expand: ParseExpandConfig,
854    /// Whether to use a new temporary target directory when running `rustc -Zunpretty=expanded`.
855    /// This may be required for some build processes.
856    pub clean: bool,
857    /// List of crate names which generate consts, statics, and fns. By default
858    /// no dependent crates generate them.
859    pub extra_bindings: Vec<String>,
860}
861
862impl ParseConfig {
863    pub(crate) fn should_generate_top_level_item(
864        &self,
865        crate_name: &str,
866        binding_crate_name: &str,
867    ) -> bool {
868        if crate_name == binding_crate_name {
869            // Always generate items for the binding crate.
870            return true;
871        }
872
873        self.extra_bindings.iter().any(|dep| dep == crate_name)
874    }
875}
876
877/// Settings to apply to pointers
878#[derive(Debug, Clone, Default, Deserialize)]
879#[serde(rename_all = "snake_case")]
880#[serde(deny_unknown_fields)]
881#[serde(default)]
882pub struct PtrConfig {
883    /// Optional attribute to apply to pointers that are required to not be null
884    pub non_null_attribute: Option<String>,
885}
886
887/// Settings specific to Cython bindings.
888#[derive(Debug, Clone, Default, Deserialize)]
889#[serde(rename_all = "snake_case")]
890#[serde(deny_unknown_fields)]
891#[serde(default)]
892pub struct CythonConfig {
893    /// Header specified in the top level `cdef extern from header:` declaration.
894    pub header: Option<String>,
895    /// `from module cimport name1, name2, ...` declarations added in the same place
896    /// where you'd get includes in C.
897    pub cimports: BTreeMap<String, Vec<String>>,
898}
899
900/// A collection of settings to customize the generated bindings.
901#[derive(Debug, Clone, Deserialize)]
902#[serde(rename_all = "snake_case")]
903#[serde(deny_unknown_fields)]
904#[serde(default)]
905pub struct Config {
906    /// Optional text to output at the beginning of the file
907    pub header: Option<String>,
908    /// A list of additional includes to put at the beginning of the generated header
909    pub includes: Vec<String>,
910    /// A list of additional system includes to put at the beginning of the generated header
911    pub sys_includes: Vec<String>,
912    /// Optional verbatim code added after the include blocks
913    pub after_includes: Option<String>,
914    /// Optional text to output at the end of the file
915    pub trailer: Option<String>,
916    /// Optional name to use for an include guard
917    pub include_guard: Option<String>,
918    /// Add a `#pragma once` guard
919    pub pragma_once: bool,
920    /// Generates no includes at all. Overrides all other include options
921    ///
922    /// This option is useful when using cbindgen with tools such as python's cffi which
923    /// doesn't understand include directives
924    pub no_includes: bool,
925    // Package version: True if the package version should appear as a comment in the .h file
926    pub package_version: bool,
927    /// Optional text to output at major sections to deter manual editing
928    pub autogen_warning: Option<String>,
929    /// Include a comment with the version of cbindgen used to generate the file
930    pub include_version: bool,
931    /// An optional name for the root namespace. Only applicable when language="C++"
932    pub namespace: Option<String>,
933    /// An optional list of namespaces. Only applicable when language="C++"
934    pub namespaces: Option<Vec<String>>,
935    /// An optional list of namespaces to declare as using. Only applicable when language="C++"
936    pub using_namespaces: Option<Vec<String>>,
937    /// The style to use for braces
938    pub braces: Braces,
939    /// The preferred length of a line, used for auto breaking function arguments
940    pub line_length: usize,
941    /// The amount of spaces in a tab
942    pub tab_width: usize,
943    /// The type of line endings to generate
944    pub line_endings: LineEndingStyle,
945    /// The language to output bindings for
946    pub language: Language,
947    /// Include preprocessor defines in C bindings to ensure C++ compatibility
948    pub cpp_compat: bool,
949    /// The style to declare structs, enums and unions in for C
950    pub style: Style,
951    /// Default sort key for functions and constants.
952    pub sort_by: SortKey,
953    /// If this option is true `usize` and `isize` will be converted into `size_t` and `ptrdiff_t`
954    /// instead of `uintptr_t` and `intptr_t` respectively.
955    pub usize_is_size_t: bool,
956    /// The configuration options for parsing
957    pub parse: ParseConfig,
958    /// The configuration options for exporting
959    pub export: ExportConfig,
960    /// The configuration options for macros.
961    pub macro_expansion: MacroExpansionConfig,
962    /// The configuration options for type layouts.
963    pub layout: LayoutConfig,
964    /// The configuration options for functions
965    #[serde(rename = "fn")]
966    pub function: FunctionConfig,
967    /// The configuration options for structs
968    #[serde(rename = "struct")]
969    pub structure: StructConfig,
970    /// The configuration options for enums
971    #[serde(rename = "enum")]
972    pub enumeration: EnumConfig,
973    /// The configuration options for constants
974    #[serde(rename = "const")]
975    pub constant: ConstantConfig,
976    /// Preprocessor defines to use when generating #ifdef's for #[cfg]
977    pub defines: HashMap<String, String>,
978    /// Include doc comments from Rust as documentation
979    pub documentation: bool,
980    /// How documentation comments should be styled.
981    pub documentation_style: DocumentationStyle,
982    /// How much of the documentation should be output for each item.
983    pub documentation_length: DocumentationLength,
984    /// Configuration options for pointers
985    #[serde(rename = "ptr")]
986    pub pointer: PtrConfig,
987    /// Only download sources for dependencies needed for the target platform.
988    ///
989    /// By default, cbindgen will fetch sources for dependencies used on any platform so that if a
990    /// type is defined in terms of a type from a dependency on another target (probably behind a
991    /// `#[cfg]`), cbindgen will be able to generate the appropriate binding as it can see the
992    /// nested type's definition. However, this makes calling cbindgen slower, as it may have to
993    /// download a number of additional dependencies.
994    ///
995    /// As an example, consider this Cargo.toml:
996    ///
997    /// ```toml
998    /// [target.'cfg(windows)'.dependencies]
999    /// windows = "0.7"
1000    /// ```
1001    ///
1002    /// with this declaration in one of the `.rs` files that cbindgen is asked to generate bindings
1003    /// for:
1004    ///
1005    /// ```rust,ignore
1006    /// #[cfg(windows)]
1007    /// pub struct Error(windows::ErrorCode);
1008    /// ```
1009    ///
1010    /// With the default value (`false`), cbindgen will download the `windows` dependency even when
1011    /// not compiling for Windows, and will thus be able to generate the binding for `Error`
1012    /// (behind a `#define`).
1013    ///
1014    /// If this value is instead to `true`, cbindgen will _not_ download the `windows` dependency
1015    /// if it's not compiling for Windows, but will also fail to generate a Windows binding for
1016    /// `Error` as it does not know the definition for `ErrorCode`.
1017    ///
1018    /// The target can be chosen via the `TARGET` environment variable (if used
1019    /// via the CLI, when ran from a build script cargo sets this variable
1020    /// appropriately).
1021    pub only_target_dependencies: bool,
1022    /// Configuration options specific to Cython.
1023    pub cython: CythonConfig,
1024    #[doc(hidden)]
1025    #[serde(skip)]
1026    /// Internal field for tracking from which file the config was loaded.
1027    ///
1028    /// Users should not set this field explicitly. Making the field private
1029    /// prevents users from filling the struct with `..Default::default()`,
1030    /// and creating a new InternalConfig struct would require more breaking
1031    /// changes to our public API.
1032    pub config_path: Option<StdPathBuf>,
1033}
1034
1035impl Default for Config {
1036    fn default() -> Config {
1037        Config {
1038            header: None,
1039            includes: Vec::new(),
1040            sys_includes: Vec::new(),
1041            after_includes: None,
1042            trailer: None,
1043            include_guard: None,
1044            pragma_once: false,
1045            autogen_warning: None,
1046            include_version: false,
1047            no_includes: false,
1048            package_version: false,
1049            namespace: None,
1050            namespaces: None,
1051            using_namespaces: None,
1052            braces: Braces::SameLine,
1053            line_length: 100,
1054            tab_width: 2,
1055            line_endings: LineEndingStyle::default(),
1056            language: Language::Cxx,
1057            cpp_compat: false,
1058            style: Style::default(),
1059            usize_is_size_t: false,
1060            sort_by: SortKey::None,
1061            macro_expansion: Default::default(),
1062            parse: ParseConfig::default(),
1063            export: ExportConfig::default(),
1064            layout: LayoutConfig::default(),
1065            function: FunctionConfig::default(),
1066            structure: StructConfig::default(),
1067            enumeration: EnumConfig::default(),
1068            constant: ConstantConfig::default(),
1069            defines: HashMap::new(),
1070            documentation: true,
1071            documentation_style: DocumentationStyle::Auto,
1072            documentation_length: DocumentationLength::Full,
1073            pointer: PtrConfig::default(),
1074            only_target_dependencies: false,
1075            cython: CythonConfig::default(),
1076            config_path: None,
1077        }
1078    }
1079}
1080
1081impl Config {
1082    pub(crate) fn cpp_compatible_c(&self) -> bool {
1083        self.language == Language::C && self.cpp_compat
1084    }
1085
1086    pub(crate) fn include_guard(&self) -> Option<&str> {
1087        if self.language == Language::Cython {
1088            None
1089        } else {
1090            self.include_guard.as_deref()
1091        }
1092    }
1093
1094    pub(crate) fn includes(&self) -> &[String] {
1095        if self.language == Language::Cython {
1096            &[]
1097        } else {
1098            &self.includes
1099        }
1100    }
1101
1102    pub(crate) fn sys_includes(&self) -> &[String] {
1103        if self.language == Language::Cython {
1104            &[]
1105        } else {
1106            &self.sys_includes
1107        }
1108    }
1109
1110    pub fn from_file<P: AsRef<StdPath>>(file_name: P) -> Result<Config, String> {
1111        let config_text = fs::read_to_string(file_name.as_ref()).map_err(|_| {
1112            format!(
1113                "Couldn't open config file: {}.",
1114                file_name.as_ref().display()
1115            )
1116        })?;
1117
1118        let mut config = toml::from_str::<Config>(&config_text)
1119            .map_err(|e| format!("Couldn't parse config file: {}.", e))?;
1120        config.config_path = Some(StdPathBuf::from(file_name.as_ref()));
1121        Ok(config)
1122    }
1123
1124    pub fn from_root_or_default<P: AsRef<StdPath>>(root: P) -> Config {
1125        let c = root.as_ref().join("cbindgen.toml");
1126
1127        if c.exists() {
1128            Config::from_file(c).unwrap()
1129        } else {
1130            Config::default()
1131        }
1132    }
1133}