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