1use std::io::Write;
2
3use syn::ext::IdentExt;
4
5use crate::bindgen::cdecl;
6use crate::bindgen::config::{Config, Language};
7use crate::bindgen::ir::{AnnotationSet, Cfg, ConditionWrite};
8use crate::bindgen::ir::{Documentation, Path, ToCondition, Type};
9use crate::bindgen::writer::{Source, SourceWriter};
10
11#[derive(Debug, Clone)]
12pub 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
20impl 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
52impl 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