1use log::error;
2
3use super::{conversion_type::ConversionType, ref_mode::RefMode, try_from_glib::TryFromGlib};
4pub use crate::config::signals::TransformationType;
5use crate::{
6 analysis::{is_gpointer, rust_type::RustType},
7 config::{self, parameter_matchable::ParameterMatchable},
8 env::Env,
9 library, nameutil,
10};
11
12#[derive(Clone, Debug)]
13pub struct RustParameter {
14 pub name: String,
15 pub typ: library::TypeId,
16 pub direction: library::ParameterDirection,
17 pub nullable: library::Nullable,
18 pub ref_mode: RefMode,
19 pub try_from_glib: TryFromGlib,
20}
21
22#[derive(Clone, Debug)]
23pub struct CParameter {
24 pub name: String,
25 pub typ: library::TypeId,
26 pub c_type: String,
27}
28
29impl CParameter {
30 pub fn is_real_gpointer(&self, env: &Env) -> bool {
31 is_gpointer(&self.c_type) && RustType::try_new(env, self.typ).is_err()
32 }
33}
34
35#[derive(Clone, Debug)]
36pub struct Transformation {
37 pub ind_c: usize, pub ind_rust: usize, pub transformation: TransformationType,
40 pub name: String,
41 pub typ: library::TypeId,
42 pub transfer: library::Transfer,
43 pub ref_mode: RefMode,
44 pub conversion_type: ConversionType,
45}
46
47#[derive(Clone, Default, Debug)]
48pub struct Parameters {
49 pub rust_parameters: Vec<RustParameter>,
50 pub c_parameters: Vec<CParameter>,
51 pub transformations: Vec<Transformation>,
52}
53
54impl Parameters {
55 pub fn new(capacity: usize) -> Self {
56 Self {
57 rust_parameters: Vec::with_capacity(capacity),
58 c_parameters: Vec::with_capacity(capacity),
59 transformations: Vec::with_capacity(capacity),
60 }
61 }
62
63 pub fn prepare_transformation(
64 &mut self,
65 env: &Env,
66 type_tid: library::TypeId,
67 name: String,
68 c_type: String,
69 direction: library::ParameterDirection,
70 transfer: library::Transfer,
71 nullable: library::Nullable,
72 ref_mode: RefMode,
73 conversion_type: ConversionType,
74 ) -> Transformation {
75 let c_par = CParameter {
76 name: name.clone(),
77 typ: type_tid,
78 c_type,
79 };
80 let ind_c = self.c_parameters.len();
81 self.c_parameters.push(c_par);
82
83 let rust_par = RustParameter {
84 name: name.clone(),
85 typ: type_tid,
86 direction,
87 nullable,
88 ref_mode,
89 try_from_glib: TryFromGlib::from_type_defaults(env, type_tid),
90 };
91 let ind_rust = self.rust_parameters.len();
92 self.rust_parameters.push(rust_par);
93
94 Transformation {
95 ind_c,
96 ind_rust,
97 transformation: TransformationType::None,
98 name,
99 typ: type_tid,
100 transfer,
101 ref_mode,
102 conversion_type,
103 }
104 }
105
106 pub fn get(&self, ind_rust: usize) -> Option<&Transformation> {
107 self.transformations
108 .iter()
109 .find(|tr| tr.ind_rust == ind_rust)
110 }
111}
112
113pub fn analyze(
114 env: &Env,
115 signal_parameters: &[library::Parameter],
116 type_tid: library::TypeId,
117 configured_signals: &[&config::signals::Signal],
118 callback_parameters_config: Option<&config::functions::CallbackParameters>,
119) -> Parameters {
120 let mut parameters = Parameters::new(signal_parameters.len() + 1);
121
122 let owner = env.type_(type_tid);
123 let c_type = format!("{}*", owner.get_glib_name().unwrap());
124
125 let transform = parameters.prepare_transformation(
126 env,
127 type_tid,
128 "this".to_owned(),
129 c_type,
130 library::ParameterDirection::In,
131 library::Transfer::None,
132 library::Nullable(false),
133 RefMode::ByRef,
134 ConversionType::Borrow,
135 );
136 parameters.transformations.push(transform);
137
138 for par in signal_parameters {
139 let name = nameutil::mangle_keywords(&*par.name).into_owned();
140
141 let ref_mode = RefMode::without_unneeded_mut(env, par, false, false);
142
143 let nullable_override = configured_signals
144 .matched_parameters(&name)
145 .iter()
146 .find_map(|p| p.nullable)
147 .or_else(|| {
148 callback_parameters_config.and_then(|cp| {
149 cp.iter()
150 .find(|cp| cp.ident.is_match(&par.name))
151 .and_then(|c| c.nullable)
152 })
153 });
154 let nullable = nullable_override.unwrap_or(par.nullable);
155
156 let conversion_type = {
157 match env.library.type_(par.typ) {
158 library::Type::Basic(library::Basic::Utf8)
159 | library::Type::Record(..)
160 | library::Type::Interface(..)
161 | library::Type::Class(..) => ConversionType::Borrow,
162 _ => ConversionType::of(env, par.typ),
163 }
164 };
165
166 let new_name = configured_signals
167 .matched_parameters(&name)
168 .iter()
169 .find_map(|p| p.new_name.clone());
170 let transformation_override = configured_signals
171 .matched_parameters(&name)
172 .iter()
173 .find_map(|p| p.transformation);
174
175 let mut transform = parameters.prepare_transformation(
176 env,
177 par.typ,
178 name,
179 par.c_type.clone(),
180 par.direction,
181 par.transfer,
182 nullable,
183 ref_mode,
184 conversion_type,
185 );
186
187 if let Some(new_name) = new_name {
188 transform.name = new_name;
189 }
190
191 if let Some(transformation_type) = transformation_override {
192 apply_transformation_type(env, &mut parameters, &mut transform, transformation_type);
193 }
194 parameters.transformations.push(transform);
195 }
196
197 parameters
198}
199
200fn apply_transformation_type(
201 env: &Env,
202 parameters: &mut Parameters,
203 transform: &mut Transformation,
204 transformation_type: TransformationType,
205) {
206 transform.transformation = transformation_type;
207 match transformation_type {
208 TransformationType::None => (),
209 TransformationType::Borrow => {
210 if transform.conversion_type == ConversionType::Pointer {
211 transform.conversion_type = ConversionType::Borrow;
212 } else if transform.conversion_type != ConversionType::Borrow {
213 error!(
214 "Wrong conversion_type for borrow transformation {:?}",
215 transform.conversion_type
216 );
217 }
218 }
219 TransformationType::TreePath => {
220 let type_ = env.type_(transform.typ);
221 if let library::Type::Basic(library::Basic::Utf8) = type_ {
222 if let Some(type_tid) = env.library.find_type(0, "Gtk.TreePath") {
223 transform.typ = type_tid;
224 transform.conversion_type = ConversionType::Direct;
225 if let Some(rust_par) = parameters.rust_parameters.get_mut(transform.ind_rust) {
226 rust_par.typ = type_tid;
227 rust_par.ref_mode = RefMode::None;
228 }
229 } else {
230 error!("Type Gtk.TreePath not found for treepath transformation");
231 }
232 } else {
233 error!(
234 "Wrong parameter type for treepath transformation {:?}",
235 transform.typ
236 );
237 }
238 }
239 }
240}