libgir/codegen/sys/
fields.rs
1use crate::{
2 analysis::{rust_type::*, types::*},
3 codegen::sys::{ffi_type::ffi_type, functions::function_signature},
4 env::Env,
5 library::*,
6 traits::{IntoString, MaybeRefAs},
7};
8
9pub struct Fields {
10 pub name: String,
12 pub external: bool,
14 pub truncated: Option<String>,
16 derives_copy: bool,
17 pub kind: &'static str,
19 pub cfg_condition: Option<String>,
21 pub fields: Vec<FieldInfo>,
22}
23
24pub struct FieldInfo {
25 pub name: String,
27 pub typ: String,
29 unsafe_access: bool,
31 pub debug: bool,
33}
34
35impl Fields {
36 pub fn derived_traits(&self) -> Vec<&'static str> {
38 let mut traits = Vec::new();
39 if self.derives_copy {
40 traits.push("Copy");
41 traits.push("Clone");
42 }
43 traits
44 }
45}
46
47impl FieldInfo {
48 pub fn access_str(&self) -> String {
51 let mut s = format!("&self.{}", self.name);
52 if self.unsafe_access {
53 s = format!("unsafe {{ {s} }}");
54 }
55 s
56 }
57}
58
59pub fn from_record(env: &Env, record: &Record) -> Fields {
60 let (fields, truncated) = analyze_fields(env, false, &record.fields);
61 let derives_copy = truncated.is_none() && record.derives_copy(&env.library);
62 Fields {
63 name: record.c_type.clone(),
64 external: record.is_external(&env.library),
65 truncated,
66 derives_copy,
67 kind: "struct",
68 cfg_condition: get_gobject_cfg_condition(env, &record.name),
69 fields,
70 }
71}
72
73pub fn from_class(env: &Env, klass: &Class) -> Fields {
74 let (fields, truncated) = analyze_fields(env, false, &klass.fields);
75 let derives_copy = truncated.is_none() && klass.derives_copy(&env.library);
76 Fields {
77 name: klass.c_type.clone(),
78 external: klass.is_external(&env.library),
79 truncated,
80 derives_copy,
81 kind: "struct",
82 cfg_condition: get_gobject_cfg_condition(env, &klass.name),
83 fields,
84 }
85}
86
87pub fn from_union(env: &Env, union: &Union) -> Fields {
88 let (fields, truncated) = analyze_fields(env, true, &union.fields);
89 let derives_copy = truncated.is_none() && union.derives_copy(&env.library);
90 Fields {
91 name: union.c_type.as_ref().unwrap().clone(),
92 external: union.is_external(&env.library),
93 truncated,
94 derives_copy,
95 kind: "union",
96 cfg_condition: None,
97 fields,
98 }
99}
100
101fn analyze_fields(
102 env: &Env,
103 unsafe_access: bool,
104 fields: &[Field],
105) -> (Vec<FieldInfo>, Option<String>) {
106 let mut truncated = None;
107 let mut infos = Vec::with_capacity(fields.len());
108
109 let mut is_bitfield = false;
110 for field in fields {
111 if is_bitfield && field.bits.is_some() {
113 truncated = Some(format!("field {} has incomplete type", &field.name));
114 break;
115 }
116 is_bitfield = field.bits.is_some();
117
118 let typ = match field_ffi_type(env, field) {
119 e @ Err(..) => {
120 truncated = Some(e.into_string());
121 break;
122 }
123 Ok(typ) => typ,
124 };
125 let debug = !field.private && !field.is_volatile() && field.implements_debug(&env.library);
129
130 infos.push(FieldInfo {
131 name: field.name.clone(),
132 typ: typ.into_string(),
133 debug,
134 unsafe_access,
135 });
136 }
137
138 (infos, truncated)
139}
140
141fn field_ffi_type(env: &Env, field: &Field) -> Result {
142 if field.is_incomplete(&env.library) {
143 return Err(TypeError::Ignored(format!(
144 "field {} has incomplete type",
145 &field.name
146 )));
147 }
148 if let Some(ref c_type) = field.c_type {
149 ffi_type(env, field.typ, c_type)
150 } else if let Some(func) = env.library.type_(field.typ).maybe_ref_as::<Function>() {
151 let (failure, signature) = function_signature(env, func, true);
152 let signature = format!("Option<unsafe extern \"C\" fn{signature}>");
153 if failure {
154 Err(TypeError::Unimplemented(signature))
155 } else {
156 Ok(signature.into())
157 }
158 } else {
159 Err(TypeError::Ignored(format!(
160 "field {} has empty c:type",
161 &field.name
162 )))
163 }
164}
165
166fn get_gobject_cfg_condition(env: &Env, name: &str) -> Option<String> {
167 let full_name = format!("{}.{}", env.namespaces.main().name, name);
168 if let Some(obj) = env.config.objects.get(&full_name) {
169 obj.cfg_condition.clone()
170 } else {
171 None
172 }
173}