Skip to content

Commit

Permalink
Merge pull request #667 from GuillaumeGomez/user-callbacks
Browse files Browse the repository at this point in the history
Start of user callbacks generation
  • Loading branch information
EPashkin committed Jan 22, 2019
2 parents 099f2e6 + 3c365ce commit 384e41e
Show file tree
Hide file tree
Showing 18 changed files with 1,222 additions and 128 deletions.
61 changes: 57 additions & 4 deletions src/analysis/bounds.rs
Expand Up @@ -6,10 +6,10 @@ use analysis::function_parameters::{async_param_to_remove, CParameter};
use analysis::functions::{find_function, find_index_to_ignore, finish_function_name};
use analysis::imports::Imports;
use analysis::out_parameters::use_function_return_for_result;
use analysis::rust_type::{bounds_rust_type, rust_type};
use analysis::rust_type::{bounds_rust_type, rust_type, rust_type_with_scope};
use consts::TYPE_PARAMETERS_START;
use env::Env;
use library::{Class, Function, Fundamental, Nullable, ParameterDirection, Type, TypeId};
use library::{Class, Concurrency, Function, Fundamental, Nullable, ParameterDirection, Type, TypeId};
use traits::IntoString;

#[derive(Clone, Eq, Debug, PartialEq)]
Expand Down Expand Up @@ -56,6 +56,7 @@ pub struct Bound {
pub alias: char,
pub type_str: String,
pub info_for_next_type: bool,
pub callback_modified: bool,
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -97,14 +98,15 @@ impl Bound {
alias: TYPE_PARAMETERS_START,
type_str: type_str.into_string(),
info_for_next_type: false,
callback_modified: false,
})
}
}
None
}
}

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct CallbackInfo {
pub callback_type: String,
pub success_parameters: String,
Expand All @@ -119,15 +121,19 @@ impl Bounds {
func: &Function,
par: &CParameter,
async: bool,
concurrency: Concurrency,
) -> (Option<String>, Option<CallbackInfo>) {
let type_name = bounds_rust_type(env, par.typ);
let mut type_string = if async && async_param_to_remove(&par.name) {
return (None, None);
} else if type_name.is_err() {
return (None, None)
} else {
type_name.into_string()
};
let mut callback_info = None;
let mut ret = None;
let mut need_is_into_check = false;
if !par.instance_parameter && par.direction != ParameterDirection::Out {
if let Some(bound_type) = Bounds::type_for(env, par.typ, par.nullable) {
ret = Some(Bounds::get_to_glib_extra(&bound_type));
Expand All @@ -154,13 +160,55 @@ impl Bounds {
bound_name,
});
}
} else if par.c_type == "GDestroyNotify" ||
env.library.type_(par.typ).is_function() {
need_is_into_check = par.c_type != "GDestroyNotify";
if let Type::Function(_) = env.library.type_(par.typ) {
type_string = rust_type_with_scope(env, par.typ, par.scope, concurrency)
.into_string();
let bound_name = *self.unused.front().unwrap();
callback_info = Some(CallbackInfo {
callback_type: type_string.clone(),
success_parameters: String::new(),
error_parameters: String::new(),
bound_name,
});
}
}
if !self.add_parameter(&par.name, &type_string, bound_type, async) {
if par.c_type != "GDestroyNotify" &&
!self.add_parameter(&par.name, &type_string, bound_type, async) {
panic!(
"Too many type constraints for {}",
func.c_identifier.as_ref().unwrap()
)
}
if need_is_into_check {
if let Some(x) = if let Some(ref mut last) = self.used.last_mut() {
if last.bound_type.is_into() {
let mut new_one = (*last).clone();
new_one.alias = self.unused.pop_front().expect("no available bound");
new_one.type_str = last.alias.to_string();
new_one.parameter_name = last.parameter_name.clone();
// When we create a new bound for a callback which can be NULL,
// we need to generate two new bounds instead of just one. This flag
// allows us to know it so we can prevent its "generation" in the
// codegen part (we don't need the `Into<>` part in a few parts of the
// code).
new_one.callback_modified = true;

last.bound_type = BoundType::NoWrapper;
last.parameter_name = String::new();

Some(new_one)
} else {
None
}
} else {
None
} {
self.used.push(x);
}
}
}
} else if par.instance_parameter {
if let Some(bound_type) = Bounds::type_for(env, par.typ, par.nullable) {
Expand Down Expand Up @@ -195,6 +243,8 @@ impl Bounds {
Type::Interface(..) => Some(Into(Some('_'), Some(Box::new(IsA(None))))),
Type::List(_) | Type::SList(_) | Type::CArray(_) => None,
Type::Fundamental(_) if *nullable => Some(Into(None, None)),
Type::Function(_) if *nullable => Some(Into(None, None)),
Type::Function(_) if !*nullable => Some(NoWrapper),
_ if !*nullable => None,
_ => Some(Into(Some('_'), None)),
}
Expand All @@ -217,6 +267,7 @@ impl Bounds {
alias,
type_str: type_str.to_string(),
info_for_next_type: false,
callback_modified: false,
});
return true;
}
Expand Down Expand Up @@ -244,6 +295,7 @@ impl Bounds {
alias,
type_str: type_str.to_owned(),
info_for_next_type: true,
callback_modified: false,
});
alias.to_string()
} else {
Expand All @@ -259,6 +311,7 @@ impl Bounds {
alias,
type_str: type_str.to_owned(),
info_for_next_type: false,
callback_modified: false,
});
true
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/analysis/child_properties.rs
Expand Up @@ -104,7 +104,7 @@ fn analyze_property(
let r_type = bounds_rust_type(env, typ).into_string();
let mut bounds = Bounds::default();
bounds.add_parameter("P", &r_type, bound, false);
let s_bounds = function::bounds(&bounds, &[], false);
let (s_bounds, _) = function::bounds(&bounds, &[], false, false);
// Because the bounds won't necessarily be added into the final function, we
// only keep the "inner" part to make the string computation easier. So
// `<T: X>` becomes `T: X`.
Expand Down
1 change: 1 addition & 0 deletions src/analysis/conversion_type.rs
Expand Up @@ -80,6 +80,7 @@ impl ConversionType {
SList(_) => ConversionType::Pointer,
Function(super::library::Function { ref name, .. }) if name == "AsyncReadyCallback" =>
ConversionType::Direct,
Function(_) => ConversionType::Direct,
Custom(super::library::Custom {
conversion_type, ..
}) => conversion_type,
Expand Down
4 changes: 1 addition & 3 deletions src/analysis/ffi_type.rs
Expand Up @@ -178,9 +178,7 @@ fn fix_name(env: &Env, type_id: TypeId, name: &str) -> Result {
&env.namespaces[type_id.ns_id].ffi_crate_name,
name
);
if env.type_status_sys(&type_id.full_name(&env.library))
.ignored()
{
if env.type_status_sys(&type_id.full_name(&env.library)).ignored() {
Err(TypeError::Ignored(name_with_prefix))
} else {
Ok(name_with_prefix)
Expand Down
21 changes: 15 additions & 6 deletions src/analysis/function_parameters.rs
Expand Up @@ -3,7 +3,7 @@ use std::collections::HashMap;
use config;
use config::parameter_matchable::ParameterMatchable;
use env::Env;
use library::{self, TypeId};
use library::{self, TypeId, ParameterScope};
use nameutil;
use super::conversion_type::ConversionType;
use super::rust_type::rust_type;
Expand Down Expand Up @@ -32,6 +32,11 @@ pub struct CParameter {
pub transfer: library::Transfer,
pub caller_allocates: bool,
pub is_error: bool,
pub scope: ParameterScope,
/// Index of the user data parameter associated with the callback.
pub user_data_index: Option<usize>,
/// Index of the destroy notification parameter associated with the callback.
pub destroy_index: Option<usize>,

//analysis fields
pub ref_mode: RefMode,
Expand Down Expand Up @@ -152,7 +157,7 @@ pub fn analyze(
) -> Parameters {
let mut parameters = Parameters::new(function_parameters.len());

//Map: length agrument position => array name
// Map: length argument position => array name
let array_lengths: HashMap<u32, String> = function_parameters
.iter()
.filter_map(|p| p.array_length.map(|pos| (pos, p.name.clone())))
Expand Down Expand Up @@ -235,6 +240,9 @@ pub fn analyze(
nullable,
ref_mode,
is_error: par.is_error,
scope: par.scope,
user_data_index: par.closure,
destroy_index: par.destroy,
};
parameters.c_parameters.push(c_par);

Expand Down Expand Up @@ -295,19 +303,20 @@ pub fn analyze(
};
let mut transformation_type = None;
match transformation.transformation_type {
TransformationType::ToGlibDirect { ref name, .. } | TransformationType::ToGlibUnknown { ref name, .. } => {
TransformationType::ToGlibDirect { ref name, .. } |
TransformationType::ToGlibUnknown { ref name, .. } => {
if async_func && name == callback_param_name {
// Remove the conversion of callback for async functions.
transformation_type = Some(TransformationType::ToSome(name.clone()));
}
},
}
TransformationType::ToGlibPointer { ref name, .. } => {
if async_func && name == data_param_name {
// Do the conversion of user_data for async functions.
// In async functions, this argument is used to send the callback.
transformation_type = Some(TransformationType::IntoRaw(name.clone()));
}
},
}
_ => (),
}
if let Some(transformation_type) = transformation_type {
Expand Down Expand Up @@ -410,5 +419,5 @@ fn has_length(env: &Env, typ: TypeId) -> bool {
}

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

0 comments on commit 384e41e

Please sign in to comment.