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}