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 | |
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 { |
36 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
37 | let s: &str = 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 { |
48 | 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 | |
112 | 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). |
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? |
137 | pub(crate) fn hide(&self) -> bool { |
138 | self.hide |
139 | } |
140 | |
141 | /// Should this type be opaque? |
142 | 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`. |
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. |
173 | pub(crate) fn derives(&self) -> &[String] { |
174 | &self.derives |
175 | } |
176 | |
177 | /// Should we avoid implementing the `Copy` trait? |
178 | pub(crate) fn disallow_copy(&self) -> bool { |
179 | self.disallow_copy |
180 | } |
181 | |
182 | /// Should we avoid implementing the `Debug` trait? |
183 | pub(crate) fn disallow_debug(&self) -> bool { |
184 | self.disallow_debug |
185 | } |
186 | |
187 | /// Should we avoid implementing the `Default` trait? |
188 | pub(crate) fn disallow_default(&self) -> bool { |
189 | self.disallow_default |
190 | } |
191 | |
192 | /// Should this type get a `#[must_use]` annotation? |
193 | 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? |
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? |
203 | pub(crate) fn accessor_kind(&self) -> Option<FieldAccessorKind> { |
204 | self.accessor_kind |
205 | } |
206 | |
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. |
253 | pub(crate) fn constify_enum_variant(&self) -> bool { |
254 | self.constify_enum_variant |
255 | } |
256 | } |
257 | |