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