Skip to content

Commit 384e41e

Browse files
authored
Merge pull request gtk-rs#667 from GuillaumeGomez/user-callbacks
Start of user callbacks generation
2 parents 099f2e6 + 3c365ce commit 384e41e

18 files changed

+1222
-128
lines changed

src/analysis/bounds.rs

+57-4
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ use analysis::function_parameters::{async_param_to_remove, CParameter};
66
use analysis::functions::{find_function, find_index_to_ignore, finish_function_name};
77
use analysis::imports::Imports;
88
use analysis::out_parameters::use_function_return_for_result;
9-
use analysis::rust_type::{bounds_rust_type, rust_type};
9+
use analysis::rust_type::{bounds_rust_type, rust_type, rust_type_with_scope};
1010
use consts::TYPE_PARAMETERS_START;
1111
use env::Env;
12-
use library::{Class, Function, Fundamental, Nullable, ParameterDirection, Type, TypeId};
12+
use library::{Class, Concurrency, Function, Fundamental, Nullable, ParameterDirection, Type, TypeId};
1313
use traits::IntoString;
1414

1515
#[derive(Clone, Eq, Debug, PartialEq)]
@@ -56,6 +56,7 @@ pub struct Bound {
5656
pub alias: char,
5757
pub type_str: String,
5858
pub info_for_next_type: bool,
59+
pub callback_modified: bool,
5960
}
6061

6162
#[derive(Clone, Debug)]
@@ -97,14 +98,15 @@ impl Bound {
9798
alias: TYPE_PARAMETERS_START,
9899
type_str: type_str.into_string(),
99100
info_for_next_type: false,
101+
callback_modified: false,
100102
})
101103
}
102104
}
103105
None
104106
}
105107
}
106108

107-
#[derive(Debug)]
109+
#[derive(Debug, Clone)]
108110
pub struct CallbackInfo {
109111
pub callback_type: String,
110112
pub success_parameters: String,
@@ -119,15 +121,19 @@ impl Bounds {
119121
func: &Function,
120122
par: &CParameter,
121123
async: bool,
124+
concurrency: Concurrency,
122125
) -> (Option<String>, Option<CallbackInfo>) {
123126
let type_name = bounds_rust_type(env, par.typ);
124127
let mut type_string = if async && async_param_to_remove(&par.name) {
125128
return (None, None);
129+
} else if type_name.is_err() {
130+
return (None, None)
126131
} else {
127132
type_name.into_string()
128133
};
129134
let mut callback_info = None;
130135
let mut ret = None;
136+
let mut need_is_into_check = false;
131137
if !par.instance_parameter && par.direction != ParameterDirection::Out {
132138
if let Some(bound_type) = Bounds::type_for(env, par.typ, par.nullable) {
133139
ret = Some(Bounds::get_to_glib_extra(&bound_type));
@@ -154,13 +160,55 @@ impl Bounds {
154160
bound_name,
155161
});
156162
}
163+
} else if par.c_type == "GDestroyNotify" ||
164+
env.library.type_(par.typ).is_function() {
165+
need_is_into_check = par.c_type != "GDestroyNotify";
166+
if let Type::Function(_) = env.library.type_(par.typ) {
167+
type_string = rust_type_with_scope(env, par.typ, par.scope, concurrency)
168+
.into_string();
169+
let bound_name = *self.unused.front().unwrap();
170+
callback_info = Some(CallbackInfo {
171+
callback_type: type_string.clone(),
172+
success_parameters: String::new(),
173+
error_parameters: String::new(),
174+
bound_name,
175+
});
176+
}
157177
}
158-
if !self.add_parameter(&par.name, &type_string, bound_type, async) {
178+
if par.c_type != "GDestroyNotify" &&
179+
!self.add_parameter(&par.name, &type_string, bound_type, async) {
159180
panic!(
160181
"Too many type constraints for {}",
161182
func.c_identifier.as_ref().unwrap()
162183
)
163184
}
185+
if need_is_into_check {
186+
if let Some(x) = if let Some(ref mut last) = self.used.last_mut() {
187+
if last.bound_type.is_into() {
188+
let mut new_one = (*last).clone();
189+
new_one.alias = self.unused.pop_front().expect("no available bound");
190+
new_one.type_str = last.alias.to_string();
191+
new_one.parameter_name = last.parameter_name.clone();
192+
// When we create a new bound for a callback which can be NULL,
193+
// we need to generate two new bounds instead of just one. This flag
194+
// allows us to know it so we can prevent its "generation" in the
195+
// codegen part (we don't need the `Into<>` part in a few parts of the
196+
// code).
197+
new_one.callback_modified = true;
198+
199+
last.bound_type = BoundType::NoWrapper;
200+
last.parameter_name = String::new();
201+
202+
Some(new_one)
203+
} else {
204+
None
205+
}
206+
} else {
207+
None
208+
} {
209+
self.used.push(x);
210+
}
211+
}
164212
}
165213
} else if par.instance_parameter {
166214
if let Some(bound_type) = Bounds::type_for(env, par.typ, par.nullable) {
@@ -195,6 +243,8 @@ impl Bounds {
195243
Type::Interface(..) => Some(Into(Some('_'), Some(Box::new(IsA(None))))),
196244
Type::List(_) | Type::SList(_) | Type::CArray(_) => None,
197245
Type::Fundamental(_) if *nullable => Some(Into(None, None)),
246+
Type::Function(_) if *nullable => Some(Into(None, None)),
247+
Type::Function(_) if !*nullable => Some(NoWrapper),
198248
_ if !*nullable => None,
199249
_ => Some(Into(Some('_'), None)),
200250
}
@@ -217,6 +267,7 @@ impl Bounds {
217267
alias,
218268
type_str: type_str.to_string(),
219269
info_for_next_type: false,
270+
callback_modified: false,
220271
});
221272
return true;
222273
}
@@ -244,6 +295,7 @@ impl Bounds {
244295
alias,
245296
type_str: type_str.to_owned(),
246297
info_for_next_type: true,
298+
callback_modified: false,
247299
});
248300
alias.to_string()
249301
} else {
@@ -259,6 +311,7 @@ impl Bounds {
259311
alias,
260312
type_str: type_str.to_owned(),
261313
info_for_next_type: false,
314+
callback_modified: false,
262315
});
263316
true
264317
} else {

src/analysis/child_properties.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ fn analyze_property(
104104
let r_type = bounds_rust_type(env, typ).into_string();
105105
let mut bounds = Bounds::default();
106106
bounds.add_parameter("P", &r_type, bound, false);
107-
let s_bounds = function::bounds(&bounds, &[], false);
107+
let (s_bounds, _) = function::bounds(&bounds, &[], false, false);
108108
// Because the bounds won't necessarily be added into the final function, we
109109
// only keep the "inner" part to make the string computation easier. So
110110
// `<T: X>` becomes `T: X`.

src/analysis/conversion_type.rs

+1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ impl ConversionType {
8080
SList(_) => ConversionType::Pointer,
8181
Function(super::library::Function { ref name, .. }) if name == "AsyncReadyCallback" =>
8282
ConversionType::Direct,
83+
Function(_) => ConversionType::Direct,
8384
Custom(super::library::Custom {
8485
conversion_type, ..
8586
}) => conversion_type,

src/analysis/ffi_type.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,7 @@ fn fix_name(env: &Env, type_id: TypeId, name: &str) -> Result {
178178
&env.namespaces[type_id.ns_id].ffi_crate_name,
179179
name
180180
);
181-
if env.type_status_sys(&type_id.full_name(&env.library))
182-
.ignored()
183-
{
181+
if env.type_status_sys(&type_id.full_name(&env.library)).ignored() {
184182
Err(TypeError::Ignored(name_with_prefix))
185183
} else {
186184
Ok(name_with_prefix)

src/analysis/function_parameters.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::collections::HashMap;
33
use config;
44
use config::parameter_matchable::ParameterMatchable;
55
use env::Env;
6-
use library::{self, TypeId};
6+
use library::{self, TypeId, ParameterScope};
77
use nameutil;
88
use super::conversion_type::ConversionType;
99
use super::rust_type::rust_type;
@@ -32,6 +32,11 @@ pub struct CParameter {
3232
pub transfer: library::Transfer,
3333
pub caller_allocates: bool,
3434
pub is_error: bool,
35+
pub scope: ParameterScope,
36+
/// Index of the user data parameter associated with the callback.
37+
pub user_data_index: Option<usize>,
38+
/// Index of the destroy notification parameter associated with the callback.
39+
pub destroy_index: Option<usize>,
3540

3641
//analysis fields
3742
pub ref_mode: RefMode,
@@ -152,7 +157,7 @@ pub fn analyze(
152157
) -> Parameters {
153158
let mut parameters = Parameters::new(function_parameters.len());
154159

155-
//Map: length agrument position => array name
160+
// Map: length argument position => array name
156161
let array_lengths: HashMap<u32, String> = function_parameters
157162
.iter()
158163
.filter_map(|p| p.array_length.map(|pos| (pos, p.name.clone())))
@@ -235,6 +240,9 @@ pub fn analyze(
235240
nullable,
236241
ref_mode,
237242
is_error: par.is_error,
243+
scope: par.scope,
244+
user_data_index: par.closure,
245+
destroy_index: par.destroy,
238246
};
239247
parameters.c_parameters.push(c_par);
240248

@@ -295,19 +303,20 @@ pub fn analyze(
295303
};
296304
let mut transformation_type = None;
297305
match transformation.transformation_type {
298-
TransformationType::ToGlibDirect { ref name, .. } | TransformationType::ToGlibUnknown { ref name, .. } => {
306+
TransformationType::ToGlibDirect { ref name, .. } |
307+
TransformationType::ToGlibUnknown { ref name, .. } => {
299308
if async_func && name == callback_param_name {
300309
// Remove the conversion of callback for async functions.
301310
transformation_type = Some(TransformationType::ToSome(name.clone()));
302311
}
303-
},
312+
}
304313
TransformationType::ToGlibPointer { ref name, .. } => {
305314
if async_func && name == data_param_name {
306315
// Do the conversion of user_data for async functions.
307316
// In async functions, this argument is used to send the callback.
308317
transformation_type = Some(TransformationType::IntoRaw(name.clone()));
309318
}
310-
},
319+
}
311320
_ => (),
312321
}
313322
if let Some(transformation_type) = transformation_type {
@@ -410,5 +419,5 @@ fn has_length(env: &Env, typ: TypeId) -> bool {
410419
}
411420

412421
pub fn async_param_to_remove(name: &str) -> bool {
413-
name == "user_data"
422+
name == "user_data" || name.ends_with("data") // FIXME: use async indexes instead
414423
}

0 commit comments

Comments
 (0)