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
7use std::str::FromStr;
8
9use 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)]
13pub 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
22impl 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
35impl 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
47impl 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)]
55pub(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)]
70pub(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
112fn 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
121impl 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