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, path::PathBuf as StdPathBuf}; |
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, Eq)] |
22 | pub enum Language { |
23 | Cxx, |
24 | C, |
25 | Cython, |
26 | } |
27 | |
28 | impl 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 | |
50 | deserialize_enum_str!(Language); |
51 | |
52 | impl 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)] |
65 | pub 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 | |
77 | impl 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 | |
97 | impl 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 | |
111 | deserialize_enum_str!(LineEndingStyle); |
112 | |
113 | /// A style of braces to use for generating code. |
114 | #[derive (Debug, Clone, PartialEq, Eq)] |
115 | pub enum Braces { |
116 | SameLine, |
117 | NextLine, |
118 | } |
119 | |
120 | impl 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 | |
134 | deserialize_enum_str!(Braces); |
135 | |
136 | /// A type of layout to use when generating long lines of code. |
137 | #[derive (Debug, Clone, PartialEq, Eq)] |
138 | pub enum Layout { |
139 | Horizontal, |
140 | Vertical, |
141 | Auto, |
142 | } |
143 | |
144 | impl 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 | |
160 | deserialize_enum_str!(Layout); |
161 | |
162 | /// How the comments containing documentation should be styled. |
163 | #[derive (Debug, Clone, PartialEq, Eq, Copy)] |
164 | pub enum DocumentationStyle { |
165 | C, |
166 | C99, |
167 | Doxy, |
168 | Cxx, |
169 | Auto, |
170 | } |
171 | |
172 | impl 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 | |
188 | deserialize_enum_str!(DocumentationStyle); |
189 | |
190 | /// How much of the documentation to include in the header file. |
191 | #[derive (Debug, Clone, Copy)] |
192 | pub enum DocumentationLength { |
193 | Short, |
194 | Full, |
195 | } |
196 | |
197 | impl 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 | |
209 | deserialize_enum_str!(DocumentationLength); |
210 | |
211 | /// A style of Style to use when generating structs and enums. |
212 | #[derive (Debug, Copy, Clone, PartialEq, Eq, Default)] |
213 | pub enum Style { |
214 | #[default] |
215 | Both, |
216 | Tag, |
217 | Type, |
218 | } |
219 | |
220 | impl 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 | |
245 | impl 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 | |
261 | deserialize_enum_str!(Style); |
262 | |
263 | /// Different item types that we can generate and filter. |
264 | #[derive (Debug, Clone, PartialEq, Eq)] |
265 | pub enum ItemType { |
266 | Constants, |
267 | Globals, |
268 | Enums, |
269 | Structs, |
270 | Unions, |
271 | Typedefs, |
272 | OpaqueItems, |
273 | Functions, |
274 | } |
275 | |
276 | impl 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 | |
295 | deserialize_enum_str!(ItemType); |
296 | |
297 | /// Type which specifies the sort order of functions |
298 | #[derive (Debug, Clone, Copy, PartialEq, Eq)] |
299 | pub enum SortKey { |
300 | Name, |
301 | None, |
302 | } |
303 | |
304 | impl 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 | |
317 | deserialize_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)] |
324 | pub 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)] |
351 | pub 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 | |
358 | impl 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)] |
389 | pub 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 | |
397 | impl 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)] |
412 | pub 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 | |
435 | impl 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 | |
452 | impl 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)] |
473 | pub 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 | |
504 | impl 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)] |
560 | pub 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 | |
608 | impl 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 | |
632 | impl 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)] |
703 | pub 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 | |
712 | impl 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)] |
727 | pub 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)] |
734 | pub enum Profile { |
735 | Debug, |
736 | Release, |
737 | } |
738 | |
739 | impl 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 | |
751 | deserialize_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)] |
758 | pub 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 | |
772 | impl 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. |
791 | fn 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)] |
828 | pub 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 | |
853 | impl 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)] |
873 | pub 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)] |
883 | pub 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)] |
896 | pub 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 | |
1017 | impl 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 | |
1062 | impl 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 | |