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