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