1 //! Types and functions related to bindgen annotation comments.
2 //!
3 //! Users can add annotations in doc comments to types that they would like to
4 //! replace other types with, mark as opaque, etc. This module deals with all of
5 //! that stuff.
6 
7 use std::str::FromStr;
8 
9 use crate::clang;
10 
11 /// What kind of visibility modifer should be used for a struct or field?
12 #[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
13 pub enum FieldVisibilityKind {
14     /// Fields are marked as private, i.e., struct Foo {bar: bool}
15     Private,
16     /// Fields are marked as crate public, i.e., struct Foo {pub(crate) bar: bool}
17     PublicCrate,
18     /// Fields are marked as public, i.e., struct Foo {pub bar: bool}
19     Public,
20 }
21 
22 impl FromStr for FieldVisibilityKind {
23     type Err = String;
24 
from_str(s: &str) -> Result<Self, Self::Err>25     fn from_str(s: &str) -> Result<Self, Self::Err> {
26         match s {
27             "private" => Ok(Self::Private),
28             "crate" => Ok(Self::PublicCrate),
29             "public" => Ok(Self::Public),
30             _ => Err(format!("Invalid visibility kind: `{}`", s)),
31         }
32     }
33 }
34 
35 impl std::fmt::Display for FieldVisibilityKind {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result36     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37         let s = match self {
38             FieldVisibilityKind::Private => "private",
39             FieldVisibilityKind::PublicCrate => "crate",
40             FieldVisibilityKind::Public => "public",
41         };
42 
43         s.fmt(f)
44     }
45 }
46 
47 impl Default for FieldVisibilityKind {
default() -> Self48     fn default() -> Self {
49         FieldVisibilityKind::Public
50     }
51 }
52 
53 /// What kind of accessor should we provide for a field?
54 #[derive(Copy, PartialEq, Eq, Clone, Debug)]
55 pub(crate) enum FieldAccessorKind {
56     /// No accessor.
57     None,
58     /// Plain accessor.
59     Regular,
60     /// Unsafe accessor.
61     Unsafe,
62     /// Immutable accessor.
63     Immutable,
64 }
65 
66 /// Annotations for a given item, or a field.
67 ///
68 /// You can see the kind of comments that are accepted in the [Doxygen documentation](https://www.doxygen.nl/manual/docblocks.html).
69 #[derive(Default, Clone, PartialEq, Eq, Debug)]
70 pub(crate) struct Annotations {
71     /// Whether this item is marked as opaque. Only applies to types.
72     opaque: bool,
73     /// Whether this item should be hidden from the output. Only applies to
74     /// types, or enum variants.
75     hide: bool,
76     /// Whether this type should be replaced by another. The name is a
77     /// namespace-aware path.
78     use_instead_of: Option<Vec<String>>,
79     /// Manually disable deriving copy/clone on this type. Only applies to
80     /// struct or union types.
81     disallow_copy: bool,
82     /// Manually disable deriving debug on this type.
83     disallow_debug: bool,
84     /// Manually disable deriving/implement default on this type.
85     disallow_default: bool,
86     /// Whether to add a `#[must_use]` annotation to this type.
87     must_use_type: bool,
88     /// Visibility of struct fields. You can set this on
89     /// structs (it will apply to all the fields), or individual fields.
90     visibility_kind: Option<FieldVisibilityKind>,
91     /// The kind of accessor this field will have. Also can be applied to
92     /// structs so all the fields inside share it by default.
93     accessor_kind: Option<FieldAccessorKind>,
94     /// Whether this enum variant should be constified.
95     ///
96     /// This is controlled by the `constant` attribute, this way:
97     ///
98     /// ```cpp
99     /// enum Foo {
100     ///     Bar = 0, /**< <div rustbindgen constant></div> */
101     ///     Baz = 0,
102     /// };
103     /// ```
104     ///
105     /// In that case, bindgen will generate a constant for `Bar` instead of
106     /// `Baz`.
107     constify_enum_variant: bool,
108     /// List of explicit derives for this type.
109     derives: Vec<String>,
110 }
111 
parse_accessor(s: &str) -> FieldAccessorKind112 fn parse_accessor(s: &str) -> FieldAccessorKind {
113     match s {
114         "false" => FieldAccessorKind::None,
115         "unsafe" => FieldAccessorKind::Unsafe,
116         "immutable" => FieldAccessorKind::Immutable,
117         _ => FieldAccessorKind::Regular,
118     }
119 }
120 
121 impl Annotations {
122     /// Construct new annotations for the given cursor and its bindgen comments
123     /// (if any).
new(cursor: &clang::Cursor) -> Option<Annotations>124     pub(crate) fn new(cursor: &clang::Cursor) -> Option<Annotations> {
125         let mut anno = Annotations::default();
126         let mut matched_one = false;
127         anno.parse(&cursor.comment(), &mut matched_one);
128 
129         if matched_one {
130             Some(anno)
131         } else {
132             None
133         }
134     }
135 
136     /// Should this type be hidden?
hide(&self) -> bool137     pub(crate) fn hide(&self) -> bool {
138         self.hide
139     }
140 
141     /// Should this type be opaque?
opaque(&self) -> bool142     pub(crate) fn opaque(&self) -> bool {
143         self.opaque
144     }
145 
146     /// For a given type, indicates the type it should replace.
147     ///
148     /// For example, in the following code:
149     ///
150     /// ```cpp
151     ///
152     /// /** <div rustbindgen replaces="Bar"></div> */
153     /// struct Foo { int x; };
154     ///
155     /// struct Bar { char foo; };
156     /// ```
157     ///
158     /// the generated code would look something like:
159     ///
160     /// ```
161     /// /** <div rustbindgen replaces="Bar"></div> */
162     /// struct Bar {
163     ///     x: ::std::os::raw::c_int,
164     /// };
165     /// ```
166     ///
167     /// That is, code for `Foo` is used to generate `Bar`.
use_instead_of(&self) -> Option<&[String]>168     pub(crate) fn use_instead_of(&self) -> Option<&[String]> {
169         self.use_instead_of.as_deref()
170     }
171 
172     /// The list of derives that have been specified in this annotation.
derives(&self) -> &[String]173     pub(crate) fn derives(&self) -> &[String] {
174         &self.derives
175     }
176 
177     /// Should we avoid implementing the `Copy` trait?
disallow_copy(&self) -> bool178     pub(crate) fn disallow_copy(&self) -> bool {
179         self.disallow_copy
180     }
181 
182     /// Should we avoid implementing the `Debug` trait?
disallow_debug(&self) -> bool183     pub(crate) fn disallow_debug(&self) -> bool {
184         self.disallow_debug
185     }
186 
187     /// Should we avoid implementing the `Default` trait?
disallow_default(&self) -> bool188     pub(crate) fn disallow_default(&self) -> bool {
189         self.disallow_default
190     }
191 
192     /// Should this type get a `#[must_use]` annotation?
must_use_type(&self) -> bool193     pub(crate) fn must_use_type(&self) -> bool {
194         self.must_use_type
195     }
196 
197     /// What kind of accessors should we provide for this type's fields?
visibility_kind(&self) -> Option<FieldVisibilityKind>198     pub(crate) fn visibility_kind(&self) -> Option<FieldVisibilityKind> {
199         self.visibility_kind
200     }
201 
202     /// What kind of accessors should we provide for this type's fields?
accessor_kind(&self) -> Option<FieldAccessorKind>203     pub(crate) fn accessor_kind(&self) -> Option<FieldAccessorKind> {
204         self.accessor_kind
205     }
206 
parse(&mut self, comment: &clang::Comment, matched: &mut bool)207     fn parse(&mut self, comment: &clang::Comment, matched: &mut bool) {
208         use clang_sys::CXComment_HTMLStartTag;
209         if comment.kind() == CXComment_HTMLStartTag &&
210             comment.get_tag_name() == "div" &&
211             comment
212                 .get_tag_attrs()
213                 .next()
214                 .map_or(false, |attr| attr.name == "rustbindgen")
215         {
216             *matched = true;
217             for attr in comment.get_tag_attrs() {
218                 match attr.name.as_str() {
219                     "opaque" => self.opaque = true,
220                     "hide" => self.hide = true,
221                     "nocopy" => self.disallow_copy = true,
222                     "nodebug" => self.disallow_debug = true,
223                     "nodefault" => self.disallow_default = true,
224                     "mustusetype" => self.must_use_type = true,
225                     "replaces" => {
226                         self.use_instead_of = Some(
227                             attr.value.split("::").map(Into::into).collect(),
228                         )
229                     }
230                     "derive" => self.derives.push(attr.value),
231                     "private" => {
232                         self.visibility_kind = if attr.value != "false" {
233                             Some(FieldVisibilityKind::Private)
234                         } else {
235                             Some(FieldVisibilityKind::Public)
236                         };
237                     }
238                     "accessor" => {
239                         self.accessor_kind = Some(parse_accessor(&attr.value))
240                     }
241                     "constant" => self.constify_enum_variant = true,
242                     _ => {}
243                 }
244             }
245         }
246 
247         for child in comment.get_children() {
248             self.parse(&child, matched);
249         }
250     }
251 
252     /// Returns whether we've parsed a "constant" attribute.
constify_enum_variant(&self) -> bool253     pub(crate) fn constify_enum_variant(&self) -> bool {
254         self.constify_enum_variant
255     }
256 }
257