libgir/analysis/
class_builder.rs
1use std::collections::HashSet;
2
3use crate::{
4 analysis::{
5 bounds::Bounds,
6 imports::Imports,
7 properties::{get_property_ref_modes, Property},
8 rust_type::RustType,
9 },
10 config::{self, GObject},
11 env::Env,
12 library,
13 traits::*,
14};
15
16pub fn analyze(
17 env: &Env,
18 props: &[library::Property],
19 type_tid: library::TypeId,
20 obj: &GObject,
21 imports: &mut Imports,
22) -> Vec<(Vec<Property>, library::TypeId)> {
23 if !obj.generate_builder {
24 return Vec::new();
25 }
26
27 let mut names = HashSet::<String>::new();
28 let mut builder_properties = vec![(
29 analyze_properties(env, type_tid, props, obj, imports, &mut names),
30 type_tid,
31 )];
32
33 for &super_tid in env.class_hierarchy.supertypes(type_tid) {
34 let type_ = env.type_(super_tid);
35
36 let super_properties = match type_ {
37 library::Type::Class(class) => &class.properties,
38 library::Type::Interface(iface) => &iface.properties,
39 _ => continue,
40 };
41 let super_obj =
42 if let Some(super_obj) = env.config.objects.get(&super_tid.full_name(&env.library)) {
43 super_obj
44 } else {
45 continue;
46 };
47
48 let new_builder_properties = (
49 analyze_properties(
50 env,
51 super_tid,
52 super_properties,
53 super_obj,
54 imports,
55 &mut names,
56 ),
57 super_tid,
58 );
59 builder_properties.push(new_builder_properties);
60 }
61
62 builder_properties
63}
64
65fn analyze_properties(
66 env: &Env,
67 type_tid: library::TypeId,
68 props: &[library::Property],
69 obj: &GObject,
70 imports: &mut Imports,
71 names: &mut HashSet<String>,
72) -> Vec<Property> {
73 let mut builder_properties = Vec::new();
74
75 for prop in props {
76 if names.contains(&prop.name) {
77 continue;
78 }
79 let configured_properties = obj.properties.matched(&prop.name);
80 if !configured_properties
81 .iter()
82 .all(|f| f.status.need_generate())
83 {
84 continue;
85 }
86
87 if env.is_totally_deprecated(Some(type_tid.ns_id), prop.deprecated_version) {
88 continue;
89 }
90 let builder = analyze_property(env, prop, &configured_properties, imports);
91 if let Some(builder) = builder {
92 builder_properties.push(builder);
93 names.insert(prop.name.clone());
94 }
95 }
96
97 builder_properties
98}
99
100fn analyze_property(
101 env: &Env,
102 prop: &library::Property,
103 configured_properties: &[&config::properties::Property],
104 imports: &mut Imports,
105) -> Option<Property> {
106 let prop_version = configured_properties
107 .iter()
108 .filter_map(|f| f.version)
109 .min()
110 .or(prop.version);
111
112 let for_builder = prop.construct_only || prop.construct || prop.writable;
113 if !for_builder {
114 return None;
115 }
116 let imports = &mut imports.with_defaults(prop_version, &None);
117 let rust_type_res = RustType::try_new(env, prop.typ);
118 if let Ok(ref rust_type) = rust_type_res {
119 if !rust_type.as_str().contains("GString") {
120 imports.add_used_types(rust_type.used_types());
121 }
122 }
123
124 let (get_out_ref_mode, set_in_ref_mode, nullable) = get_property_ref_modes(env, prop);
125
126 let mut bounds = Bounds::default();
127 if let Some(bound) = Bounds::type_for(env, prop.typ) {
128 imports.add("glib::prelude::*");
129 bounds.add_parameter(&prop.name, &rust_type_res.into_string(), bound, false);
130 }
131
132 Some(Property {
133 name: prop.name.clone(),
134 var_name: String::new(),
135 typ: prop.typ,
136 is_get: false,
137 func_name: String::new(),
138 func_name_alias: None,
139 nullable,
140 get_out_ref_mode,
141 set_in_ref_mode,
142 set_bound: None,
143 bounds,
144 version: prop_version,
145 deprecated_version: prop.deprecated_version,
146 })
147}