libgir/analysis/
child_properties.rs
1use log::error;
2
3use crate::{
4 analysis::{
5 bounds::{Bound, Bounds},
6 imports::Imports,
7 ref_mode::RefMode,
8 rust_type::RustType,
9 },
10 config,
11 consts::TYPE_PARAMETERS_START,
12 env::Env,
13 library::{self, ParameterDirection},
14 nameutil,
15 traits::*,
16};
17
18#[derive(Clone, Debug)]
19pub struct ChildProperty {
20 pub name: String,
21 pub prop_name: String,
22 pub getter_name: String,
23 pub typ: library::TypeId,
24 pub child_name: String,
25 pub child_type: Option<library::TypeId>,
26 pub nullable: library::Nullable,
27 pub get_out_ref_mode: RefMode,
28 pub set_in_ref_mode: RefMode,
29 pub doc_hidden: bool,
30 pub set_params: String,
31 pub bounds: String,
32 pub to_glib_extra: String,
33}
34
35pub type ChildProperties = Vec<ChildProperty>;
36
37pub fn analyze(
38 env: &Env,
39 config: Option<&config::ChildProperties>,
40 type_tid: library::TypeId,
41 imports: &mut Imports,
42) -> ChildProperties {
43 let mut properties = Vec::new();
44 if config.is_none() {
45 return properties;
46 }
47 let config = config.unwrap();
48 let child_name = config.child_name.as_ref().map_or("child", |s| s.as_str());
49 let child_type = config
50 .child_type
51 .as_ref()
52 .and_then(|name| env.library.find_type(0, name));
53 if config.child_type.is_some() && child_type.is_none() {
54 let owner_name = RustType::try_new(env, type_tid).into_string();
55 let child_type: &str = config.child_type.as_ref().unwrap();
56 error!("Bad child type `{}` for `{}`", child_type, owner_name);
57 return properties;
58 }
59
60 for prop in &config.properties {
61 if let Some(prop) =
62 analyze_property(env, prop, child_name, child_type, type_tid, config, imports)
63 {
64 properties.push(prop);
65 }
66 }
67
68 if !properties.is_empty() {
69 imports.add("glib::prelude::*");
70 if let Some(rust_type) = child_type.and_then(|typ| RustType::try_new(env, typ).ok()) {
71 imports.add_used_types(rust_type.used_types());
72 }
73 }
74
75 properties
76}
77
78fn analyze_property(
79 env: &Env,
80 prop: &config::ChildProperty,
81 child_name: &str,
82 child_type: Option<library::TypeId>,
83 type_tid: library::TypeId,
84 config: &config::ChildProperties,
85 imports: &mut Imports,
86) -> Option<ChildProperty> {
87 let name = prop.name.clone();
88 let prop_name = nameutil::signal_to_snake(&prop.name);
89 let getter_rename = config
90 .properties
91 .iter()
92 .find(|cp| cp.name == name)
93 .and_then(|cp| cp.rename_getter.clone());
94 let is_getter_renamed = getter_rename.is_some();
95 let mut getter_name = getter_rename.unwrap_or_else(|| prop_name.clone());
96
97 if let Some(typ) = env.library.find_type(0, &prop.type_name) {
98 let doc_hidden = prop.doc_hidden;
99
100 imports.add("glib::prelude::*");
101 if let Ok(rust_type) = RustType::try_new(env, typ) {
102 imports.add_used_types(rust_type.used_types());
103 }
104
105 let get_out_ref_mode = RefMode::of(env, typ, library::ParameterDirection::Return);
106 if !is_getter_renamed {
107 if let Ok(new_name) = getter_rules::try_rename_getter_suffix(
108 &getter_name,
109 typ == library::TypeId::tid_bool(),
110 ) {
111 getter_name = new_name.unwrap();
112 }
113 }
114
115 let mut set_in_ref_mode = RefMode::of(env, typ, library::ParameterDirection::In);
116 if set_in_ref_mode == RefMode::ByRefMut {
117 set_in_ref_mode = RefMode::ByRef;
118 }
119 let nullable = library::Nullable(set_in_ref_mode.is_ref());
120
121 let mut bounds_str = String::new();
122 let dir = ParameterDirection::In;
123 let set_params = if let Some(bound) = Bounds::type_for(env, typ) {
124 let r_type = RustType::builder(env, typ)
125 .ref_mode(RefMode::ByRefFake)
126 .try_build()
127 .into_string();
128
129 let _bound = Bound {
130 bound_type: bound,
131 parameter_name: TYPE_PARAMETERS_START.to_string(),
132 alias: Some(TYPE_PARAMETERS_START.to_owned()),
133 type_str: r_type,
134 callback_modified: false,
135 };
136 bounds_str.push_str("TODO");
138 format!("{prop_name}: {TYPE_PARAMETERS_START}")
139 } else {
149 format!(
150 "{}: {}",
151 prop_name,
152 RustType::builder(env, typ)
153 .direction(dir)
154 .nullable(nullable)
155 .ref_mode(set_in_ref_mode)
156 .try_build_param()
157 .into_string()
158 )
159 };
160
161 Some(ChildProperty {
162 name,
163 prop_name,
164 getter_name,
165 typ,
166 child_name: child_name.to_owned(),
167 child_type,
168 nullable,
169 get_out_ref_mode,
170 set_in_ref_mode,
171 doc_hidden,
172 set_params,
173 bounds: bounds_str,
174 to_glib_extra: String::new(),
175 })
176 } else {
177 let owner_name = RustType::try_new(env, type_tid).into_string();
178 error!(
179 "Bad type `{}` of child property `{}` for `{}`",
180 &prop.type_name, name, owner_name
181 );
182 None
183 }
184}