1use std::{
2 io::{prelude::*, Result},
3 path::Path,
4};
5
6use super::{function, general::allow_deprecated, trait_impls};
7use crate::{
8 analysis::flags::Info,
9 codegen::{
10 general::{
11 self, cfg_condition, cfg_condition_doc, cfg_condition_no_doc, cfg_condition_string,
12 cfg_deprecated, derives, doc_alias, version_condition, version_condition_doc,
13 version_condition_no_doc, version_condition_string,
14 },
15 generate_default_impl,
16 },
17 config::gobjects::GObject,
18 env::Env,
19 file_saver,
20 library::*,
21 nameutil::{bitfield_member_name, use_glib_type},
22 traits::*,
23};
24
25pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec<String>) {
26 if !env
27 .analysis
28 .flags
29 .iter()
30 .any(|f| env.config.objects[&f.full_name].status.need_generate())
31 {
32 return;
33 }
34
35 let path = root_path.join("flags.rs");
36 file_saver::save_to_file(path, env.config.make_backup, |w| {
37 general::start_comments(w, &env.config)?;
38 general::uses(w, env, &env.analysis.flags_imports, None)?;
39 writeln!(w)?;
40
41 mod_rs.push("\nmod flags;".into());
42 for flags_analysis in &env.analysis.flags {
43 let config = &env.config.objects[&flags_analysis.full_name];
44 if !config.status.need_generate() {
45 continue;
46 }
47 let flags = flags_analysis.type_(&env.library);
48
49 if let Some(cfg) = version_condition_string(env, None, flags.version, false, 0) {
50 mod_rs.push(cfg);
51 }
52 if let Some(cfg) = cfg_condition_string(config.cfg_condition.as_ref(), false, 0) {
53 mod_rs.push(cfg);
54 }
55 mod_rs.push(format!(
56 "{}{} use self::flags::{};",
57 flags
58 .deprecated_version
59 .map(|_| "#[allow(deprecated)]\n")
60 .unwrap_or(""),
61 flags_analysis.visibility.export_visibility(),
62 flags.name
63 ));
64 generate_flags(env, w, flags, config, flags_analysis)?;
65 }
66
67 Ok(())
68 });
69}
70
71fn generate_flags(
72 env: &Env,
73 w: &mut dyn Write,
74 flags: &Bitfield,
75 config: &GObject,
76 analysis: &Info,
77) -> Result<()> {
78 let sys_crate_name = env.sys_crate_import(analysis.type_id);
79 cfg_condition_no_doc(w, config.cfg_condition.as_ref(), false, 0)?;
80 version_condition_no_doc(w, env, None, flags.version, false, 0)?;
81 writeln!(w, "bitflags! {{")?;
82 cfg_condition_doc(w, config.cfg_condition.as_ref(), false, 1)?;
83 version_condition_doc(w, env, flags.version, false, 1)?;
84 cfg_deprecated(
85 w,
86 env,
87 Some(analysis.type_id),
88 flags.deprecated_version,
89 false,
90 1,
91 )?;
92 if config.must_use {
93 writeln!(w, " #[must_use]")?;
94 }
95
96 if let Some(ref d) = config.derives {
97 derives(w, d, 1)?;
98 }
99 writeln!(w, " #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]")?;
100
101 doc_alias(w, &flags.c_type, "", 1)?;
102 writeln!(
103 w,
104 " {} struct {}: u32 {{",
105 analysis.visibility, flags.name
106 )?;
107 for member in &flags.members {
108 let member_config = config.members.matched(&member.name);
109 if member.status.ignored() {
110 continue;
111 }
112
113 let name = bitfield_member_name(&member.name);
114 let deprecated_version = member_config
115 .iter()
116 .find_map(|m| m.deprecated_version)
117 .or(member.deprecated_version);
118 let version = member_config
119 .iter()
120 .find_map(|m| m.version)
121 .or(member.version);
122 let cfg_cond = member_config.iter().find_map(|m| m.cfg_condition.as_ref());
123 cfg_deprecated(w, env, Some(analysis.type_id), deprecated_version, false, 2)?;
124 version_condition(w, env, None, version, false, 2)?;
125 cfg_condition(w, cfg_cond, false, 2)?;
126 if member.c_identifier != member.name {
127 doc_alias(w, &member.c_identifier, "", 2)?;
128 }
129 writeln!(
130 w,
131 "\t\tconst {} = {}::{} as _;",
132 name, sys_crate_name, member.c_identifier,
133 )?;
134 }
135
136 writeln!(
137 w,
138 " }}
139}}"
140 )?;
141
142 let functions = analysis
143 .functions
144 .iter()
145 .filter(|f| f.status.need_generate())
146 .collect::<Vec<_>>();
147
148 if !functions.is_empty() {
149 writeln!(w)?;
150 version_condition(w, env, None, flags.version, false, 0)?;
151 cfg_condition_no_doc(w, config.cfg_condition.as_ref(), false, 0)?;
152 allow_deprecated(w, flags.deprecated_version, false, 0)?;
153 write!(w, "impl {} {{", analysis.name)?;
154 for func_analysis in functions {
155 function::generate(
156 w,
157 env,
158 Some(analysis.type_id),
159 func_analysis,
160 Some(&analysis.specials),
161 flags.version,
162 false,
163 false,
164 1,
165 )?;
166 }
167 writeln!(w, "}}")?;
168 }
169
170 trait_impls::generate(
171 w,
172 env,
173 &analysis.name,
174 &analysis.functions,
175 &analysis.specials,
176 None,
177 None,
178 config.cfg_condition.as_deref(),
179 )?;
180
181 writeln!(w)?;
182
183 generate_default_impl(
184 w,
185 env,
186 config,
187 &flags.name,
188 flags.version,
189 flags.members.iter(),
190 |member| {
191 let member_config = config.members.matched(&member.name);
192 if member.status.ignored() {
193 return None;
194 }
195 let version = member_config
196 .iter()
197 .find_map(|m| m.version)
198 .or(member.version);
199 let cfg_cond = member_config.iter().find_map(|m| m.cfg_condition.as_ref());
200 Some((version, cfg_cond, bitfield_member_name(&member.name)))
201 },
202 )?;
203
204 version_condition(w, env, None, flags.version, false, 0)?;
205 cfg_condition_no_doc(w, config.cfg_condition.as_ref(), false, 0)?;
206 allow_deprecated(w, flags.deprecated_version, false, 0)?;
207 writeln!(
208 w,
209 "#[doc(hidden)]
210impl IntoGlib for {name} {{
211 type GlibType = {sys_crate_name}::{ffi_name};
212
213 #[inline]
214 fn into_glib(self) -> {sys_crate_name}::{ffi_name} {{
215 self.bits()
216 }}
217}}
218",
219 sys_crate_name = sys_crate_name,
220 name = flags.name,
221 ffi_name = flags.c_type
222 )?;
223
224 let assert = if env.config.generate_safety_asserts {
225 "skip_assert_initialized!();\n\t\t"
226 } else {
227 ""
228 };
229
230 version_condition(w, env, None, flags.version, false, 0)?;
231 cfg_condition_no_doc(w, config.cfg_condition.as_ref(), false, 0)?;
232 allow_deprecated(w, flags.deprecated_version, false, 0)?;
233 writeln!(
234 w,
235 "#[doc(hidden)]
236impl FromGlib<{sys_crate_name}::{ffi_name}> for {name} {{
237 #[inline]
238 unsafe fn from_glib(value: {sys_crate_name}::{ffi_name}) -> Self {{
239 {assert}Self::from_bits_truncate(value)
240 }}
241}}
242",
243 sys_crate_name = sys_crate_name,
244 name = flags.name,
245 ffi_name = flags.c_type,
246 assert = assert
247 )?;
248
249 if let Some(ref get_type) = flags.glib_get_type {
250 let configured_functions = config.functions.matched("get_type");
251 let version = std::iter::once(flags.version)
252 .chain(configured_functions.iter().map(|f| f.version))
253 .max()
254 .flatten();
255
256 version_condition(w, env, None, version, false, 0)?;
257 cfg_condition_no_doc(w, config.cfg_condition.as_ref(), false, 0)?;
258 allow_deprecated(w, flags.deprecated_version, false, 0)?;
259 writeln!(
260 w,
261 "impl StaticType for {name} {{
262 #[inline]",
263 name = flags.name,
264 )?;
265 doc_alias(w, get_type, "", 1)?;
266 writeln!(
267 w,
268 " fn static_type() -> {glib_type} {{
269 unsafe {{ from_glib({sys_crate_name}::{get_type}()) }}
270 }}
271 }}",
272 sys_crate_name = sys_crate_name,
273 get_type = get_type,
274 glib_type = use_glib_type(env, "Type")
275 )?;
276 writeln!(w)?;
277
278 version_condition(w, env, None, version, false, 0)?;
279 cfg_condition_no_doc(w, config.cfg_condition.as_ref(), false, 0)?;
280 allow_deprecated(w, flags.deprecated_version, false, 0)?;
281 writeln!(
282 w,
283 "impl {has_param_spec} for {name} {{
284 type ParamSpec = {param_spec_flags};
285 type SetValue = Self;
286 type BuilderFn = fn(&str) -> {param_spec_builder}<Self>;
287
288 fn param_spec_builder() -> Self::BuilderFn {{
289 Self::ParamSpec::builder
290 }}
291}}",
292 name = flags.name,
293 has_param_spec = use_glib_type(env, "HasParamSpec"),
294 param_spec_flags = use_glib_type(env, "ParamSpecFlags"),
295 param_spec_builder = use_glib_type(env, "ParamSpecFlagsBuilder"),
296 )?;
297 writeln!(w)?;
298
299 version_condition(w, env, None, version, false, 0)?;
300 cfg_condition_no_doc(w, config.cfg_condition.as_ref(), false, 0)?;
301 allow_deprecated(w, flags.deprecated_version, false, 0)?;
302 writeln!(
303 w,
304 "impl {valuetype} for {name} {{
305 type Type = Self;
306}}",
307 name = flags.name,
308 valuetype = use_glib_type(env, "value::ValueType"),
309 )?;
310 writeln!(w)?;
311
312 version_condition(w, env, None, version, false, 0)?;
313 cfg_condition_no_doc(w, config.cfg_condition.as_ref(), false, 0)?;
314 allow_deprecated(w, flags.deprecated_version, false, 0)?;
315 writeln!(
316 w,
317 "unsafe impl<'a> {from_value_type}<'a> for {name} {{
318 type Checker = {genericwrongvaluetypechecker}<Self>;
319
320 #[inline]
321 unsafe fn from_value(value: &'a {gvalue}) -> Self {{
322 {assert}from_glib({glib}(value.to_glib_none().0))
323 }}
324}}",
325 name = flags.name,
326 glib = use_glib_type(env, "gobject_ffi::g_value_get_flags"),
327 gvalue = use_glib_type(env, "Value"),
328 genericwrongvaluetypechecker = use_glib_type(env, "value::GenericValueTypeChecker"),
329 assert = assert,
330 from_value_type = use_glib_type(env, "value::FromValue"),
331 )?;
332 writeln!(w)?;
333
334 version_condition(w, env, None, version, false, 0)?;
335 cfg_condition_no_doc(w, config.cfg_condition.as_ref(), false, 0)?;
336 allow_deprecated(w, flags.deprecated_version, false, 0)?;
337 writeln!(
338 w,
339 "impl ToValue for {name} {{
340 #[inline]
341 fn to_value(&self) -> {gvalue} {{
342 let mut value = {gvalue}::for_value_type::<Self>();
343 unsafe {{
344 {glib}(value.to_glib_none_mut().0, self.into_glib());
345 }}
346 value
347 }}
348
349 #[inline]
350 fn value_type(&self) -> {gtype} {{
351 Self::static_type()
352 }}
353}}",
354 name = flags.name,
355 glib = use_glib_type(env, "gobject_ffi::g_value_set_flags"),
356 gvalue = use_glib_type(env, "Value"),
357 gtype = use_glib_type(env, "Type"),
358 )?;
359 writeln!(w)?;
360
361 version_condition(w, env, None, version, false, 0)?;
362 cfg_condition_no_doc(w, config.cfg_condition.as_ref(), false, 0)?;
363 allow_deprecated(w, flags.deprecated_version, false, 0)?;
364 writeln!(
365 w,
366 "impl From<{name}> for {gvalue} {{
367 #[inline]
368 fn from(v: {name}) -> Self {{
369 {assert}ToValue::to_value(&v)
370 }}
371}}",
372 name = flags.name,
373 gvalue = use_glib_type(env, "Value"),
374 assert = assert,
375 )?;
376 writeln!(w)?;
377 }
378
379 Ok(())
380}