| 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 | |