| 1 | use std::io::Write; |
| 2 | |
| 3 | use syn::ext::IdentExt; |
| 4 | |
| 5 | use crate::bindgen::cdecl; |
| 6 | use crate::bindgen::config::{Config, Language}; |
| 7 | use crate::bindgen::ir::{AnnotationSet, Cfg, ConditionWrite}; |
| 8 | use crate::bindgen::ir::{Documentation, Path, ToCondition, Type}; |
| 9 | use crate::bindgen::writer::{Source, SourceWriter}; |
| 10 | |
| 11 | #[derive (Debug, Clone)] |
| 12 | pub struct Field { |
| 13 | pub name: String, |
| 14 | pub ty: Type, |
| 15 | pub cfg: Option<Cfg>, |
| 16 | pub annotations: AnnotationSet, |
| 17 | pub documentation: Documentation, |
| 18 | } |
| 19 | |
| 20 | impl Field { |
| 21 | pub fn from_name_and_type(name: String, ty: Type) -> Field { |
| 22 | Field { |
| 23 | name, |
| 24 | ty, |
| 25 | cfg: None, |
| 26 | annotations: AnnotationSet::new(), |
| 27 | documentation: Documentation::none(), |
| 28 | } |
| 29 | } |
| 30 | |
| 31 | pub fn load(field: &syn::Field, self_path: &Path) -> Result<Option<Field>, String> { |
| 32 | Ok(if let Some(mut ty) = Type::load(&field.ty)? { |
| 33 | ty.replace_self_with(self_path); |
| 34 | Some(Field { |
| 35 | name: field |
| 36 | .ident |
| 37 | .as_ref() |
| 38 | .ok_or_else(|| "field is missing identifier" .to_string())? |
| 39 | .unraw() |
| 40 | .to_string(), |
| 41 | ty, |
| 42 | cfg: Cfg::load(&field.attrs), |
| 43 | annotations: AnnotationSet::load(&field.attrs)?, |
| 44 | documentation: Documentation::load(&field.attrs), |
| 45 | }) |
| 46 | } else { |
| 47 | None |
| 48 | }) |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | impl Source for Field { |
| 53 | fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) { |
| 54 | // Cython doesn't support conditional fields. |
| 55 | let condition = self.cfg.to_condition(config); |
| 56 | if config.language != Language::Cython { |
| 57 | condition.write_before(config, out); |
| 58 | } |
| 59 | |
| 60 | self.documentation.write(config, out); |
| 61 | cdecl::write_field(out, &self.ty, &self.name, config); |
| 62 | // Cython extern declarations don't manage layouts, layouts are defined entierly by the |
| 63 | // corresponding C code. So we can omit bitfield sizes which are not supported by Cython. |
| 64 | if config.language != Language::Cython { |
| 65 | if let Some(bitfield) = self.annotations.atom("bitfield" ) { |
| 66 | write!(out, ": {}" , bitfield.unwrap_or_default()); |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | if config.language != Language::Cython { |
| 71 | condition.write_after(config, out); |
| 72 | // FIXME(#634): `write_vertical_source_list` should support |
| 73 | // configuring list elements natively. For now we print a newline |
| 74 | // here to avoid printing `#endif;` with semicolon. |
| 75 | if condition.is_some() { |
| 76 | out.new_line(); |
| 77 | } |
| 78 | } |
| 79 | } |
| 80 | } |
| 81 | |