From 7bbfb29ce66d9fc63c8c2798a5ac0ecac9d122f8 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 15 May 2018 22:09:39 +0200 Subject: [PATCH 001/122] add subclass work mode --- src/config/work_mode.rs | 2 ++ src/main.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/config/work_mode.rs b/src/config/work_mode.rs index 11d4d4a79..d09919ac6 100644 --- a/src/config/work_mode.rs +++ b/src/config/work_mode.rs @@ -5,6 +5,7 @@ pub enum WorkMode { Normal, // generate widgets etc. Sys, // generate -sys with ffi Doc, // generate documentation file + Subclass, // generate subclassing traits DisplayNotBound, // Show not bound types } @@ -21,6 +22,7 @@ impl FromStr for WorkMode { "normal" => Ok(WorkMode::Normal), "sys" => Ok(WorkMode::Sys), "doc" => Ok(WorkMode::Doc), + "subclass" => Ok(WorkMode::Subclass), "not_bound" => Ok(WorkMode::DisplayNotBound), _ => Err("Wrong work mode".into()), } diff --git a/src/main.rs b/src/main.rs index 04dd6b2b6..0b31e45d1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,7 +19,7 @@ Options: -h, --help Show this message. -c CONFIG Config file path (default: Gir.toml) -d GIRSPATH Directory for girs - -m MODE Work mode: doc, normal, sys or not_bound + -m MODE Work mode: doc, normal, sys, subclass or not_bound -o PATH Target path --doc-target-path PATH Doc target path -b, --make-backup Make backup before generating From 58eb331f69b616d7abf131c0a3843f5998402a50 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 15 May 2018 22:11:47 +0200 Subject: [PATCH 002/122] add stub subclass codegen module --- src/codegen/subclass/mod.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/codegen/subclass/mod.rs diff --git a/src/codegen/subclass/mod.rs b/src/codegen/subclass/mod.rs new file mode 100644 index 000000000..e69de29bb From 628f9ad7684979f1d3d081a2a4abb870472343fa Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 15 May 2018 22:14:35 +0200 Subject: [PATCH 003/122] subclass generate function --- src/codegen/mod.rs | 2 ++ src/codegen/subclass/mod.rs | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 6941389f5..6060602ec 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -24,6 +24,7 @@ mod records; mod return_value; mod signal; mod signal_body; +mod subclass; mod sys; mod trait_impls; mod trampoline; @@ -37,6 +38,7 @@ pub fn generate(env: &Env) { WorkMode::Normal => normal_generate(env), WorkMode::Sys => sys::generate(env), WorkMode::Doc => doc::generate(env), + WorkMode::Subclass => subclass::generate(env), WorkMode::DisplayNotBound => {} } } diff --git a/src/codegen/subclass/mod.rs b/src/codegen/subclass/mod.rs index e69de29bb..ff67b9eb5 100644 --- a/src/codegen/subclass/mod.rs +++ b/src/codegen/subclass/mod.rs @@ -0,0 +1,18 @@ +use env::Env; + +mod build; +mod cargo_toml; +pub mod ffi_type; +mod fields; +mod functions; +mod lib_; +mod statics; +mod tests; + +pub fn generate(env: &Env) { + // generate_single_version_file(env); + // lib_::generate(env); + // build::generate(env); + // let crate_name = cargo_toml::generate(env); + // tests::generate(env, &crate_name); +} From 800895c3812325b1698e0866750cee98acdca2b4 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 16 May 2018 07:51:21 +0200 Subject: [PATCH 004/122] add subclass target path --- src/codegen/subclass/mod.rs | 2 ++ src/config/config.rs | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/codegen/subclass/mod.rs b/src/codegen/subclass/mod.rs index ff67b9eb5..a601979f7 100644 --- a/src/codegen/subclass/mod.rs +++ b/src/codegen/subclass/mod.rs @@ -10,6 +10,8 @@ mod statics; mod tests; pub fn generate(env: &Env) { + info!("Generating subclasssing traits {:?}", env.config.subclass_target_path); + // generate_single_version_file(env); // lib_::generate(env); // build::generate(env); diff --git a/src/config/config.rs b/src/config/config.rs index 38970fe2d..d1b2eb24b 100644 --- a/src/config/config.rs +++ b/src/config/config.rs @@ -24,6 +24,7 @@ pub struct Config { /// Path where files generated in normal and sys mode pub auto_path: PathBuf, pub doc_target_path: PathBuf, + pub subclass_target_path: PathBuf, pub external_libraries: Vec, pub objects: gobjects::GObjects, pub min_cfg_version: Version, @@ -44,6 +45,7 @@ impl Config { library_version: S, target_path: S, doc_target_path: S, + subclass_target_path: S, make_backup: B, show_statistics: B) -> Result @@ -124,6 +126,17 @@ impl Config { Some(p) => config_dir.join(p), }; + let subclass_target_path: PathBuf = match subclass_target_path.into() { + Some("") | None => { + let path = try!(toml.lookup_str( + "options.subclass_target_path", + "No subclass target path specified", + )); + config_dir.join(path) + } + Some(a) => a.into(), + }; + let concurrency = match toml.lookup("options.concurrency") { Some(v) => try!(try!(v.as_result_str("options.concurrency")).parse()), None => Default::default(), @@ -179,6 +192,7 @@ impl Config { target_path, auto_path, doc_target_path, + subclass_target_path, external_libraries, objects, min_cfg_version, From 4ef29155f6343540cbcfc7da34f42c7e4c90b465 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 16 May 2018 07:54:54 +0200 Subject: [PATCH 005/122] add subclass target path cli param --- src/codegen/subclass/mod.rs | 8 -------- src/main.rs | 4 +++- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/codegen/subclass/mod.rs b/src/codegen/subclass/mod.rs index a601979f7..818f363ed 100644 --- a/src/codegen/subclass/mod.rs +++ b/src/codegen/subclass/mod.rs @@ -1,13 +1,5 @@ use env::Env; -mod build; -mod cargo_toml; -pub mod ffi_type; -mod fields; -mod functions; -mod lib_; -mod statics; -mod tests; pub fn generate(env: &Env) { info!("Generating subclasssing traits {:?}", env.config.subclass_target_path); diff --git a/src/main.rs b/src/main.rs index 0b31e45d1..9789fcc54 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,6 +22,7 @@ Options: -m MODE Work mode: doc, normal, sys, subclass or not_bound -o PATH Target path --doc-target-path PATH Doc target path + --subclass-target-path PATH Subclass target path -b, --make-backup Make backup before generating -s, --stats Show statistics "; @@ -44,7 +45,8 @@ fn build_config() -> Result { Config::new(args.get_str("-c"), work_mode, args.get_str("-d"), args.get_str(""), args.get_str(""), args.get_str("-o"), - args.get_str("--doc-target-path"), args.get_bool("-b"), args.get_bool("-s")) + args.get_str("--doc-target-path"), args.get_str("--subclass-target-path"), + args.get_bool("-b"), args.get_bool("-s")) } #[cfg_attr(test, allow(dead_code))] From 5967ad31736550ae376b36175808a38266a41c48 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 16 May 2018 20:45:17 +0200 Subject: [PATCH 006/122] read subclass trait names from config --- src/analysis/object.rs | 21 +++++++++++++++++++++ src/codegen/subclass/mod.rs | 11 ++++++++++- src/codegen/subclass/object.rs | 26 ++++++++++++++++++++++++++ src/codegen/subclass/objects.rs | 29 +++++++++++++++++++++++++++++ src/config/gobjects.rs | 24 ++++++++++++++++++++++++ 5 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 src/codegen/subclass/object.rs create mode 100644 src/codegen/subclass/objects.rs diff --git a/src/analysis/object.rs b/src/analysis/object.rs index ef2884a1e..175adee05 100644 --- a/src/analysis/object.rs +++ b/src/analysis/object.rs @@ -21,6 +21,9 @@ pub struct Info { pub supertypes: Vec, pub generate_trait: bool, pub trait_name: String, + pub subclass_impl_trait_name: String, + pub subclass_base_trait_name: String, + pub subclass_class_trait_name: String, pub has_constructors: bool, pub has_methods: bool, pub has_functions: bool, @@ -102,6 +105,21 @@ pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option .cloned() .unwrap_or_else(|| format!("{}Ext", name)); + let subclass_impl_trait_name = obj.subclass_impl_trait_name + .as_ref() + .cloned() + .unwrap_or_else(|| format!("{}Impl", name)); + + let subclass_base_trait_name = obj.subclass_base_trait_name + .as_ref() + .cloned() + .unwrap_or_else(|| format!("{}Base", name)); + + let subclass_class_trait_name = obj.subclass_class_trait_name + .as_ref() + .cloned() + .unwrap_or_else(|| format!("{}ClassExt", name)); + // Sanity check the user's configuration. It's unlikely that not generating // a trait is wanted if there are subtypes in this very crate if !generate_trait && has_known_subtypes(env, class_tid) { @@ -239,6 +257,9 @@ pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option supertypes, generate_trait, trait_name, + subclass_impl_trait_name, + subclass_base_trait_name, + subclass_class_trait_name, has_constructors, has_methods, has_functions, diff --git a/src/codegen/subclass/mod.rs b/src/codegen/subclass/mod.rs index 818f363ed..224b8e77f 100644 --- a/src/codegen/subclass/mod.rs +++ b/src/codegen/subclass/mod.rs @@ -1,10 +1,19 @@ use env::Env; +mod objects; +mod object; +use codegen::generate_single_version_file; pub fn generate(env: &Env) { info!("Generating subclasssing traits {:?}", env.config.subclass_target_path); - // generate_single_version_file(env); + let root_path = env.config.subclass_target_path.join("src").join("auto"); + let mut mod_rs: Vec = Vec::new(); + let mut traits: Vec = Vec::new(); + + generate_single_version_file(env); + objects::generate(env, &root_path, &mut mod_rs, &mut traits); + // lib_::generate(env); // build::generate(env); // let crate_name = cargo_toml::generate(env); diff --git a/src/codegen/subclass/object.rs b/src/codegen/subclass/object.rs new file mode 100644 index 000000000..851da12e5 --- /dev/null +++ b/src/codegen/subclass/object.rs @@ -0,0 +1,26 @@ +use std::io::{Result, Write}; + +use analysis; +use library; +use env::Env; +use codegen::child_properties; +use codegen::function; +use codegen::general; +use codegen::properties; +use codegen::signal; +use codegen::trait_impls; +use codegen::trampoline; + + + +pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> { + try!(general::start_comments(w, &env.config)); + try!(general::uses(w, env, &analysis.imports)); + // TODO: insert gobject-subclass uses + // TODO: insert gobject-subclass uses of parent types + + println!("{:?}, {:?}", analysis.subclass_impl_trait_name, analysis.subclass_base_trait_name); + + + Ok(()) +} diff --git a/src/codegen/subclass/objects.rs b/src/codegen/subclass/objects.rs new file mode 100644 index 000000000..20f8c1105 --- /dev/null +++ b/src/codegen/subclass/objects.rs @@ -0,0 +1,29 @@ +use std::path::Path; + +use env::Env; +use file_saver::*; +use nameutil::*; + +pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec, traits: &mut Vec) { + info!("Generate objects"); + for class_analysis in env.analysis.objects.values() { + let obj = &env.config.objects[&class_analysis.full_name]; + if !obj.status.need_generate() { + continue; + } + + let mod_name = obj.module_name.clone().unwrap_or_else(|| { + module_name(split_namespace_name(&class_analysis.full_name).1) + }); + + let mut path = root_path.join(&mod_name); + path.set_extension("rs"); + info!("Generating file {:?}", path); + + save_to_file(path, env.config.make_backup, |ref mut w| { + super::object::generate(w, env, class_analysis) + }); + + // super::object::generate_reexports(env, class_analysis, &mod_name, mod_rs, traits); + } +} diff --git a/src/config/gobjects.rs b/src/config/gobjects.rs index 957df6901..c5288e1ef 100644 --- a/src/config/gobjects.rs +++ b/src/config/gobjects.rs @@ -72,6 +72,9 @@ pub struct GObject { pub type_id: Option, pub generate_trait: bool, pub trait_name: Option, + pub subclass_impl_trait_name: Option, + pub subclass_base_trait_name: Option, + pub subclass_class_trait_name: Option, pub child_properties: Option, pub concurrency: library::Concurrency, pub ref_mode: Option, @@ -99,6 +102,9 @@ impl Default for GObject { type_id: None, generate_trait: true, trait_name: None, + subclass_impl_trait_name: None, + subclass_base_trait_name: None, + subclass_class_trait_name: None, child_properties: None, concurrency: Default::default(), ref_mode: None, @@ -185,6 +191,9 @@ fn parse_object( "child_type", "trait", "trait_name", + "subclass_impl_trait_name", + "subclass_base_trait_name", + "subclass_class_trait_name", "cfg_condition", "must_use", "use_boxed_functions", @@ -242,6 +251,18 @@ fn parse_object( .lookup("trait_name") .and_then(|v| v.as_str()) .map(|s| s.to_owned()); + let subclass_impl_trait_name = toml_object + .lookup("subclass_impl_trait_name") + .and_then(|v| v.as_str()) + .map(|s| s.to_owned()); + let subclass_base_trait_name = toml_object + .lookup("subclass_base_trait_name") + .and_then(|v| v.as_str()) + .map(|s| s.to_owned()); + let subclass_class_trait_name = toml_object + .lookup("subclass_class_trait_name") + .and_then(|v| v.as_str()) + .map(|s| s.to_owned()); let concurrency = toml_object .lookup("concurrency") .and_then(|v| v.as_str()) @@ -296,6 +317,9 @@ fn parse_object( type_id: None, generate_trait, trait_name, + subclass_impl_trait_name, + subclass_base_trait_name, + subclass_class_trait_name, child_properties, concurrency, ref_mode, From dda175a8abc32a1a64f15d8a67f76bb9840bfb7b Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 16 May 2018 21:15:55 +0200 Subject: [PATCH 007/122] reuse target path instead of defining a new one --- src/codegen/subclass/mod.rs | 4 ++-- src/config/config.rs | 14 -------------- src/main.rs | 3 +-- 3 files changed, 3 insertions(+), 18 deletions(-) diff --git a/src/codegen/subclass/mod.rs b/src/codegen/subclass/mod.rs index 224b8e77f..5b0082d21 100644 --- a/src/codegen/subclass/mod.rs +++ b/src/codegen/subclass/mod.rs @@ -5,9 +5,9 @@ mod object; use codegen::generate_single_version_file; pub fn generate(env: &Env) { - info!("Generating subclasssing traits {:?}", env.config.subclass_target_path); + info!("Generating subclasssing traits {:?}", env.config.target_path); - let root_path = env.config.subclass_target_path.join("src").join("auto"); + let root_path = env.config.target_path.join("src").join("auto"); let mut mod_rs: Vec = Vec::new(); let mut traits: Vec = Vec::new(); diff --git a/src/config/config.rs b/src/config/config.rs index d1b2eb24b..38970fe2d 100644 --- a/src/config/config.rs +++ b/src/config/config.rs @@ -24,7 +24,6 @@ pub struct Config { /// Path where files generated in normal and sys mode pub auto_path: PathBuf, pub doc_target_path: PathBuf, - pub subclass_target_path: PathBuf, pub external_libraries: Vec, pub objects: gobjects::GObjects, pub min_cfg_version: Version, @@ -45,7 +44,6 @@ impl Config { library_version: S, target_path: S, doc_target_path: S, - subclass_target_path: S, make_backup: B, show_statistics: B) -> Result @@ -126,17 +124,6 @@ impl Config { Some(p) => config_dir.join(p), }; - let subclass_target_path: PathBuf = match subclass_target_path.into() { - Some("") | None => { - let path = try!(toml.lookup_str( - "options.subclass_target_path", - "No subclass target path specified", - )); - config_dir.join(path) - } - Some(a) => a.into(), - }; - let concurrency = match toml.lookup("options.concurrency") { Some(v) => try!(try!(v.as_result_str("options.concurrency")).parse()), None => Default::default(), @@ -192,7 +179,6 @@ impl Config { target_path, auto_path, doc_target_path, - subclass_target_path, external_libraries, objects, min_cfg_version, diff --git a/src/main.rs b/src/main.rs index 9789fcc54..b95abc792 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,7 +22,6 @@ Options: -m MODE Work mode: doc, normal, sys, subclass or not_bound -o PATH Target path --doc-target-path PATH Doc target path - --subclass-target-path PATH Subclass target path -b, --make-backup Make backup before generating -s, --stats Show statistics "; @@ -45,7 +44,7 @@ fn build_config() -> Result { Config::new(args.get_str("-c"), work_mode, args.get_str("-d"), args.get_str(""), args.get_str(""), args.get_str("-o"), - args.get_str("--doc-target-path"), args.get_str("--subclass-target-path"), + args.get_str("--doc-target-path"), args.get_bool("-b"), args.get_bool("-s")) } From b6ce8e2ed707e262212b20352dbe3e334ca4766b Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 16 May 2018 21:39:27 +0200 Subject: [PATCH 008/122] wip: some initial trait generation --- src/codegen/subclass/mod.rs | 1 + src/codegen/subclass/object.rs | 18 +++++++++++++++ src/codegen/subclass/traits.rs | 40 ++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 src/codegen/subclass/traits.rs diff --git a/src/codegen/subclass/mod.rs b/src/codegen/subclass/mod.rs index 5b0082d21..7ac53a72e 100644 --- a/src/codegen/subclass/mod.rs +++ b/src/codegen/subclass/mod.rs @@ -1,6 +1,7 @@ use env::Env; mod objects; mod object; +mod traits; use codegen::generate_single_version_file; diff --git a/src/codegen/subclass/object.rs b/src/codegen/subclass/object.rs index 851da12e5..cbe4a88ce 100644 --- a/src/codegen/subclass/object.rs +++ b/src/codegen/subclass/object.rs @@ -12,6 +12,19 @@ use codegen::trait_impls; use codegen::trampoline; +use codegen::subclass::traits; + + +pub struct SubclassInfo{ + +} + +impl SubclassInfo{ + pub fn new(env: &Env, analysis: &analysis::object::Info) -> Self{ + Self{} + } +} + pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> { try!(general::start_comments(w, &env.config)); @@ -21,6 +34,11 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> println!("{:?}, {:?}", analysis.subclass_impl_trait_name, analysis.subclass_base_trait_name); + let subclass_info = SubclassInfo::new(env, analysis); + + traits::generate_impl(w, env, analysis, &subclass_info); + + Ok(()) } diff --git a/src/codegen/subclass/traits.rs b/src/codegen/subclass/traits.rs new file mode 100644 index 000000000..7b4f7272a --- /dev/null +++ b/src/codegen/subclass/traits.rs @@ -0,0 +1,40 @@ +use std::io::{Result, Write}; + +use library; +use analysis; +use analysis::bounds::Bounds; +use analysis::functions::Visibility; +use analysis::namespaces; +use chunk::{ffi_function_todo, Chunk}; +use env::Env; + +use writer::primitives::tabs; +use writer::ToCode; + +use std::result::Result as StdResult; +use std::fmt; + +use codegen::subclass::object::SubclassInfo; + +// pub fn generate_impl --> +// pub trait ApplicationImpl: ObjectImpl + AnyImpl + 'static { + +pub fn generate_impl(w: &mut Write, + env: &Env, + analysis: &analysis::object::Info, + subclass_info: &SubclassInfo + ) -> Result<()> { + + try!(writeln!( + w, + "pub trait {}: ObjectImpl + AnyImpl + 'static {{", + analysis.subclass_impl_trait_name, + analysis.subclass_base_trait_name + )); + + Ok(()) +} + + +// pub fn generate_base --> +// pub unsafe trait ApplicationBase: IsA + ObjectType { From d8a84d3dca8afe0e739ce95ca69b0e7657df6891 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 16 May 2018 21:48:35 +0200 Subject: [PATCH 009/122] wip: some more initial trait generation --- src/codegen/subclass/object.rs | 2 ++ src/codegen/subclass/traits.rs | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/codegen/subclass/object.rs b/src/codegen/subclass/object.rs index cbe4a88ce..ca3b70e86 100644 --- a/src/codegen/subclass/object.rs +++ b/src/codegen/subclass/object.rs @@ -39,6 +39,8 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> traits::generate_impl(w, env, analysis, &subclass_info); + traits::generate_base(w, env, analysis, &subclass_info); + Ok(()) } diff --git a/src/codegen/subclass/traits.rs b/src/codegen/subclass/traits.rs index 7b4f7272a..ccb54bd71 100644 --- a/src/codegen/subclass/traits.rs +++ b/src/codegen/subclass/traits.rs @@ -25,6 +25,8 @@ pub fn generate_impl(w: &mut Write, subclass_info: &SubclassInfo ) -> Result<()> { + // start impl trait + try!(writeln!(w)); try!(writeln!( w, "pub trait {}: ObjectImpl + AnyImpl + 'static {{", @@ -32,9 +34,41 @@ pub fn generate_impl(w: &mut Write, analysis.subclass_base_trait_name )); + //end impl trait + try!(writeln!(w)); + try!(writeln!( + w, + "}}" + )); + Ok(()) } +pub fn generate_base(w: &mut Write, + env: &Env, + analysis: &analysis::object::Info, + subclass_info: &SubclassInfo + ) -> Result<()> { + + // start base trait + try!(writeln!(w)); + try!(writeln!( + w, + "pub unsafe trait {}: IsA<{}> + ObjectType {{", + analysis.subclass_base_trait_name, + analysis.subclass_impl_trait_name //TODO: user-facing parent + )); + + //end base trait + try!(writeln!(w)); + try!(writeln!( + w, + "}}" + )); + + Ok(()) +} + // pub fn generate_base --> // pub unsafe trait ApplicationBase: IsA + ObjectType { From d7e1a9a30c4e5c0dfbdddef7c178da191a3d29dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 10 Nov 2017 16:10:00 +0100 Subject: [PATCH 010/122] Generate new variant of the glib_wrapper!() macro that distinguishes parent classes and interfaces --- src/analysis/general.rs | 2 +- src/analysis/object.rs | 6 ++++ src/codegen/general.rs | 74 +++++++++++++++++++++++++++++++++++------ src/codegen/object.rs | 19 ++++++++++- 4 files changed, 88 insertions(+), 13 deletions(-) diff --git a/src/analysis/general.rs b/src/analysis/general.rs index e0fcbde59..f0a65de1c 100644 --- a/src/analysis/general.rs +++ b/src/analysis/general.rs @@ -1,7 +1,7 @@ use config::gobjects::*; use library::*; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct StatusedTypeId { pub type_id: TypeId, pub name: String, diff --git a/src/analysis/object.rs b/src/analysis/object.rs index 175adee05..d9218e319 100644 --- a/src/analysis/object.rs +++ b/src/analysis/object.rs @@ -14,7 +14,9 @@ use traits::*; #[derive(Debug, Default)] pub struct Info { pub base: InfoBase, + pub is_interface: bool, pub c_type: String, + pub class_type: Option, pub c_class_type: Option, pub rust_class_type: Option, pub get_type: String, @@ -250,7 +252,9 @@ pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option let info = Info { base, + is_interface: false, c_type: klass.c_type.clone(), + class_type: klass.type_struct.clone(), c_class_type: klass.c_class_type.clone(), rust_class_type, get_type: klass.glib_get_type.clone(), @@ -372,7 +376,9 @@ pub fn interface(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option Result<()> { pub fn define_object_type( w: &mut Write, env: &Env, + is_interface: bool, type_name: &str, glib_name: &str, + class_name: &Option<&str>, glib_class_name: &Option<&str>, rust_class_name: &Option<&str>, glib_func_name: &str, parents: &[StatusedTypeId], + ifaces: &[StatusedTypeId], ) -> Result<()> { let mut external_parents = false; let parents: Vec = parents @@ -97,10 +100,25 @@ pub fn define_object_type( ) }) .collect(); + let ifaces: Vec = ifaces + .iter() + .filter(|p| !p.status.ignored()) + .map(|p| if p.type_id.ns_id == namespaces::MAIN { + p.name.clone() + } else { + external_parents = true; + format!( + "{krate}::{name} => {krate}_ffi::{ffi_name}", + krate = env.namespaces[p.type_id.ns_id].crate_name, + name = p.name, + ffi_name = env.library.type_(p.type_id).get_glib_name().unwrap() + ) + }) + .collect(); let (separator, class_name) = { - if let Some(s) = *glib_class_name { - (", ".to_string(), format!("ffi::{}", s)) + if let (Some(name), Some(ffi_name)) = (*class_name, *glib_class_name) { + (", ".to_string(), format!("{}, ffi::{}", name, ffi_name)) } else { ("".to_string(), "".to_string()) } @@ -111,13 +129,16 @@ pub fn define_object_type( Some(ref rust_class_name) => format!(", {}", rust_class_name), }; + let kind_name = if is_interface { "Interface" } else { "Object" }; + try!(writeln!(w)); try!(writeln!(w, "glib_wrapper! {{")); - if parents.is_empty() { + if parents.is_empty() && ifaces.is_empty() { try!(writeln!( w, - "\tpub struct {}(Object);", + "\tpub struct {}({});", type_name, + kind_name, glib_name, separator, class_name, @@ -126,28 +147,59 @@ pub fn define_object_type( } else if external_parents { try!(writeln!( w, - "\tpub struct {}(Object): [", + "\tpub struct {}({}):", type_name, + kind_name, glib_name, separator, class_name, rust_class_name )); - for parent in parents { - try!(writeln!(w, "\t\t{},", parent)); + + if !parents.is_empty() { + try!(writeln!(w, "\t\tparents=[")); + try!(writeln!(w, "{}", parents.iter().map(|s| format!("\t\t\t{}", s)).collect::>().join(",\n"))); + + if !ifaces.is_empty() { + try!(writeln!(w, "\t\t],")); + } else { + try!(writeln!(w, "\t\t];")); + } + } + + if !ifaces.is_empty() { + try!(writeln!(w, "\t\tifaces=[")); + try!(writeln!(w, "{}", ifaces.iter().map(|s| format!("\t\t\t{}", s)).collect::>().join(",\n"))); + try!(writeln!(w, "\t\t];")); } - try!(writeln!(w, "\t];")); } else { try!(writeln!( w, - "\tpub struct {}(Object): {};", + "\tpub struct {}({}):", type_name, + kind_name, glib_name, separator, class_name, - rust_class_name, - parents.join(", ") + rust_class_name )); + + if !parents.is_empty() { + try!(writeln!(w, "\t\tparents=[")); + try!(writeln!(w, "{}", parents.iter().map(|s| format!("\t\t\t{}", s)).collect::>().join(",\n"))); + + if !ifaces.is_empty() { + try!(writeln!(w, "\t\t],")); + } else { + try!(writeln!(w, "\t\t];")); + } + } + + if !ifaces.is_empty() { + try!(writeln!(w, "\t\tifaces=[")); + try!(writeln!(w, "{}", ifaces.iter().map(|s| format!("\t\t\t{}", s)).collect::>().join(",\n"))); + try!(writeln!(w, "\t\t];")); + } } try!(writeln!(w)); try!(writeln!(w, "\tmatch fn {{")); diff --git a/src/codegen/object.rs b/src/codegen/object.rs index 45a8f61b1..9eb3a408e 100644 --- a/src/codegen/object.rs +++ b/src/codegen/object.rs @@ -20,15 +20,32 @@ pub fn generate( try!(general::start_comments(w, &env.config)); try!(general::uses(w, env, &analysis.imports)); + let parents = analysis.supertypes.iter().filter(|t| { + match *env.library.type_(t.type_id) { + library::Type::Class(..) => true, + _ => false, + } + }).cloned().collect::>(); + + let interfaces = analysis.supertypes.iter().filter(|t| { + match *env.library.type_(t.type_id) { + library::Type::Interface(..) => true, + _ => false, + } + }).cloned().collect::>(); + try!(general::define_object_type( w, env, + analysis.is_interface, &analysis.name, &analysis.c_type, + &analysis.class_type.as_ref().map(|s| &s[..]), &analysis.c_class_type.as_ref().map(|s| &s[..]), &analysis.rust_class_type.as_ref().map(|s| &s[..]), &analysis.get_type, - &analysis.supertypes, + parents.as_ref(), + interfaces.as_ref(), )); if need_generate_inherent(analysis) { From 05a8da1737159a723ae6c0ac800e6fcff4aaae6d Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 17 May 2018 00:39:42 +0200 Subject: [PATCH 011/122] try to figure out how to get the class vfuncs --- src/codegen/subclass/functions.rs | 31 +++++++++++++++++++++++ src/codegen/subclass/mod.rs | 1 + src/codegen/subclass/object.rs | 20 ++++++++++++++- src/codegen/subclass/objects.rs | 2 +- src/codegen/subclass/traits.rs | 41 ++++++++++++++++++++++++++++--- 5 files changed, 90 insertions(+), 5 deletions(-) create mode 100644 src/codegen/subclass/functions.rs diff --git a/src/codegen/subclass/functions.rs b/src/codegen/subclass/functions.rs new file mode 100644 index 000000000..3cc719571 --- /dev/null +++ b/src/codegen/subclass/functions.rs @@ -0,0 +1,31 @@ +use std::io::{Result, Write}; + +use library; +use analysis; +use analysis::bounds::Bounds; +use analysis::functions::Visibility; +use analysis::namespaces; +use chunk::{ffi_function_todo, Chunk}; +use env::Env; + +use writer::primitives::tabs; +use writer::ToCode; +use nameutil; + +use std::result::Result as StdResult; +use std::fmt; + +use codegen::subclass::object::SubclassInfo; + + +pub fn generate_impl(w: &mut Write, + env: &Env, + analysis: &analysis::functions::Info, + subclass_info: &SubclassInfo, + indent: usize + ) -> Result<()> { + + info!("{:?}", analysis.name); + + Ok(()) +} diff --git a/src/codegen/subclass/mod.rs b/src/codegen/subclass/mod.rs index 7ac53a72e..002281687 100644 --- a/src/codegen/subclass/mod.rs +++ b/src/codegen/subclass/mod.rs @@ -2,6 +2,7 @@ use env::Env; mod objects; mod object; mod traits; +mod functions; use codegen::generate_single_version_file; diff --git a/src/codegen/subclass/object.rs b/src/codegen/subclass/object.rs index ca3b70e86..8ceaa52fc 100644 --- a/src/codegen/subclass/object.rs +++ b/src/codegen/subclass/object.rs @@ -32,15 +32,33 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> // TODO: insert gobject-subclass uses // TODO: insert gobject-subclass uses of parent types - println!("{:?}, {:?}", analysis.subclass_impl_trait_name, analysis.subclass_base_trait_name); + info!("{:?}, {:?}", analysis.c_type, analysis.c_type); let subclass_info = SubclassInfo::new(env, analysis); traits::generate_impl(w, env, analysis, &subclass_info); + traits::generate_impl_ext(w, env, analysis, &subclass_info); + + generate_any_impl(w, env, analysis, &subclass_info); + traits::generate_base(w, env, analysis, &subclass_info); Ok(()) } + + +fn generate_any_impl(w: &mut Write, _env: &Env, analysis: &analysis::object::Info, _subclass_info: &SubclassInfo) -> Result<()> +{ + try!(writeln!(w)); + try!(writeln!( + w, + "any_impl!({}, {});", + analysis.subclass_base_trait_name, + analysis.subclass_impl_trait_name + )); + + Ok(()) +} diff --git a/src/codegen/subclass/objects.rs b/src/codegen/subclass/objects.rs index 20f8c1105..a5801c50e 100644 --- a/src/codegen/subclass/objects.rs +++ b/src/codegen/subclass/objects.rs @@ -18,7 +18,7 @@ pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec, traits: & let mut path = root_path.join(&mod_name); path.set_extension("rs"); - info!("Generating file {:?}", path); + info!("Generating file {:?}", mod_name); save_to_file(path, env.config.make_backup, |ref mut w| { super::object::generate(w, env, class_analysis) diff --git a/src/codegen/subclass/traits.rs b/src/codegen/subclass/traits.rs index ccb54bd71..9a1b88a7c 100644 --- a/src/codegen/subclass/traits.rs +++ b/src/codegen/subclass/traits.rs @@ -10,11 +10,13 @@ use env::Env; use writer::primitives::tabs; use writer::ToCode; +use nameutil; use std::result::Result as StdResult; use std::fmt; use codegen::subclass::object::SubclassInfo; +use codegen::subclass::functions; // pub fn generate_impl --> // pub trait ApplicationImpl: ObjectImpl + AnyImpl + 'static { @@ -25,15 +27,45 @@ pub fn generate_impl(w: &mut Write, subclass_info: &SubclassInfo ) -> Result<()> { + info!("Generating {:?}", analysis.subclass_impl_trait_name); + // start impl trait try!(writeln!(w)); try!(writeln!( w, - "pub trait {}: ObjectImpl + AnyImpl + 'static {{", + "pub trait {}: ObjectImpl + AnyImpl + 'static {{", //TODO: use real superclasses chain analysis.subclass_impl_trait_name, analysis.subclass_base_trait_name )); + for func_analysis in &analysis.functions{ + try!(functions::generate_impl(w, env, func_analysis, subclass_info, 1)); + } + + //end impl trait + try!(writeln!(w)); + try!(writeln!( + w, + "}}" + )); + + Ok(()) +} + +pub fn generate_impl_ext(w: &mut Write, + env: &Env, + analysis: &analysis::object::Info, + subclass_info: &SubclassInfo + ) -> Result<()> { + + // start impl trait + try!(writeln!(w)); + try!(writeln!( + w, + "pub trait {}Ext {{}}", + analysis.subclass_impl_trait_name + )); + //end impl trait try!(writeln!(w)); try!(writeln!( @@ -51,13 +83,16 @@ pub fn generate_base(w: &mut Write, subclass_info: &SubclassInfo ) -> Result<()> { + let normal_crate_name = nameutil::crate_name(&env.config.library_name); + // start base trait try!(writeln!(w)); try!(writeln!( w, - "pub unsafe trait {}: IsA<{}> + ObjectType {{", + "pub unsafe trait {}: IsA<{}::{}> + ObjectType {{", analysis.subclass_base_trait_name, - analysis.subclass_impl_trait_name //TODO: user-facing parent + normal_crate_name, + analysis.name )); //end base trait From 2eba7fa358e6c5d7ceb6164eda4187a3112d23f7 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 17 May 2018 01:18:47 +0200 Subject: [PATCH 012/122] remove subclass_class_trait_name in favour of class_type --- src/analysis/object.rs | 7 ------- src/config/gobjects.rs | 8 -------- 2 files changed, 15 deletions(-) diff --git a/src/analysis/object.rs b/src/analysis/object.rs index d9218e319..9b1b09055 100644 --- a/src/analysis/object.rs +++ b/src/analysis/object.rs @@ -25,7 +25,6 @@ pub struct Info { pub trait_name: String, pub subclass_impl_trait_name: String, pub subclass_base_trait_name: String, - pub subclass_class_trait_name: String, pub has_constructors: bool, pub has_methods: bool, pub has_functions: bool, @@ -117,11 +116,6 @@ pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option .cloned() .unwrap_or_else(|| format!("{}Base", name)); - let subclass_class_trait_name = obj.subclass_class_trait_name - .as_ref() - .cloned() - .unwrap_or_else(|| format!("{}ClassExt", name)); - // Sanity check the user's configuration. It's unlikely that not generating // a trait is wanted if there are subtypes in this very crate if !generate_trait && has_known_subtypes(env, class_tid) { @@ -263,7 +257,6 @@ pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option trait_name, subclass_impl_trait_name, subclass_base_trait_name, - subclass_class_trait_name, has_constructors, has_methods, has_functions, diff --git a/src/config/gobjects.rs b/src/config/gobjects.rs index c5288e1ef..41ac7881b 100644 --- a/src/config/gobjects.rs +++ b/src/config/gobjects.rs @@ -74,7 +74,6 @@ pub struct GObject { pub trait_name: Option, pub subclass_impl_trait_name: Option, pub subclass_base_trait_name: Option, - pub subclass_class_trait_name: Option, pub child_properties: Option, pub concurrency: library::Concurrency, pub ref_mode: Option, @@ -104,7 +103,6 @@ impl Default for GObject { trait_name: None, subclass_impl_trait_name: None, subclass_base_trait_name: None, - subclass_class_trait_name: None, child_properties: None, concurrency: Default::default(), ref_mode: None, @@ -193,7 +191,6 @@ fn parse_object( "trait_name", "subclass_impl_trait_name", "subclass_base_trait_name", - "subclass_class_trait_name", "cfg_condition", "must_use", "use_boxed_functions", @@ -259,10 +256,6 @@ fn parse_object( .lookup("subclass_base_trait_name") .and_then(|v| v.as_str()) .map(|s| s.to_owned()); - let subclass_class_trait_name = toml_object - .lookup("subclass_class_trait_name") - .and_then(|v| v.as_str()) - .map(|s| s.to_owned()); let concurrency = toml_object .lookup("concurrency") .and_then(|v| v.as_str()) @@ -319,7 +312,6 @@ fn parse_object( trait_name, subclass_impl_trait_name, subclass_base_trait_name, - subclass_class_trait_name, child_properties, concurrency, ref_mode, From b65b3ed7678d81ddd5d876b1ffe10dce17a6ca32 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 17 May 2018 08:55:59 +0200 Subject: [PATCH 013/122] try to get to class vfuncs --- .../{traits.rs => class_trait_impls.rs} | 12 ++++- src/codegen/subclass/mod.rs | 10 +++- src/codegen/subclass/object.rs | 8 ++-- src/codegen/subclass/objects.rs | 46 ++++++++++++++++++- src/codegen/sys/mod.rs | 2 +- 5 files changed, 70 insertions(+), 8 deletions(-) rename src/codegen/subclass/{traits.rs => class_trait_impls.rs} (86%) diff --git a/src/codegen/subclass/traits.rs b/src/codegen/subclass/class_trait_impls.rs similarity index 86% rename from src/codegen/subclass/traits.rs rename to src/codegen/subclass/class_trait_impls.rs index 9a1b88a7c..1746a9385 100644 --- a/src/codegen/subclass/traits.rs +++ b/src/codegen/subclass/class_trait_impls.rs @@ -27,7 +27,17 @@ pub fn generate_impl(w: &mut Write, subclass_info: &SubclassInfo ) -> Result<()> { - info!("Generating {:?}", analysis.subclass_impl_trait_name); + + if analysis.class_type.is_some(){ + // let name = format!("{}.{}", env.config., &analysis.class_type.as_ref().unwrap()); + // let klass = env.config.objects.vmap(|x| x.name).collect(); + let ns: Vec = env.library.namespaces.iter().map(|ref x| x.name.clone()).collect(); + info!("Generating {:?} {:?}", ns, env.analysis.objects.keys()); + + + } + + // start impl trait try!(writeln!(w)); diff --git a/src/codegen/subclass/mod.rs b/src/codegen/subclass/mod.rs index 002281687..1df70f695 100644 --- a/src/codegen/subclass/mod.rs +++ b/src/codegen/subclass/mod.rs @@ -1,9 +1,16 @@ use env::Env; +use std::io::{Result, Write}; + +use library::*; + mod objects; mod object; -mod traits; +mod class_trait_impls; mod functions; +use traits::*; + + use codegen::generate_single_version_file; pub fn generate(env: &Env) { @@ -14,6 +21,7 @@ pub fn generate(env: &Env) { let mut traits: Vec = Vec::new(); generate_single_version_file(env); + objects::generate(env, &root_path, &mut mod_rs, &mut traits); // lib_::generate(env); diff --git a/src/codegen/subclass/object.rs b/src/codegen/subclass/object.rs index 8ceaa52fc..b6e9c8827 100644 --- a/src/codegen/subclass/object.rs +++ b/src/codegen/subclass/object.rs @@ -12,7 +12,7 @@ use codegen::trait_impls; use codegen::trampoline; -use codegen::subclass::traits; +use codegen::subclass::class_trait_impls; pub struct SubclassInfo{ @@ -36,14 +36,14 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> let subclass_info = SubclassInfo::new(env, analysis); - traits::generate_impl(w, env, analysis, &subclass_info); + class_trait_impls::generate_impl(w, env, analysis, &subclass_info); - traits::generate_impl_ext(w, env, analysis, &subclass_info); + class_trait_impls::generate_impl_ext(w, env, analysis, &subclass_info); generate_any_impl(w, env, analysis, &subclass_info); - traits::generate_base(w, env, analysis, &subclass_info); + class_trait_impls::generate_base(w, env, analysis, &subclass_info); Ok(()) diff --git a/src/codegen/subclass/objects.rs b/src/codegen/subclass/objects.rs index a5801c50e..20401631b 100644 --- a/src/codegen/subclass/objects.rs +++ b/src/codegen/subclass/objects.rs @@ -1,9 +1,14 @@ use std::path::Path; +use std::io::{Result, Write}; use env::Env; use file_saver::*; use nameutil::*; +use library::*; +use traits::*; + + pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec, traits: &mut Vec) { info!("Generate objects"); for class_analysis in env.analysis.objects.values() { @@ -20,10 +25,49 @@ pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec, traits: & path.set_extension("rs"); info!("Generating file {:?}", mod_name); + + let ns = env.library.namespace(MAIN_NAMESPACE); + let classes = prepare(ns); + save_to_file(path, env.config.make_backup, |ref mut w| { - super::object::generate(w, env, class_analysis) + super::object::generate(w, env, class_analysis); + generate_classes_traits(w, env, &classes) + }); // super::object::generate_reexports(env, class_analysis, &mod_name, mod_rs, traits); } } + + + +fn prepare(ns: &Namespace) -> Vec<&T> +where + Type: MaybeRef, +{ + let mut vec: Vec<&T> = Vec::with_capacity(ns.types.len()); + for typ in ns.types.iter().filter_map(|t| t.as_ref()) { + if let Some(x) = typ.maybe_ref() { + vec.push(x); + } + } + vec.sort(); + vec +} + + +fn generate_classes_traits(w: &mut Write, env: &Env, classes: &[&Class]) -> Result<()> { + if !classes.is_empty() { + try!(writeln!(w, "// Classes")); + } + for class in classes { + let full_name = format!("{}.{}", env.namespaces.main().name, class.name); + info!("{:?}", full_name); + // if !env.type_status_sys(&full_name).need_generate() { + // continue; + // } + // let fields = fields::from_class(env, class); + // try!(generate_from_fields(w, &fields)); + } + Ok(()) +} diff --git a/src/codegen/sys/mod.rs b/src/codegen/sys/mod.rs index a3793481e..bfdedf3c6 100644 --- a/src/codegen/sys/mod.rs +++ b/src/codegen/sys/mod.rs @@ -4,7 +4,7 @@ use env::Env; mod build; mod cargo_toml; pub mod ffi_type; -mod fields; +pub mod fields; mod functions; mod lib_; mod statics; From dac5a41c75f40de6c2665d720c1fbf8828b88443 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 17 May 2018 22:13:45 +0200 Subject: [PATCH 014/122] can we read vfuncs exactly the same as signals? --- src/library.rs | 2 ++ src/parser.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/library.rs b/src/library.rs index d4cf8ac9d..92c9b0895 100644 --- a/src/library.rs +++ b/src/library.rs @@ -445,6 +445,7 @@ pub struct Interface { pub c_class_type: Option, pub glib_get_type: String, pub functions: Vec, + pub virtual_methods: Vec, pub signals: Vec, pub properties: Vec, pub prerequisites: Vec, @@ -462,6 +463,7 @@ pub struct Class { pub glib_get_type: String, pub fields: Vec, pub functions: Vec, + pub virtual_methods: Vec, pub signals: Vec, pub properties: Vec, pub parent: Option, diff --git a/src/parser.rs b/src/parser.rs index 11ce9ca79..0dd033ada 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -124,6 +124,7 @@ impl Library { let mut properties = Vec::new(); let mut impls = Vec::new(); let mut fields = Vec::new(); + let mut vfns = Vec::new(); let mut doc = None; let mut union_count = 1; @@ -153,7 +154,11 @@ impl Library { fields.push(f); }) } - "virtual-method" => parser.ignore_element(), + "virtual-method" => { + self.read_signal(parser, ns_id, elem).map(|v| { + vfns.push(v) + }) + } "doc" => parser.text().map(|t| doc = Some(t)), "union" => { self.read_union(parser, ns_id, elem, Some(class_name), Some(c_type)).map(|mut u| { @@ -194,6 +199,7 @@ impl Library { glib_get_type: get_type.into(), fields, functions: fns, + virtual_methods: vfns, signals, properties, parent, @@ -498,6 +504,51 @@ impl Library { } } + fn read_vfunc(&mut self, parser: &mut XmlParser, ns_id: u16, + elem: &Element) -> Result { + let field_name = elem.attr_required("name")?; + let private = elem.attr_bool("private", false); + let bits = elem.attr("bits").and_then(|s| s.parse().ok()); + + let mut typ = None; + let mut doc = None; + + parser.elements(|parser, elem| match elem.name() { + "type" | "array" => { + if typ.is_some() { + return Err(parser.fail("Too many elements")); + } + self.read_type(parser, ns_id, elem).map(|t| { + typ = Some(t); + }) + } + "callback" => { + if typ.is_some() { + return Err(parser.fail("Too many elements")); + } + self.read_function(parser, ns_id, elem.name(), elem).map(|f| { + typ = Some((Type::function(self, f), None, None)); + }) + } + "doc" => parser.text().map(|t| doc = Some(t)), + _ => Err(parser.unexpected_element(elem)), + })?; + + if let Some((tid, c_type, array_length)) = typ { + Ok(Field { + name: field_name.into(), + typ: tid, + c_type, + private, + bits, + array_length, + doc, + }) + } else { + Err(parser.fail("Missing element")) + } + } + fn read_named_callback( &mut self, parser: &mut XmlParser, @@ -527,6 +578,7 @@ impl Library { let mut signals = Vec::new(); let mut properties = Vec::new(); let mut prereqs = Vec::new(); + let mut vfns = Vec::new(); let mut doc = None; parser.elements(|parser, elem| match elem.name() { @@ -551,7 +603,11 @@ impl Library { }) } "doc" => parser.text().map(|t| doc = Some(t)), - "virtual-method" => parser.ignore_element(), + "virtual-method" => { + self.read_signal(parser, ns_id, elem).map(|v| { + vfns.push(v) + }) + }, _ => Err(parser.unexpected_element(elem)), })?; @@ -562,6 +618,7 @@ impl Library { c_class_type: None, // this will be resolved during postprocessing glib_get_type: get_type.into(), functions: fns, + virtual_methods: vfns, signals, properties, prerequisites: prereqs, @@ -899,6 +956,7 @@ impl Library { } self.read_function(parser, ns_id, kind_str, elem).and_then(|f| { if f.c_identifier.is_none() { + info!("read func: {:?}", f); return Err(parser.fail_with_position("Missing c:identifier attribute", elem.position())); } From 320b42b2d5a37ef97c552f0a7408f6939a0d40e2 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 18 May 2018 08:42:37 +0200 Subject: [PATCH 015/122] supply class info to generators --- .../{class_trait_impls.rs => class_impl.rs} | 52 ++- src/codegen/subclass/class_impls.rs | 81 ++++ src/codegen/subclass/function.rs | 405 ++++++++++++++++++ src/codegen/subclass/functions.rs | 2 +- src/codegen/subclass/mod.rs | 11 +- src/codegen/subclass/object.rs | 128 +++--- src/codegen/subclass/objects.rs | 73 ---- 7 files changed, 604 insertions(+), 148 deletions(-) rename src/codegen/subclass/{class_trait_impls.rs => class_impl.rs} (68%) create mode 100644 src/codegen/subclass/class_impls.rs create mode 100644 src/codegen/subclass/function.rs delete mode 100644 src/codegen/subclass/objects.rs diff --git a/src/codegen/subclass/class_trait_impls.rs b/src/codegen/subclass/class_impl.rs similarity index 68% rename from src/codegen/subclass/class_trait_impls.rs rename to src/codegen/subclass/class_impl.rs index 1746a9385..eb04c6ebf 100644 --- a/src/codegen/subclass/class_trait_impls.rs +++ b/src/codegen/subclass/class_impl.rs @@ -15,14 +15,46 @@ use nameutil; use std::result::Result as StdResult; use std::fmt; -use codegen::subclass::object::SubclassInfo; +use library::*; +use codegen::subclass::class_impls::SubclassInfo; use codegen::subclass::functions; +use codegen::general; +use codegen::sys::fields; + + +pub fn generate(w: &mut Write, env: &Env, class: &Class, analysis: &analysis::object::Info) -> Result<()> +{ + try!(general::start_comments(w, &env.config)); + try!(general::uses(w, env, &analysis.imports)); + // TODO: insert gobject-subclass uses + // TODO: insert gobject-subclass uses of parent types + + info!("{:?}, {:?}", analysis.c_type, analysis.c_type); + + let subclass_info = SubclassInfo::new(env, class, analysis); + + generate_impl(w, env, class, analysis, &subclass_info); + + generate_impl_ext(w, env, class, analysis, &subclass_info); + + generate_any_impl(w, env, class, analysis, &subclass_info); + + + generate_base(w, env, class, analysis, &subclass_info); + + + Ok(()) +} // pub fn generate_impl --> // pub trait ApplicationImpl: ObjectImpl + AnyImpl + 'static { + + + pub fn generate_impl(w: &mut Write, env: &Env, + class: &Class, analysis: &analysis::object::Info, subclass_info: &SubclassInfo ) -> Result<()> { @@ -34,7 +66,7 @@ pub fn generate_impl(w: &mut Write, let ns: Vec = env.library.namespaces.iter().map(|ref x| x.name.clone()).collect(); info!("Generating {:?} {:?}", ns, env.analysis.objects.keys()); - + // let f = fields::from_class() } @@ -64,6 +96,7 @@ pub fn generate_impl(w: &mut Write, pub fn generate_impl_ext(w: &mut Write, env: &Env, + class: &Class, analysis: &analysis::object::Info, subclass_info: &SubclassInfo ) -> Result<()> { @@ -89,6 +122,7 @@ pub fn generate_impl_ext(w: &mut Write, pub fn generate_base(w: &mut Write, env: &Env, + class: &Class, analysis: &analysis::object::Info, subclass_info: &SubclassInfo ) -> Result<()> { @@ -117,3 +151,17 @@ pub fn generate_base(w: &mut Write, // pub fn generate_base --> // pub unsafe trait ApplicationBase: IsA + ObjectType { + + +fn generate_any_impl(w: &mut Write, _env: &Env, class: &Class, analysis: &analysis::object::Info, _subclass_info: &SubclassInfo) -> Result<()> +{ + try!(writeln!(w)); + try!(writeln!( + w, + "any_impl!({}, {});", + analysis.subclass_base_trait_name, + analysis.subclass_impl_trait_name + )); + + Ok(()) +} diff --git a/src/codegen/subclass/class_impls.rs b/src/codegen/subclass/class_impls.rs new file mode 100644 index 000000000..2cbd9a209 --- /dev/null +++ b/src/codegen/subclass/class_impls.rs @@ -0,0 +1,81 @@ +use std::path::Path; +use std::io::{Result, Write}; + +use env::Env; +use file_saver::*; +use nameutil::*; + +use analysis; +use library::*; +use traits::*; +use codegen::subclass::class_impl; + +pub struct SubclassInfo{ + +} + +impl SubclassInfo{ + pub fn new(env: &Env, class: &Class, analysis: &analysis::object::Info) -> Self{ + Self{} + } +} + + + +pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec, traits: &mut Vec) { + info!("Generate class traits"); + + let ns = env.library.namespace(MAIN_NAMESPACE); + let classes = prepare(ns); + + + for object_analysis in env.analysis.objects.values() { + let obj = &env.config.objects[&object_analysis.full_name]; + if !obj.status.need_generate() { + continue; + } + + let mod_name = obj.module_name.clone().unwrap_or_else(|| { + module_name(split_namespace_name(&object_analysis.full_name).1) + }); + + let mut path = root_path.join(&mod_name); + path.set_extension("rs"); + info!("Generating file {:?}", mod_name); + + let class_idx = classes.binary_search_by(|c: &&Class| { + (*c).c_type.cmp(&object_analysis.c_type) + }); + + match class_idx{ + Ok(idx) => { + let class = classes[class_idx.unwrap()]; + + save_to_file(path, env.config.make_backup, |ref mut w| { + class_impl::generate(w, env, class, object_analysis) + }); + }, + Err(_) => { + warn!("No class definition found for {:?}. Skipping...", object_analysis.full_name) + } + } + + // super::object::generate_reexports(env, class_analysis, &mod_name, mod_rs, traits); + } +} + + +// TODO: remove duplicate with sys generator +fn prepare(ns: &Namespace) -> Vec<&T> +where + Type: MaybeRef, +{ + let mut vec: Vec<&T> = Vec::with_capacity(ns.types.len()); + for typ in ns.types.iter().filter_map(|t| t.as_ref()) { + if let Some(x) = typ.maybe_ref() { + vec.push(x); + } + } + vec.sort(); + vec +} diff --git a/src/codegen/subclass/function.rs b/src/codegen/subclass/function.rs new file mode 100644 index 000000000..76a09fe2a --- /dev/null +++ b/src/codegen/subclass/function.rs @@ -0,0 +1,405 @@ +use std::io::{Result, Write}; + +use library; +use analysis; +use analysis::bounds::Bounds; +use analysis::functions::Visibility; +use analysis::namespaces; +use chunk::{ffi_function_todo, Chunk}; +use env::Env; +use super::function_body_chunk; +use super::general::{ + cfg_condition, cfg_deprecated, doc_hidden, not_version_condition, version_condition, +}; +use super::parameter::ToParameter; +use super::return_value::{out_parameters_as_return, ToReturnValue}; +use writer::primitives::tabs; +use writer::ToCode; + +use std::result::Result as StdResult; +use std::fmt; + +pub fn generate( + w: &mut Write, + env: &Env, + analysis: &analysis::functions::Info, + in_trait: bool, + only_declaration: bool, + indent: usize, +) -> Result<()> { + if analysis.is_async_finish(env) { + return Ok(()); + } + + let mut commented = false; + let mut comment_prefix = ""; + let mut pub_prefix = if in_trait { "" } else { "pub " }; + + match analysis.visibility { + Visibility::Public => {} + Visibility::Comment => { + commented = true; + comment_prefix = "//"; + } + Visibility::Private => if in_trait { + warn!( + "Generating trait method for private function {}", + analysis.glib_name + ); + } else { + pub_prefix = ""; + }, + Visibility::Hidden => return Ok(()), + } + let declaration = declaration(env, analysis); + let suffix = if only_declaration { ";" } else { " {" }; + + try!(writeln!(w)); + if !in_trait || only_declaration { + try!(cfg_deprecated(w, env, analysis.deprecated_version, commented, indent)); + } + try!(cfg_condition(w, &analysis.cfg_condition, commented, indent)); + try!(version_condition( + w, + env, + analysis.version, + commented, + indent, + )); + try!(not_version_condition( + w, + analysis.not_version, + commented, + indent, + )); + try!(doc_hidden(w, analysis.doc_hidden, comment_prefix, indent)); + try!(writeln!( + w, + "{}{}{}{}{}", + tabs(indent), + comment_prefix, + pub_prefix, + declaration, + suffix + )); + + if !only_declaration { + let body = body_chunk(env, analysis).to_code(env); + for s in body { + try!(writeln!(w, "{}{}", tabs(indent), s)); + } + } + + if analysis.async_future.is_some() { + let declaration = declaration_futures(env, analysis); + let suffix = if only_declaration { ";" } else { " {" }; + + try!(writeln!(w)); + if !in_trait || only_declaration { + try!(cfg_deprecated(w, env, analysis.deprecated_version, commented, indent)); + } + + try!(writeln!(w, "{}{}#[cfg(feature = \"futures\")]", tabs(indent), comment_prefix)); + try!(cfg_condition(w, &analysis.cfg_condition, commented, indent)); + try!(version_condition( + w, + env, + analysis.version, + commented, + indent, + )); + try!(not_version_condition( + w, + analysis.not_version, + commented, + indent, + )); + try!(doc_hidden(w, analysis.doc_hidden, comment_prefix, indent)); + try!(writeln!( + w, + "{}{}{}{}{}", + tabs(indent), + comment_prefix, + pub_prefix, + declaration, + suffix + )); + + if !only_declaration { + let body = body_chunk_futures(env, analysis).unwrap(); + for s in body.lines() { + if !s.is_empty() { + try!(writeln!(w, "{}{}{}", tabs(indent+1), comment_prefix, s)); + } else { + try!(writeln!(w)); + } + } + try!(writeln!(w, "{}{}}}", tabs(indent), comment_prefix)); + } + } + + Ok(()) +} + +pub fn declaration(env: &Env, analysis: &analysis::functions::Info) -> String { + let outs_as_return = !analysis.outs.is_empty(); + let return_str = if outs_as_return { + out_parameters_as_return(env, analysis) + } else if analysis.ret.bool_return_is_error.is_some() { + if env.namespaces.glib_ns_id == namespaces::MAIN { + " -> Result<(), error::BoolError>".into() + } else { + " -> Result<(), glib::error::BoolError>".into() + } + } else { + analysis.ret.to_return_value(env) + }; + let mut param_str = String::with_capacity(100); + + let bounds = bounds(&analysis.bounds, &[], false); + + for (pos, par) in analysis.parameters.rust_parameters.iter().enumerate() { + if pos > 0 { + param_str.push_str(", ") + } + let c_par = &analysis.parameters.c_parameters[par.ind_c]; + let s = c_par.to_parameter(env, &analysis.bounds); + param_str.push_str(&s); + } + + format!( + "fn {}{}({}){}", + analysis.name, + bounds, + param_str, + return_str + ) +} + +pub fn declaration_futures(env: &Env, analysis: &analysis::functions::Info) -> String { + let async_future = analysis.async_future.as_ref().unwrap(); + + let return_str = if async_future.is_method { + format!(" -> Box_>", async_future.success_parameters, async_future.error_parameters) + } else { + format!(" -> Box_>", async_future.success_parameters, async_future.error_parameters) + }; + + let mut param_str = String::with_capacity(100); + + let mut skipped = 0; + let mut skipped_bounds = vec![]; + for (pos, par) in analysis.parameters.rust_parameters.iter().enumerate() { + let c_par = &analysis.parameters.c_parameters[par.ind_c]; + + if c_par.name == "callback" || c_par.name == "cancellable" { + skipped += 1; + if let Some((t, _)) = analysis.bounds.get_parameter_alias_info(&c_par.name) { + skipped_bounds.push(t); + } + continue; + } + + if pos - skipped > 0 { + param_str.push_str(", ") + } + + let s = c_par.to_parameter(env, &analysis.bounds); + param_str.push_str(&s); + } + + let bounds = bounds(&analysis.bounds, skipped_bounds.as_ref(), true); + + format!( + "fn {}{}({}){}", + async_future.name, + bounds, + param_str, + return_str + ) +} + +pub fn bounds(bounds: &Bounds, skip: &[char], async: bool) -> String { + use analysis::bounds::BoundType::*; + if bounds.is_empty() { + return String::new(); + } + + let skip_lifetimes = bounds.iter() + .filter(|bound| skip.contains(&bound.alias)) + .filter_map(|bound| match bound.bound_type { + IsA(Some(lifetime)) | + AsRef(Some(lifetime)) | + Into(Some(lifetime), _) => Some(lifetime), + _ => None, + }) + .collect::>(); + + let strs: Vec = bounds + .iter_lifetimes() + .filter(|s| !skip_lifetimes.contains(s)) + .map(|s| format!("'{}", s)) + .chain(bounds.iter().filter(|bound| !skip.contains(&bound.alias)).map(|bound| match bound.bound_type { + NoWrapper => { + format!("{}: {}", bound.alias, bound.type_str) + } + IsA(Some(lifetime)) => { + format!("{}: IsA<{}> + {}", bound.alias, bound.type_str, if async { "Clone + 'static".into() } else { format!("'{}", lifetime) }) + } + IsA(None) => format!("{}: IsA<{}>{}", bound.alias, bound.type_str, if async { " + Clone + 'static" } else { "" }), + // This case should normally never happened + AsRef(Some(lifetime)) => { + format!("{}: AsRef<{}> + '{}", bound.alias, bound.type_str, lifetime) + } + AsRef(None) => format!("{}: AsRef<{}>", bound.alias, bound.type_str), + Into(Some(l), _) => { + format!("{}: Into>", bound.alias, l, bound.type_str) + } + Into(None, _) => format!("{}: Into>", bound.alias, bound.type_str), + })) + .collect(); + + if strs.is_empty() { + String::new() + } else { + format!("<{}>", strs.join(", ")) + } +} + +pub fn body_chunk(env: &Env, analysis: &analysis::functions::Info) -> Chunk { + if analysis.visibility == Visibility::Comment { + return ffi_function_todo(&analysis.glib_name); + } + + let outs_as_return = !analysis.outs.is_empty(); + + let mut builder = function_body_chunk::Builder::new(); + builder + .glib_name(&analysis.glib_name) + .assertion(analysis.assertion) + .ret(&analysis.ret) + .transformations(&analysis.parameters.transformations) + .outs_mode(analysis.outs.mode); + + if analysis.async { + if let Some(ref trampoline) = analysis.trampoline { + builder.async_trampoline(trampoline); + } else { + warn!("Async function {} has no associated _finish function", analysis.name); + } + } + + for par in &analysis.parameters.c_parameters { + if outs_as_return && analysis.outs.iter().any(|p| p.name == par.name) { + builder.out_parameter(env, par); + } else { + builder.parameter(); + } + } + + builder.generate(env) +} + +pub fn body_chunk_futures(env: &Env, analysis: &analysis::functions::Info) -> StdResult { + use std::fmt::Write; + use analysis::bounds::BoundType; + use analysis::ref_mode::RefMode; + + let async_future = analysis.async_future.as_ref().unwrap(); + + let mut body = String::new(); + + if env.config.library_name != "Gio" { + try!(writeln!(body, "use gio::GioFuture;")); + } else { + try!(writeln!(body, "use GioFuture;")); + } + try!(writeln!(body, "use send_cell::SendCell;")); + try!(writeln!(body)); + + let skip = if async_future.is_method { 1 } else { 0 }; + + // Skip the instance parameter + for par in analysis.parameters.rust_parameters.iter().skip(skip) { + if par.name == "cancellable" || par.name == "callback" { + continue; + } + + let c_par = &analysis.parameters.c_parameters[par.ind_c]; + + let bounds = analysis.bounds.get_parameter_alias_info(&par.name); + let is_into = if let Some((_, BoundType::Into(..))) = bounds { true } else { false }; + + let type_ = env.type_(par.typ); + let is_str = if let library::Type::Fundamental(library::Fundamental::Utf8) = *type_ { true } else { false }; + + if is_into { + try!(writeln!(body, "let {} = {}.into();", par.name, par.name)); + if is_str || c_par.nullable.0 { + try!(writeln!(body, "let {} = {}.map(ToOwned::to_owned);", par.name, par.name)); + } + } else if is_str { + try!(writeln!(body, "let {} = String::from({});", par.name, par.name)); + } else if c_par.ref_mode != RefMode::None { + try!(writeln!(body, "let {} = {}.clone();", par.name, par.name)); + } + } + + if async_future.is_method { + try!(writeln!(body, "GioFuture::new(self, move |obj, send| {{")); + } else { + try!(writeln!(body, "GioFuture::new(&(), move |_obj, send| {{")); + } + + if env.config.library_name != "Gio" { + try!(writeln!(body, " let cancellable = gio::Cancellable::new();")); + } else { + try!(writeln!(body, " let cancellable = Cancellable::new();")); + } + try!(writeln!(body, " let send = SendCell::new(send);")); + + if async_future.is_method { + try!(writeln!(body, " let obj_clone = SendCell::new(obj.clone());")); + try!(writeln!(body, " obj.{}(", analysis.name)); + } else if analysis.type_name.is_ok() { + try!(writeln!(body, " Self::{}(", analysis.name)); + } else { + try!(writeln!(body, " {}(", analysis.name)); + } + + // Skip the instance parameter + for par in analysis.parameters.rust_parameters.iter().skip(skip) { + if par.name == "cancellable" { + try!(writeln!(body, " Some(&cancellable),")); + } else if par.name == "callback" { + continue; + } else { + let c_par = &analysis.parameters.c_parameters[par.ind_c]; + + let bounds = analysis.bounds.get_parameter_alias_info(&par.name); + let is_into = if let Some((_, BoundType::Into(..))) = bounds { true } else { false }; + + if is_into { + try!(writeln!(body, " {}.as_ref().map(::std::borrow::Borrow::borrow),", par.name)); + } else if c_par.ref_mode != RefMode::None { + try!(writeln!(body, " &{},", par.name)); + } else { + try!(writeln!(body, " {},", par.name)); + } + } + } + + try!(writeln!(body, " move |res| {{")); + if async_future.is_method { + try!(writeln!(body, " let obj = obj_clone.into_inner();")); + try!(writeln!(body, " let res = res.map(|v| (obj.clone(), v)).map_err(|v| (obj.clone(), v));")); + } + try!(writeln!(body, " let _ = send.into_inner().send(res);")); + try!(writeln!(body, " }},")); + try!(writeln!(body, " );")); + try!(writeln!(body)); + try!(writeln!(body, " cancellable")); + try!(writeln!(body, "}})")); + + Ok(body) +} diff --git a/src/codegen/subclass/functions.rs b/src/codegen/subclass/functions.rs index 3cc719571..98ea5e829 100644 --- a/src/codegen/subclass/functions.rs +++ b/src/codegen/subclass/functions.rs @@ -15,7 +15,7 @@ use nameutil; use std::result::Result as StdResult; use std::fmt; -use codegen::subclass::object::SubclassInfo; +use codegen::subclass::class_impls::SubclassInfo; pub fn generate_impl(w: &mut Write, diff --git a/src/codegen/subclass/mod.rs b/src/codegen/subclass/mod.rs index 1df70f695..b8987c4bf 100644 --- a/src/codegen/subclass/mod.rs +++ b/src/codegen/subclass/mod.rs @@ -1,15 +1,10 @@ use env::Env; -use std::io::{Result, Write}; -use library::*; - -mod objects; mod object; -mod class_trait_impls; +mod class_impls; +mod class_impl; mod functions; -use traits::*; - use codegen::generate_single_version_file; @@ -22,7 +17,7 @@ pub fn generate(env: &Env) { generate_single_version_file(env); - objects::generate(env, &root_path, &mut mod_rs, &mut traits); + class_impls::generate(env, &root_path, &mut mod_rs, &mut traits); // lib_::generate(env); // build::generate(env); diff --git a/src/codegen/subclass/object.rs b/src/codegen/subclass/object.rs index b6e9c8827..fb3d4ff73 100644 --- a/src/codegen/subclass/object.rs +++ b/src/codegen/subclass/object.rs @@ -1,64 +1,64 @@ -use std::io::{Result, Write}; - -use analysis; -use library; -use env::Env; -use codegen::child_properties; -use codegen::function; -use codegen::general; -use codegen::properties; -use codegen::signal; -use codegen::trait_impls; -use codegen::trampoline; - - -use codegen::subclass::class_trait_impls; - - -pub struct SubclassInfo{ - -} - -impl SubclassInfo{ - pub fn new(env: &Env, analysis: &analysis::object::Info) -> Self{ - Self{} - } -} - - -pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> { - try!(general::start_comments(w, &env.config)); - try!(general::uses(w, env, &analysis.imports)); - // TODO: insert gobject-subclass uses - // TODO: insert gobject-subclass uses of parent types - - info!("{:?}, {:?}", analysis.c_type, analysis.c_type); - - let subclass_info = SubclassInfo::new(env, analysis); - - class_trait_impls::generate_impl(w, env, analysis, &subclass_info); - - class_trait_impls::generate_impl_ext(w, env, analysis, &subclass_info); - - generate_any_impl(w, env, analysis, &subclass_info); - - - class_trait_impls::generate_base(w, env, analysis, &subclass_info); - - - Ok(()) -} - - -fn generate_any_impl(w: &mut Write, _env: &Env, analysis: &analysis::object::Info, _subclass_info: &SubclassInfo) -> Result<()> -{ - try!(writeln!(w)); - try!(writeln!( - w, - "any_impl!({}, {});", - analysis.subclass_base_trait_name, - analysis.subclass_impl_trait_name - )); - - Ok(()) -} +// use std::io::{Result, Write}; +// +// use analysis; +// use library; +// use env::Env; +// use codegen::child_properties; +// use codegen::function; +// use codegen::general; +// use codegen::properties; +// use codegen::signal; +// use codegen::trait_impls; +// use codegen::trampoline; +// +// +// use codegen::subclass::class_impls; +// +// +// pub struct SubclassInfo{ +// +// } +// +// impl SubclassInfo{ +// pub fn new(env: &Env, analysis: &analysis::object::Info) -> Self{ +// Self{} +// } +// } +// +// +// pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> { +// try!(general::start_comments(w, &env.config)); +// try!(general::uses(w, env, &analysis.imports)); +// // TODO: insert gobject-subclass uses +// // TODO: insert gobject-subclass uses of parent types +// +// info!("{:?}, {:?}", analysis.c_type, analysis.c_type); +// +// let subclass_info = SubclassInfo::new(env, analysis); +// +// class_impls::generate_impl(w, env, analysis, &subclass_info); +// +// class_impls::generate_impl_ext(w, env, analysis, &subclass_info); +// +// generate_any_impl(w, env, analysis, &subclass_info); +// +// +// class_impls::generate_base(w, env, analysis, &subclass_info); +// +// +// Ok(()) +// } +// +// +// fn generate_any_impl(w: &mut Write, _env: &Env, analysis: &analysis::object::Info, _subclass_info: &SubclassInfo) -> Result<()> +// { +// try!(writeln!(w)); +// try!(writeln!( +// w, +// "any_impl!({}, {});", +// analysis.subclass_base_trait_name, +// analysis.subclass_impl_trait_name +// )); +// +// Ok(()) +// } diff --git a/src/codegen/subclass/objects.rs b/src/codegen/subclass/objects.rs deleted file mode 100644 index 20401631b..000000000 --- a/src/codegen/subclass/objects.rs +++ /dev/null @@ -1,73 +0,0 @@ -use std::path::Path; -use std::io::{Result, Write}; - -use env::Env; -use file_saver::*; -use nameutil::*; - -use library::*; -use traits::*; - - -pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec, traits: &mut Vec) { - info!("Generate objects"); - for class_analysis in env.analysis.objects.values() { - let obj = &env.config.objects[&class_analysis.full_name]; - if !obj.status.need_generate() { - continue; - } - - let mod_name = obj.module_name.clone().unwrap_or_else(|| { - module_name(split_namespace_name(&class_analysis.full_name).1) - }); - - let mut path = root_path.join(&mod_name); - path.set_extension("rs"); - info!("Generating file {:?}", mod_name); - - - let ns = env.library.namespace(MAIN_NAMESPACE); - let classes = prepare(ns); - - save_to_file(path, env.config.make_backup, |ref mut w| { - super::object::generate(w, env, class_analysis); - generate_classes_traits(w, env, &classes) - - }); - - // super::object::generate_reexports(env, class_analysis, &mod_name, mod_rs, traits); - } -} - - - -fn prepare(ns: &Namespace) -> Vec<&T> -where - Type: MaybeRef, -{ - let mut vec: Vec<&T> = Vec::with_capacity(ns.types.len()); - for typ in ns.types.iter().filter_map(|t| t.as_ref()) { - if let Some(x) = typ.maybe_ref() { - vec.push(x); - } - } - vec.sort(); - vec -} - - -fn generate_classes_traits(w: &mut Write, env: &Env, classes: &[&Class]) -> Result<()> { - if !classes.is_empty() { - try!(writeln!(w, "// Classes")); - } - for class in classes { - let full_name = format!("{}.{}", env.namespaces.main().name, class.name); - info!("{:?}", full_name); - // if !env.type_status_sys(&full_name).need_generate() { - // continue; - // } - // let fields = fields::from_class(env, class); - // try!(generate_from_fields(w, &fields)); - } - Ok(()) -} From 766bf9e2c7a30f4cab3eb1b62030b90223cf41fc Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 18 May 2018 22:39:42 +0200 Subject: [PATCH 016/122] wip: start generating default impls --- src/codegen/subclass/class_impl.rs | 19 +- src/codegen/subclass/function.rs | 405 ------------------------ src/codegen/subclass/functions.rs | 31 -- src/codegen/subclass/mod.rs | 2 +- src/codegen/subclass/virtual_methods.rs | 57 ++++ 5 files changed, 63 insertions(+), 451 deletions(-) delete mode 100644 src/codegen/subclass/function.rs delete mode 100644 src/codegen/subclass/functions.rs create mode 100644 src/codegen/subclass/virtual_methods.rs diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index eb04c6ebf..a80a47bab 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -17,7 +17,7 @@ use std::fmt; use library::*; use codegen::subclass::class_impls::SubclassInfo; -use codegen::subclass::functions; +use codegen::subclass::virtual_methods; use codegen::general; use codegen::sys::fields; @@ -60,17 +60,6 @@ pub fn generate_impl(w: &mut Write, ) -> Result<()> { - if analysis.class_type.is_some(){ - // let name = format!("{}.{}", env.config., &analysis.class_type.as_ref().unwrap()); - // let klass = env.config.objects.vmap(|x| x.name).collect(); - let ns: Vec = env.library.namespaces.iter().map(|ref x| x.name.clone()).collect(); - info!("Generating {:?} {:?}", ns, env.analysis.objects.keys()); - - // let f = fields::from_class() - } - - - // start impl trait try!(writeln!(w)); try!(writeln!( @@ -80,8 +69,10 @@ pub fn generate_impl(w: &mut Write, analysis.subclass_base_trait_name )); - for func_analysis in &analysis.functions{ - try!(functions::generate_impl(w, env, func_analysis, subclass_info, 1)); + for vfunc_analysis in &class.virtual_methods{ + try!(virtual_methods::generate_default_impl(w, env, analysis, vfunc_analysis, subclass_info, 1)); + + } //end impl trait diff --git a/src/codegen/subclass/function.rs b/src/codegen/subclass/function.rs deleted file mode 100644 index 76a09fe2a..000000000 --- a/src/codegen/subclass/function.rs +++ /dev/null @@ -1,405 +0,0 @@ -use std::io::{Result, Write}; - -use library; -use analysis; -use analysis::bounds::Bounds; -use analysis::functions::Visibility; -use analysis::namespaces; -use chunk::{ffi_function_todo, Chunk}; -use env::Env; -use super::function_body_chunk; -use super::general::{ - cfg_condition, cfg_deprecated, doc_hidden, not_version_condition, version_condition, -}; -use super::parameter::ToParameter; -use super::return_value::{out_parameters_as_return, ToReturnValue}; -use writer::primitives::tabs; -use writer::ToCode; - -use std::result::Result as StdResult; -use std::fmt; - -pub fn generate( - w: &mut Write, - env: &Env, - analysis: &analysis::functions::Info, - in_trait: bool, - only_declaration: bool, - indent: usize, -) -> Result<()> { - if analysis.is_async_finish(env) { - return Ok(()); - } - - let mut commented = false; - let mut comment_prefix = ""; - let mut pub_prefix = if in_trait { "" } else { "pub " }; - - match analysis.visibility { - Visibility::Public => {} - Visibility::Comment => { - commented = true; - comment_prefix = "//"; - } - Visibility::Private => if in_trait { - warn!( - "Generating trait method for private function {}", - analysis.glib_name - ); - } else { - pub_prefix = ""; - }, - Visibility::Hidden => return Ok(()), - } - let declaration = declaration(env, analysis); - let suffix = if only_declaration { ";" } else { " {" }; - - try!(writeln!(w)); - if !in_trait || only_declaration { - try!(cfg_deprecated(w, env, analysis.deprecated_version, commented, indent)); - } - try!(cfg_condition(w, &analysis.cfg_condition, commented, indent)); - try!(version_condition( - w, - env, - analysis.version, - commented, - indent, - )); - try!(not_version_condition( - w, - analysis.not_version, - commented, - indent, - )); - try!(doc_hidden(w, analysis.doc_hidden, comment_prefix, indent)); - try!(writeln!( - w, - "{}{}{}{}{}", - tabs(indent), - comment_prefix, - pub_prefix, - declaration, - suffix - )); - - if !only_declaration { - let body = body_chunk(env, analysis).to_code(env); - for s in body { - try!(writeln!(w, "{}{}", tabs(indent), s)); - } - } - - if analysis.async_future.is_some() { - let declaration = declaration_futures(env, analysis); - let suffix = if only_declaration { ";" } else { " {" }; - - try!(writeln!(w)); - if !in_trait || only_declaration { - try!(cfg_deprecated(w, env, analysis.deprecated_version, commented, indent)); - } - - try!(writeln!(w, "{}{}#[cfg(feature = \"futures\")]", tabs(indent), comment_prefix)); - try!(cfg_condition(w, &analysis.cfg_condition, commented, indent)); - try!(version_condition( - w, - env, - analysis.version, - commented, - indent, - )); - try!(not_version_condition( - w, - analysis.not_version, - commented, - indent, - )); - try!(doc_hidden(w, analysis.doc_hidden, comment_prefix, indent)); - try!(writeln!( - w, - "{}{}{}{}{}", - tabs(indent), - comment_prefix, - pub_prefix, - declaration, - suffix - )); - - if !only_declaration { - let body = body_chunk_futures(env, analysis).unwrap(); - for s in body.lines() { - if !s.is_empty() { - try!(writeln!(w, "{}{}{}", tabs(indent+1), comment_prefix, s)); - } else { - try!(writeln!(w)); - } - } - try!(writeln!(w, "{}{}}}", tabs(indent), comment_prefix)); - } - } - - Ok(()) -} - -pub fn declaration(env: &Env, analysis: &analysis::functions::Info) -> String { - let outs_as_return = !analysis.outs.is_empty(); - let return_str = if outs_as_return { - out_parameters_as_return(env, analysis) - } else if analysis.ret.bool_return_is_error.is_some() { - if env.namespaces.glib_ns_id == namespaces::MAIN { - " -> Result<(), error::BoolError>".into() - } else { - " -> Result<(), glib::error::BoolError>".into() - } - } else { - analysis.ret.to_return_value(env) - }; - let mut param_str = String::with_capacity(100); - - let bounds = bounds(&analysis.bounds, &[], false); - - for (pos, par) in analysis.parameters.rust_parameters.iter().enumerate() { - if pos > 0 { - param_str.push_str(", ") - } - let c_par = &analysis.parameters.c_parameters[par.ind_c]; - let s = c_par.to_parameter(env, &analysis.bounds); - param_str.push_str(&s); - } - - format!( - "fn {}{}({}){}", - analysis.name, - bounds, - param_str, - return_str - ) -} - -pub fn declaration_futures(env: &Env, analysis: &analysis::functions::Info) -> String { - let async_future = analysis.async_future.as_ref().unwrap(); - - let return_str = if async_future.is_method { - format!(" -> Box_>", async_future.success_parameters, async_future.error_parameters) - } else { - format!(" -> Box_>", async_future.success_parameters, async_future.error_parameters) - }; - - let mut param_str = String::with_capacity(100); - - let mut skipped = 0; - let mut skipped_bounds = vec![]; - for (pos, par) in analysis.parameters.rust_parameters.iter().enumerate() { - let c_par = &analysis.parameters.c_parameters[par.ind_c]; - - if c_par.name == "callback" || c_par.name == "cancellable" { - skipped += 1; - if let Some((t, _)) = analysis.bounds.get_parameter_alias_info(&c_par.name) { - skipped_bounds.push(t); - } - continue; - } - - if pos - skipped > 0 { - param_str.push_str(", ") - } - - let s = c_par.to_parameter(env, &analysis.bounds); - param_str.push_str(&s); - } - - let bounds = bounds(&analysis.bounds, skipped_bounds.as_ref(), true); - - format!( - "fn {}{}({}){}", - async_future.name, - bounds, - param_str, - return_str - ) -} - -pub fn bounds(bounds: &Bounds, skip: &[char], async: bool) -> String { - use analysis::bounds::BoundType::*; - if bounds.is_empty() { - return String::new(); - } - - let skip_lifetimes = bounds.iter() - .filter(|bound| skip.contains(&bound.alias)) - .filter_map(|bound| match bound.bound_type { - IsA(Some(lifetime)) | - AsRef(Some(lifetime)) | - Into(Some(lifetime), _) => Some(lifetime), - _ => None, - }) - .collect::>(); - - let strs: Vec = bounds - .iter_lifetimes() - .filter(|s| !skip_lifetimes.contains(s)) - .map(|s| format!("'{}", s)) - .chain(bounds.iter().filter(|bound| !skip.contains(&bound.alias)).map(|bound| match bound.bound_type { - NoWrapper => { - format!("{}: {}", bound.alias, bound.type_str) - } - IsA(Some(lifetime)) => { - format!("{}: IsA<{}> + {}", bound.alias, bound.type_str, if async { "Clone + 'static".into() } else { format!("'{}", lifetime) }) - } - IsA(None) => format!("{}: IsA<{}>{}", bound.alias, bound.type_str, if async { " + Clone + 'static" } else { "" }), - // This case should normally never happened - AsRef(Some(lifetime)) => { - format!("{}: AsRef<{}> + '{}", bound.alias, bound.type_str, lifetime) - } - AsRef(None) => format!("{}: AsRef<{}>", bound.alias, bound.type_str), - Into(Some(l), _) => { - format!("{}: Into>", bound.alias, l, bound.type_str) - } - Into(None, _) => format!("{}: Into>", bound.alias, bound.type_str), - })) - .collect(); - - if strs.is_empty() { - String::new() - } else { - format!("<{}>", strs.join(", ")) - } -} - -pub fn body_chunk(env: &Env, analysis: &analysis::functions::Info) -> Chunk { - if analysis.visibility == Visibility::Comment { - return ffi_function_todo(&analysis.glib_name); - } - - let outs_as_return = !analysis.outs.is_empty(); - - let mut builder = function_body_chunk::Builder::new(); - builder - .glib_name(&analysis.glib_name) - .assertion(analysis.assertion) - .ret(&analysis.ret) - .transformations(&analysis.parameters.transformations) - .outs_mode(analysis.outs.mode); - - if analysis.async { - if let Some(ref trampoline) = analysis.trampoline { - builder.async_trampoline(trampoline); - } else { - warn!("Async function {} has no associated _finish function", analysis.name); - } - } - - for par in &analysis.parameters.c_parameters { - if outs_as_return && analysis.outs.iter().any(|p| p.name == par.name) { - builder.out_parameter(env, par); - } else { - builder.parameter(); - } - } - - builder.generate(env) -} - -pub fn body_chunk_futures(env: &Env, analysis: &analysis::functions::Info) -> StdResult { - use std::fmt::Write; - use analysis::bounds::BoundType; - use analysis::ref_mode::RefMode; - - let async_future = analysis.async_future.as_ref().unwrap(); - - let mut body = String::new(); - - if env.config.library_name != "Gio" { - try!(writeln!(body, "use gio::GioFuture;")); - } else { - try!(writeln!(body, "use GioFuture;")); - } - try!(writeln!(body, "use send_cell::SendCell;")); - try!(writeln!(body)); - - let skip = if async_future.is_method { 1 } else { 0 }; - - // Skip the instance parameter - for par in analysis.parameters.rust_parameters.iter().skip(skip) { - if par.name == "cancellable" || par.name == "callback" { - continue; - } - - let c_par = &analysis.parameters.c_parameters[par.ind_c]; - - let bounds = analysis.bounds.get_parameter_alias_info(&par.name); - let is_into = if let Some((_, BoundType::Into(..))) = bounds { true } else { false }; - - let type_ = env.type_(par.typ); - let is_str = if let library::Type::Fundamental(library::Fundamental::Utf8) = *type_ { true } else { false }; - - if is_into { - try!(writeln!(body, "let {} = {}.into();", par.name, par.name)); - if is_str || c_par.nullable.0 { - try!(writeln!(body, "let {} = {}.map(ToOwned::to_owned);", par.name, par.name)); - } - } else if is_str { - try!(writeln!(body, "let {} = String::from({});", par.name, par.name)); - } else if c_par.ref_mode != RefMode::None { - try!(writeln!(body, "let {} = {}.clone();", par.name, par.name)); - } - } - - if async_future.is_method { - try!(writeln!(body, "GioFuture::new(self, move |obj, send| {{")); - } else { - try!(writeln!(body, "GioFuture::new(&(), move |_obj, send| {{")); - } - - if env.config.library_name != "Gio" { - try!(writeln!(body, " let cancellable = gio::Cancellable::new();")); - } else { - try!(writeln!(body, " let cancellable = Cancellable::new();")); - } - try!(writeln!(body, " let send = SendCell::new(send);")); - - if async_future.is_method { - try!(writeln!(body, " let obj_clone = SendCell::new(obj.clone());")); - try!(writeln!(body, " obj.{}(", analysis.name)); - } else if analysis.type_name.is_ok() { - try!(writeln!(body, " Self::{}(", analysis.name)); - } else { - try!(writeln!(body, " {}(", analysis.name)); - } - - // Skip the instance parameter - for par in analysis.parameters.rust_parameters.iter().skip(skip) { - if par.name == "cancellable" { - try!(writeln!(body, " Some(&cancellable),")); - } else if par.name == "callback" { - continue; - } else { - let c_par = &analysis.parameters.c_parameters[par.ind_c]; - - let bounds = analysis.bounds.get_parameter_alias_info(&par.name); - let is_into = if let Some((_, BoundType::Into(..))) = bounds { true } else { false }; - - if is_into { - try!(writeln!(body, " {}.as_ref().map(::std::borrow::Borrow::borrow),", par.name)); - } else if c_par.ref_mode != RefMode::None { - try!(writeln!(body, " &{},", par.name)); - } else { - try!(writeln!(body, " {},", par.name)); - } - } - } - - try!(writeln!(body, " move |res| {{")); - if async_future.is_method { - try!(writeln!(body, " let obj = obj_clone.into_inner();")); - try!(writeln!(body, " let res = res.map(|v| (obj.clone(), v)).map_err(|v| (obj.clone(), v));")); - } - try!(writeln!(body, " let _ = send.into_inner().send(res);")); - try!(writeln!(body, " }},")); - try!(writeln!(body, " );")); - try!(writeln!(body)); - try!(writeln!(body, " cancellable")); - try!(writeln!(body, "}})")); - - Ok(body) -} diff --git a/src/codegen/subclass/functions.rs b/src/codegen/subclass/functions.rs deleted file mode 100644 index 98ea5e829..000000000 --- a/src/codegen/subclass/functions.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::io::{Result, Write}; - -use library; -use analysis; -use analysis::bounds::Bounds; -use analysis::functions::Visibility; -use analysis::namespaces; -use chunk::{ffi_function_todo, Chunk}; -use env::Env; - -use writer::primitives::tabs; -use writer::ToCode; -use nameutil; - -use std::result::Result as StdResult; -use std::fmt; - -use codegen::subclass::class_impls::SubclassInfo; - - -pub fn generate_impl(w: &mut Write, - env: &Env, - analysis: &analysis::functions::Info, - subclass_info: &SubclassInfo, - indent: usize - ) -> Result<()> { - - info!("{:?}", analysis.name); - - Ok(()) -} diff --git a/src/codegen/subclass/mod.rs b/src/codegen/subclass/mod.rs index b8987c4bf..431d2c323 100644 --- a/src/codegen/subclass/mod.rs +++ b/src/codegen/subclass/mod.rs @@ -3,7 +3,7 @@ use env::Env; mod object; mod class_impls; mod class_impl; -mod functions; +mod virtual_methods; use codegen::generate_single_version_file; diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs new file mode 100644 index 000000000..437675968 --- /dev/null +++ b/src/codegen/subclass/virtual_methods.rs @@ -0,0 +1,57 @@ +use std::io::{Result, Write}; + +use library; +use analysis; +use analysis::bounds::Bounds; +use analysis::functions::Visibility; +use analysis::namespaces; +use env::Env; +use writer::primitives::tabs; +use writer::ToCode; + +use std::result::Result as StdResult; +use std::fmt; + +use codegen::subclass::class_impls::SubclassInfo; + +pub fn generate_default_impl( + w: &mut Write, + env: &Env, + analysis: &analysis::object::Info, + method: &library::Signal, + subclass_info: &SubclassInfo, + indent: usize, +) -> Result<()> { + info!("vfunc: {:?}", method.name); + +// fn window_added(&self, application: &T, window: >k::Window) { +// application.parent_window_added(window) +// } + try!(writeln!(w)); + try!(writeln!( + w, + "{}fn {}(&self, {}:&T){{", + tabs(indent), + method.name, + analysis.name.to_lowercase(), + )); + + try!(writeln!( + w, + "{}{}.parent_{}()", + tabs(indent+1), + analysis.name.to_lowercase(), + method.name + )); + + + try!(writeln!( + w, + "{}}}", + tabs(indent), + )); + + Ok(()) + + +} From 1b0ff1a506080f0bf55bc4c621b7ee875151e5fd Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 20 May 2018 09:11:33 +0200 Subject: [PATCH 017/122] wip: beef up analysis for virtual methods. Still panicks somewhere --- src/analysis/mod.rs | 1 + src/analysis/object.rs | 27 ++ src/analysis/virtual_methods.rs | 385 ++++++++++++++++++++++++ src/codegen/subclass/class_impl.rs | 31 +- src/codegen/subclass/class_impls.rs | 39 +-- src/codegen/subclass/virtual_methods.rs | 53 +++- src/config/gobjects.rs | 5 + src/library.rs | 6 +- src/parser.rs | 79 ++++- 9 files changed, 558 insertions(+), 68 deletions(-) create mode 100644 src/analysis/virtual_methods.rs diff --git a/src/analysis/mod.rs b/src/analysis/mod.rs index a50e72808..467bf8445 100644 --- a/src/analysis/mod.rs +++ b/src/analysis/mod.rs @@ -28,6 +28,7 @@ pub mod return_value; pub mod rust_type; pub mod safety_assertion_mode; pub mod signals; +pub mod virtual_methods; pub mod signatures; pub mod special_functions; pub mod supertypes; diff --git a/src/analysis/object.rs b/src/analysis/object.rs index 9b1b09055..83226e91b 100644 --- a/src/analysis/object.rs +++ b/src/analysis/object.rs @@ -30,6 +30,7 @@ pub struct Info { pub has_functions: bool, pub signals: Vec, pub notify_signals: Vec, + pub virtual_methods: Vec, pub trampolines: trampolines::Trampolines, pub properties: Vec, pub child_properties: ChildProperties, @@ -163,6 +164,18 @@ pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option obj, &mut imports, ); + + let virtual_methods = virtual_methods::analyze( + env, + &klass.virtual_methods, + class_tid, + generate_trait, + obj, + &mut imports, + Some(&mut signatures), + Some(deps), + ); + let (properties, notify_signals) = properties::analyze( env, &klass.properties, @@ -262,6 +275,7 @@ pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option has_functions, signals, notify_signals, + virtual_methods, trampolines, properties, child_properties, @@ -327,6 +341,18 @@ pub fn interface(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option Option, + pub deprecated_version: Option, + pub not_version: Option, + pub cfg_condition: Option, + pub assertion: SafetyAssertionMode, + pub doc_hidden: bool, + pub async: bool, + pub trampoline: Option, + pub async_future: Option, +} + + +pub fn analyze( + env: &Env, + methods: &[library::Function], + type_tid: library::TypeId, + in_trait: bool, + obj: &GObject, + imports: &mut Imports, + mut signatures: Option<&mut Signatures>, + deps: Option<&[library::TypeId]>, +) -> Vec { + let mut vmethds = Vec::new(); + + for method in methods { + let method = method.borrow(); + let configured_methods = obj.virtual_methods.matched(&method.name); + if configured_methods.iter().any(|m| m.ignore) { + continue; + } + if env.is_totally_deprecated(method.deprecated_version) { + continue; + } + + let name = nameutil::mangle_keywords(&*method.name).into_owned(); + let signature_params = Signature::new(method); + let mut not_version = None; + if let Some(deps) = deps { + let (has, version) = signature_params.has_in_deps(env, &name, deps); + if has { + match version { + Some(v) if v > env.config.min_cfg_version => not_version = version, + _ => continue, + } + } + } + + if let Some(ref mut signatures) = signatures { + signatures.insert(name.clone(), signature_params); + } + + let mut info = analyze_virtual_method(env, name, method, type_tid, in_trait, + &configured_methods, obj, imports); + info.not_version = not_version; + vmethds.push(info); + } + + vmethds +} + + + +fn analyze_virtual_method( + env: &Env, + name: String, + method: &library::Function, + type_tid: library::TypeId, + in_trait: bool, + configured_methods: &[&config::functions::Function], + obj: &GObject, + imports: &mut Imports +) -> Info { + + let async = method.parameters.iter().any(|parameter| parameter.scope == ParameterScope::Async); + let mut commented = false; + let mut bounds: Bounds = Default::default(); + let mut to_glib_extras = HashMap::::new(); + let mut used_types: Vec = Vec::with_capacity(4); + let mut trampoline = None; + let mut async_future = None; + + let version = configured_methods + .iter() + .filter_map(|f| f.version) + .min() + .or(method.version); + let version = env.config.filter_version(version); + let deprecated_version = method.deprecated_version; + let cfg_condition = configured_methods + .iter() + .filter_map(|f| f.cfg_condition.clone()) + .next(); + let doc_hidden = configured_methods.iter().any(|f| f.doc_hidden); + let disable_length_detect = configured_methods.iter().any(|f| f.disable_length_detect); + + let ret = return_value::analyze( + env, + method, + type_tid, + configured_methods, + &mut used_types, + imports, + ); + commented |= ret.commented; + + let mut parameters = function_parameters::analyze( + env, + &method.parameters, + configured_methods, + disable_length_detect, + async, + in_trait + ); + parameters.analyze_return(env, &ret.parameter); + + for (pos, par) in parameters.c_parameters.iter().enumerate() { + assert!( + !par.instance_parameter || pos == 0, + "Wrong instance parameter in {}", + method.c_identifier.as_ref().unwrap() + ); + if let Ok(s) = used_rust_type(env, par.typ) { + used_types.push(s); + } + let (to_glib_extra, type_string) = bounds.add_for_parameter(env, method, par, async); + if let Some(to_glib_extra) = to_glib_extra { + to_glib_extras.insert(pos, to_glib_extra); + } + if let Some((callback_type, success_parameters, error_parameters, bound_name)) = type_string { + // Checks for /*Ignored*/ or other error comments + if callback_type.find("/*").is_some() { + commented = true; + } + let func_name = method.c_identifier.as_ref().unwrap(); + let finish_func_name = finish_function_name(func_name); + let mut output_params = vec![]; + let mut ffi_ret = None; + if let Some(function) = find_function(env, &finish_func_name) { + if use_function_return_for_result(env, function.ret.typ) { + ffi_ret = Some(function.ret.clone()); + } + + output_params.extend(function.parameters.clone()); + for param in &mut output_params { + if nameutil::needs_mangling(¶m.name) { + param.name = nameutil::mangle_keywords(&*param.name).into_owned(); + } + } + } + trampoline = Some(AsyncTrampoline { + is_method: true, + name: format!("{}_trampoline", method.name), + finish_func_name, + callback_type, + bound_name, + output_params, + ffi_ret, + }); + + async_future = Some(AsyncFuture { + is_method: true, + name: format!("{}_future", method.name), + success_parameters, + error_parameters, + }); + } + let type_error = + !(async && *env.library.type_(par.typ) == Type::Fundamental(library::Fundamental::Pointer)) && + parameter_rust_type(env, par.typ, par.direction, Nullable(false), RefMode::None) + .is_err(); + if type_error { + commented = true; + } + } + + if async && trampoline.is_none() { + commented = true; + } + + for par in ¶meters.rust_parameters { + // Disallow fundamental arrays without length + let is_len_for_par = |t: &&Transformation| { + if let TransformationType::Length { ref array_name, .. } = t.transformation_type { + array_name == &par.name + } else { + false + } + }; + if is_carray_with_direct_elements(env, par.typ) + && parameters + .transformations + .iter() + .find(is_len_for_par) + .is_none() + { + commented = true; + } + } + + let (outs, unsupported_outs) = out_parameters::analyze( + env, + method, + ¶meters.c_parameters, + &ret, + configured_methods, + ); + if unsupported_outs { + warn!( + "Function {} has unsupported outs", + method.c_identifier.as_ref().unwrap_or(&method.name) + ); + commented = true; + } else if !outs.is_empty() && !commented { + out_parameters::analyze_imports(env, method, imports); + } + + if async && !commented { + if env.config.library_name != "Gio" { + imports.add("gio_ffi", version); + imports.add_with_constraint("gio", version, Some("futures")); + } + imports.add("glib_ffi", None); + imports.add("gobject_ffi", None); + imports.add_with_constraint("futures_core", version, Some("futures")); + imports.add_with_constraint("std::boxed::Box as Box_", version, Some("futures")); + + if let Some(ref trampoline) = trampoline { + for par in &trampoline.output_params { + if let Ok(s) = used_rust_type(env, par.typ) { + used_types.push(s); + } + } + if let Some(ref par) = trampoline.ffi_ret { + if let Ok(s) = used_rust_type(env, par.typ) { + used_types.push(s); + } + } + } + } + + if !commented { + for transformation in &mut parameters.transformations { + if let Some(to_glib_extra) = to_glib_extras.get(&transformation.ind_c) { + transformation + .transformation_type + .set_to_glib_extra(to_glib_extra); + } + } + + imports.add_used_types(&used_types, version); + if ret.base_tid.is_some() { + imports.add("glib::object::Downcast", None); + } + bounds.update_imports(imports); + } + + let visibility = if commented { + Visibility::Comment + } else { + Visibility::Public + }; + let assertion = SafetyAssertionMode::of(env, true, ¶meters); + + Info { + name, + glib_name: method.c_identifier.as_ref().unwrap().clone(), + visibility, + type_name: rust_type(env, type_tid), + parameters, + ret, + bounds, + outs, + version, + deprecated_version, + not_version: None, + cfg_condition, + assertion, + doc_hidden, + async, + trampoline, + async_future, + } +} + + +// let mut used_types: Vec = Vec::with_capacity(4); +// let version = configured_signals +// .iter() +// .filter_map(|f| f.version) +// .min() +// .or(signal.version); +// let deprecated_version = signal.deprecated_version; +// let doc_hidden = configured_signals.iter().any(|f| f.doc_hidden); +// +// let connect_name = format!("connect_{}", nameutil::signal_to_snake(&signal.name)); +// let trampoline_name = trampolines::analyze( +// env, +// signal, +// type_tid, +// in_trait, +// configured_signals, +// trampolines, +// obj, +// &mut used_types, +// version, +// ); +// +// let action_emit_name = if signal.is_action { +// if !in_trait { +// imports.add("glib::object::ObjectExt", version); +// } +// Some(format!("emit_{}", nameutil::signal_to_snake(&signal.name))) +// } else { +// None +// }; +// +// if trampoline_name.is_ok() { +// imports.add_used_types(&used_types, version); +// if in_trait { +// imports.add("glib", version); +// imports.add("glib::object::Downcast", version); +// } +// imports.add("glib::signal::connect", version); +// imports.add("glib::signal::SignalHandlerId", version); +// imports.add("std::mem::transmute", version); +// imports.add("std::boxed::Box as Box_", version); +// imports.add("glib_ffi", version); +// } +// +// let info = Info { +// connect_name, +// signal_name: signal.name.clone(), +// trampoline_name, +// action_emit_name, +// version, +// deprecated_version, +// doc_hidden, +// }; +// Some(info) +// } diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index a80a47bab..470625828 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -22,7 +22,7 @@ use codegen::general; use codegen::sys::fields; -pub fn generate(w: &mut Write, env: &Env, class: &Class, analysis: &analysis::object::Info) -> Result<()> +pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> { try!(general::start_comments(w, &env.config)); try!(general::uses(w, env, &analysis.imports)); @@ -31,16 +31,16 @@ pub fn generate(w: &mut Write, env: &Env, class: &Class, analysis: &analysis::ob info!("{:?}, {:?}", analysis.c_type, analysis.c_type); - let subclass_info = SubclassInfo::new(env, class, analysis); + let subclass_info = SubclassInfo::new(env, analysis); - generate_impl(w, env, class, analysis, &subclass_info); + generate_impl(w, env, analysis, &subclass_info); - generate_impl_ext(w, env, class, analysis, &subclass_info); + generate_impl_ext(w, env, analysis, &subclass_info); - generate_any_impl(w, env, class, analysis, &subclass_info); + generate_any_impl(w, env, analysis, &subclass_info); - generate_base(w, env, class, analysis, &subclass_info); + generate_base(w, env, analysis, &subclass_info); Ok(()) @@ -54,8 +54,7 @@ pub fn generate(w: &mut Write, env: &Env, class: &Class, analysis: &analysis::ob pub fn generate_impl(w: &mut Write, env: &Env, - class: &Class, - analysis: &analysis::object::Info, + object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo ) -> Result<()> { @@ -65,12 +64,12 @@ pub fn generate_impl(w: &mut Write, try!(writeln!( w, "pub trait {}: ObjectImpl + AnyImpl + 'static {{", //TODO: use real superclasses chain - analysis.subclass_impl_trait_name, - analysis.subclass_base_trait_name + object_analysis.subclass_impl_trait_name, + object_analysis.subclass_base_trait_name )); - for vfunc_analysis in &class.virtual_methods{ - try!(virtual_methods::generate_default_impl(w, env, analysis, vfunc_analysis, subclass_info, 1)); + for method_analysis in &object_analysis.virtual_methods{ + try!(virtual_methods::generate_default_impl(w, env, object_analysis, method_analysis, subclass_info, 1)); } @@ -87,8 +86,7 @@ pub fn generate_impl(w: &mut Write, pub fn generate_impl_ext(w: &mut Write, env: &Env, - class: &Class, - analysis: &analysis::object::Info, + object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo ) -> Result<()> { @@ -97,7 +95,7 @@ pub fn generate_impl_ext(w: &mut Write, try!(writeln!( w, "pub trait {}Ext {{}}", - analysis.subclass_impl_trait_name + object_analysis.subclass_impl_trait_name )); //end impl trait @@ -113,7 +111,6 @@ pub fn generate_impl_ext(w: &mut Write, pub fn generate_base(w: &mut Write, env: &Env, - class: &Class, analysis: &analysis::object::Info, subclass_info: &SubclassInfo ) -> Result<()> { @@ -144,7 +141,7 @@ pub fn generate_base(w: &mut Write, // pub unsafe trait ApplicationBase: IsA + ObjectType { -fn generate_any_impl(w: &mut Write, _env: &Env, class: &Class, analysis: &analysis::object::Info, _subclass_info: &SubclassInfo) -> Result<()> +fn generate_any_impl(w: &mut Write, _env: &Env, analysis: &analysis::object::Info, _subclass_info: &SubclassInfo) -> Result<()> { try!(writeln!(w)); try!(writeln!( diff --git a/src/codegen/subclass/class_impls.rs b/src/codegen/subclass/class_impls.rs index 2cbd9a209..2c108005e 100644 --- a/src/codegen/subclass/class_impls.rs +++ b/src/codegen/subclass/class_impls.rs @@ -15,7 +15,7 @@ pub struct SubclassInfo{ } impl SubclassInfo{ - pub fn new(env: &Env, class: &Class, analysis: &analysis::object::Info) -> Self{ + pub fn new(env: &Env, analysis: &analysis::object::Info) -> Self{ Self{} } } @@ -25,9 +25,6 @@ impl SubclassInfo{ pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec, traits: &mut Vec) { info!("Generate class traits"); - let ns = env.library.namespace(MAIN_NAMESPACE); - let classes = prepare(ns); - for object_analysis in env.analysis.objects.values() { let obj = &env.config.objects[&object_analysis.full_name]; @@ -43,39 +40,11 @@ pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec, traits: & path.set_extension("rs"); info!("Generating file {:?}", mod_name); - let class_idx = classes.binary_search_by(|c: &&Class| { - (*c).c_type.cmp(&object_analysis.c_type) - }); - - match class_idx{ - Ok(idx) => { - let class = classes[class_idx.unwrap()]; - save_to_file(path, env.config.make_backup, |ref mut w| { - class_impl::generate(w, env, class, object_analysis) - }); - }, - Err(_) => { - warn!("No class definition found for {:?}. Skipping...", object_analysis.full_name) - } - } + save_to_file(path, env.config.make_backup, |ref mut w| { + class_impl::generate(w, env, object_analysis) + }); // super::object::generate_reexports(env, class_analysis, &mod_name, mod_rs, traits); } } - - -// TODO: remove duplicate with sys generator -fn prepare(ns: &Namespace) -> Vec<&T> -where - Type: MaybeRef, -{ - let mut vec: Vec<&T> = Vec::with_capacity(ns.types.len()); - for typ in ns.types.iter().filter_map(|t| t.as_ref()) { - if let Some(x) = typ.maybe_ref() { - vec.push(x); - } - } - vec.sort(); - vec -} diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 437675968..72d6d8e3a 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -8,6 +8,7 @@ use analysis::namespaces; use env::Env; use writer::primitives::tabs; use writer::ToCode; +use codegen::parameter::ToParameter; use std::result::Result as StdResult; use std::fmt; @@ -17,31 +18,44 @@ use codegen::subclass::class_impls::SubclassInfo; pub fn generate_default_impl( w: &mut Write, env: &Env, - analysis: &analysis::object::Info, - method: &library::Signal, + object_analysis: &analysis::object::Info, + method_analysis: &analysis::virtual_methods::Info, subclass_info: &SubclassInfo, indent: usize, ) -> Result<()> { - info!("vfunc: {:?}", method.name); + info!("vfunc: {:?}", method_analysis.name); + + + -// fn window_added(&self, application: &T, window: >k::Window) { -// application.parent_window_added(window) -// } try!(writeln!(w)); - try!(writeln!( + try!(write!( w, - "{}fn {}(&self, {}:&T){{", + "{}fn {}(&self", tabs(indent), - method.name, - analysis.name.to_lowercase(), + method_analysis.name, )); + let mut param_str = String::with_capacity(100); + for (pos, par) in method_analysis.parameters.rust_parameters.iter().enumerate() { + if pos > 0 { + param_str.push_str(", ") + } + let c_par = &method_analysis.parameters.c_parameters[par.ind_c]; + let s = c_par.to_parameter(env, &method_analysis.bounds); + param_str.push_str(&s); + } + + + try!(writeln!(w, "{}){{", param_str)); + + try!(writeln!( w, "{}{}.parent_{}()", tabs(indent+1), - analysis.name.to_lowercase(), - method.name + object_analysis.name.to_lowercase(), + method_analysis.name )); @@ -53,5 +67,20 @@ pub fn generate_default_impl( Ok(()) +} + +fn generate_args(w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + method_analysys: &analysis::virtual_methods::Info, + subclass_info: &SubclassInfo) -> Result<()> +{ + + // for ref param in &method.parameters { + // try!(write!(w, "{}:{}", param.name, param.typ.full_name(&env.library))); + // + // } + + Ok(()) } diff --git a/src/config/gobjects.rs b/src/config/gobjects.rs index 41ac7881b..54b303af4 100644 --- a/src/config/gobjects.rs +++ b/src/config/gobjects.rs @@ -60,6 +60,7 @@ impl FromStr for GStatus { pub struct GObject { pub name: String, pub functions: Functions, + pub virtual_methods: Functions, pub constants: Constants, pub signals: Signals, pub members: Members, @@ -89,6 +90,7 @@ impl Default for GObject { GObject { name: "Default".into(), functions: Functions::new(), + virtual_methods: Functions::new(), constants: Constants::new(), signals: Signals::new(), members: Members::new(), @@ -174,6 +176,7 @@ fn parse_object( "name", "status", "function", + "virtual_method", "constant", "signal", "member", @@ -209,6 +212,7 @@ fn parse_object( let constants = Constants::parse(toml_object.lookup("constant"), &name); let functions = Functions::parse(toml_object.lookup("function"), &name); + let virtual_methods = Functions::parse(toml_object.lookup("virtual_methods"), &name); let signals = { let mut v = Vec::new(); if let Some(configs) = toml_object.lookup("signal").and_then(|val| val.as_array()) { @@ -298,6 +302,7 @@ fn parse_object( GObject { name, functions, + virtual_methods, constants, signals, members, diff --git a/src/library.rs b/src/library.rs index 92c9b0895..2ce27163d 100644 --- a/src/library.rs +++ b/src/library.rs @@ -124,6 +124,7 @@ pub enum FunctionKind { Function, Method, Global, + VirtualMethod } impl FromStr for FunctionKind { @@ -136,6 +137,7 @@ impl FromStr for FunctionKind { "method" => Ok(Method), "callback" => Ok(Function), "global" => Ok(Global), + "virtual-method" => Ok(VirtualMethod), _ => Err("Unknown function kind".into()), } } @@ -445,7 +447,7 @@ pub struct Interface { pub c_class_type: Option, pub glib_get_type: String, pub functions: Vec, - pub virtual_methods: Vec, + pub virtual_methods: Vec, pub signals: Vec, pub properties: Vec, pub prerequisites: Vec, @@ -463,7 +465,7 @@ pub struct Class { pub glib_get_type: String, pub fields: Vec, pub functions: Vec, - pub virtual_methods: Vec, + pub virtual_methods: Vec, pub signals: Vec, pub properties: Vec, pub parent: Option, diff --git a/src/parser.rs b/src/parser.rs index 0dd033ada..f4ebb8e34 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -155,7 +155,7 @@ impl Library { }) } "virtual-method" => { - self.read_signal(parser, ns_id, elem).map(|v| { + self.read_virtual_method(parser, ns_id, elem).map(|v| { vfns.push(v) }) } @@ -604,7 +604,7 @@ impl Library { } "doc" => parser.text().map(|t| doc = Some(t)), "virtual-method" => { - self.read_signal(parser, ns_id, elem).map(|v| { + self.read_virtual_method(parser, ns_id, elem).map(|v| { vfns.push(v) }) }, @@ -1014,6 +1014,81 @@ impl Library { } } + fn read_virtual_method( + &mut self, + parser: &mut XmlParser, + ns_id: u16, + elem: &Element, + ) -> Result { + let method_name = elem.attr_required("name")?; + let version = self.read_version(parser, ns_id, elem)?; + let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?; + let c_identifier = elem.attr("identifier").or_else(|| elem.attr("type")); + + let mut params = Vec::new(); + let mut ret = None; + let mut doc = None; + let mut doc_deprecated = None; + + parser.elements(|parser, elem| match elem.name() { + "parameters" => { + self.read_parameters(parser, ns_id, true, true).map(|mut ps| { + params.append(&mut ps) + }) + } + "return-value" => { + if ret.is_some() { + return Err(parser.fail("Too many elements")); + } + self.read_parameter(parser, ns_id, elem, true, false).map(|p| { + ret = Some(p) + }) + } + "doc" => parser.text().map(|t| doc = Some(t)), + "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)), + _ => Err(parser.unexpected_element(elem)), + })?; + + let throws = elem.attr_bool("throws", false); + if throws { + params.push(Parameter { + name: "error".into(), + typ: self.find_or_stub_type(ns_id, "GLib.Error"), + c_type: "GError**".into(), + instance_parameter: false, + direction: ParameterDirection::Out, + transfer: Transfer::Full, + caller_allocates: false, + nullable: Nullable(true), + array_length: None, + allow_none: true, + is_error: true, + doc: None, + scope: ParameterScope::None, + closure: None, + destroy: None, + }); + } + + if let Some(ret) = ret { + Ok(Function { + name: method_name.into(), + c_identifier: c_identifier.map(|s| s.into()), + kind: FunctionKind::VirtualMethod, + parameters: params, + ret, + throws, + version, + deprecated_version, + doc, + doc_deprecated, + }) + } else { + Err(parser.fail("Missing element")) + } + } + + fn read_parameters( &mut self, parser: &mut XmlParser, From 2ac1f3c1a7ba9e43e634d74287a6940e4abf6b11 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 20 May 2018 09:39:52 +0200 Subject: [PATCH 018/122] use name if c_identifier is not specified --- src/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser.rs b/src/parser.rs index f4ebb8e34..f80537b05 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1023,7 +1023,7 @@ impl Library { let method_name = elem.attr_required("name")?; let version = self.read_version(parser, ns_id, elem)?; let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?; - let c_identifier = elem.attr("identifier").or_else(|| elem.attr("type")); + let c_identifier = elem.attr("identifier").or_else(|| elem.attr("name")); let mut params = Vec::new(); let mut ret = None; From de46e6d50d9a5ed7d375d2f664948ad5de413f1c Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 20 May 2018 10:02:57 +0200 Subject: [PATCH 019/122] fix virtual methods in Impl trait --- src/codegen/subclass/virtual_methods.rs | 27 +++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 72d6d8e3a..61332705c 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -31,7 +31,7 @@ pub fn generate_default_impl( try!(writeln!(w)); try!(write!( w, - "{}fn {}(&self", + "{}fn {}(", tabs(indent), method_analysis.name, )); @@ -39,23 +39,42 @@ pub fn generate_default_impl( let mut param_str = String::with_capacity(100); for (pos, par) in method_analysis.parameters.rust_parameters.iter().enumerate() { if pos > 0 { - param_str.push_str(", ") + param_str.push_str(", "); } + let c_par = &method_analysis.parameters.c_parameters[par.ind_c]; let s = c_par.to_parameter(env, &method_analysis.bounds); param_str.push_str(&s); + + // insert the templated param + if pos == 0{ + param_str.push_str(&format!(", {}: &T", object_analysis.name.to_lowercase())); + } } try!(writeln!(w, "{}){{", param_str)); + let mut arg_str = String::with_capacity(100); + for (pos, par) in method_analysis.parameters.rust_parameters.iter().enumerate() { + if pos == 0{ + // skip the first one + continue; + } + if pos > 1 { + arg_str.push_str(", "); + } + arg_str.push_str(&par.name); + } + try!(writeln!( w, - "{}{}.parent_{}()", + "{}{}.parent_{}({})", tabs(indent+1), object_analysis.name.to_lowercase(), - method_analysis.name + method_analysis.name, + arg_str )); From 4d0bcc910bd6c57c8e28858d8ccac0764b1db2b7 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 20 May 2018 12:27:35 +0200 Subject: [PATCH 020/122] impl trait: use real parents and interfaces --- src/codegen/subclass/class_impl.rs | 185 ++++++++++++++++-------- src/codegen/subclass/class_impls.rs | 11 -- src/codegen/subclass/virtual_methods.rs | 4 +- 3 files changed, 126 insertions(+), 74 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 470625828..50fa2667f 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -1,36 +1,69 @@ use std::io::{Result, Write}; -use library; use analysis; use analysis::bounds::Bounds; use analysis::functions::Visibility; use analysis::namespaces; use chunk::{ffi_function_todo, Chunk}; use env::Env; +use library; +use nameutil; use writer::primitives::tabs; use writer::ToCode; -use nameutil; -use std::result::Result as StdResult; use std::fmt; +use std::result::Result as StdResult; -use library::*; -use codegen::subclass::class_impls::SubclassInfo; -use codegen::subclass::virtual_methods; use codegen::general; +use codegen::subclass::virtual_methods; use codegen::sys::fields; +use library::*; +use analysis::general::StatusedTypeId; -pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> -{ +pub struct SubclassInfo { + parents: Vec, + interfaces: Vec, +} + +impl SubclassInfo { + pub fn new(env: &Env, analysis: &analysis::object::Info) -> Self { + let parents = analysis + .supertypes + .iter() + .filter(|t| match *env.library.type_(t.type_id) { + library::Type::Class(..) => true, + _ => false, + }) + .cloned() + .collect::>(); + + let interfaces = analysis + .supertypes + .iter() + .filter(|t| match *env.library.type_(t.type_id) { + library::Type::Interface(..) => true, + _ => false, + }) + .cloned() + .collect::>(); + + info!("{:?}, {:?}", parents, interfaces); + + Self { + parents, + interfaces, + } + } +} + +pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> { try!(general::start_comments(w, &env.config)); try!(general::uses(w, env, &analysis.imports)); // TODO: insert gobject-subclass uses // TODO: insert gobject-subclass uses of parent types - info!("{:?}, {:?}", analysis.c_type, analysis.c_type); - let subclass_info = SubclassInfo::new(env, analysis); generate_impl(w, env, analysis, &subclass_info); @@ -39,57 +72,96 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> generate_any_impl(w, env, analysis, &subclass_info); - generate_base(w, env, analysis, &subclass_info); - Ok(()) } // pub fn generate_impl --> // pub trait ApplicationImpl: ObjectImpl + AnyImpl + 'static { - - - -pub fn generate_impl(w: &mut Write, - env: &Env, - object_analysis: &analysis::object::Info, - subclass_info: &SubclassInfo - ) -> Result<()> { - +pub fn generate_impl( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + subclass_info: &SubclassInfo, +) -> Result<()> { + let mut parents: Vec = subclass_info + .parents + .iter() + .map(|ref p| { + if p.type_id.ns_id == namespaces::MAIN { + p.name.clone() + } else { + format!( + "{krate}_subclass::{name}", + krate = env.namespaces[p.type_id.ns_id].crate_name, + name = p.name + ) + } + }) + .collect(); + + let mut interfaces: Vec = subclass_info + .interfaces + .iter() + .map(|ref p| { + if p.type_id.ns_id == namespaces::MAIN { + p.name.clone() + } else { + format!( + "{krate}_subclass::{name}", + krate = env.namespaces[p.type_id.ns_id].crate_name, + name = p.name + ) + } + }) + .collect(); + + parents.append(&mut interfaces); + + let parent_impls: Vec = parents + .iter() + .map(|ref p| format!("{}Impl + ", p)) + .collect(); + let parent_objs = parent_impls.join(" "); // start impl trait try!(writeln!(w)); try!(writeln!( w, - "pub trait {}: ObjectImpl + AnyImpl + 'static {{", //TODO: use real superclasses chain + "pub trait {}: {} ObjectImpl + AnyImpl + 'static {{", object_analysis.subclass_impl_trait_name, - object_analysis.subclass_base_trait_name + object_analysis.subclass_base_trait_name, + parent_objs )); - for method_analysis in &object_analysis.virtual_methods{ - try!(virtual_methods::generate_default_impl(w, env, object_analysis, method_analysis, subclass_info, 1)); - - + info!("supertypes, {:?}, {:?}", parents, interfaces); + + for method_analysis in &object_analysis.virtual_methods { + try!(virtual_methods::generate_default_impl( + w, + env, + object_analysis, + method_analysis, + subclass_info, + 1 + )); } //end impl trait try!(writeln!(w)); - try!(writeln!( - w, - "}}" - )); + try!(writeln!(w, "}}")); Ok(()) } -pub fn generate_impl_ext(w: &mut Write, - env: &Env, - object_analysis: &analysis::object::Info, - subclass_info: &SubclassInfo - ) -> Result<()> { - +pub fn generate_impl_ext( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + subclass_info: &SubclassInfo, +) -> Result<()> { // start impl trait try!(writeln!(w)); try!(writeln!( @@ -100,21 +172,17 @@ pub fn generate_impl_ext(w: &mut Write, //end impl trait try!(writeln!(w)); - try!(writeln!( - w, - "}}" - )); + try!(writeln!(w, "}}")); Ok(()) } - -pub fn generate_base(w: &mut Write, - env: &Env, - analysis: &analysis::object::Info, - subclass_info: &SubclassInfo - ) -> Result<()> { - +pub fn generate_base( + w: &mut Write, + env: &Env, + analysis: &analysis::object::Info, + subclass_info: &SubclassInfo, +) -> Result<()> { let normal_crate_name = nameutil::crate_name(&env.config.library_name); // start base trait @@ -122,17 +190,12 @@ pub fn generate_base(w: &mut Write, try!(writeln!( w, "pub unsafe trait {}: IsA<{}::{}> + ObjectType {{", - analysis.subclass_base_trait_name, - normal_crate_name, - analysis.name + analysis.subclass_base_trait_name, normal_crate_name, analysis.name )); //end base trait try!(writeln!(w)); - try!(writeln!( - w, - "}}" - )); + try!(writeln!(w, "}}")); Ok(()) } @@ -140,15 +203,17 @@ pub fn generate_base(w: &mut Write, // pub fn generate_base --> // pub unsafe trait ApplicationBase: IsA + ObjectType { - -fn generate_any_impl(w: &mut Write, _env: &Env, analysis: &analysis::object::Info, _subclass_info: &SubclassInfo) -> Result<()> -{ +fn generate_any_impl( + w: &mut Write, + _env: &Env, + analysis: &analysis::object::Info, + _subclass_info: &SubclassInfo, +) -> Result<()> { try!(writeln!(w)); try!(writeln!( w, "any_impl!({}, {});", - analysis.subclass_base_trait_name, - analysis.subclass_impl_trait_name + analysis.subclass_base_trait_name, analysis.subclass_impl_trait_name )); Ok(()) diff --git a/src/codegen/subclass/class_impls.rs b/src/codegen/subclass/class_impls.rs index 2c108005e..ff915379a 100644 --- a/src/codegen/subclass/class_impls.rs +++ b/src/codegen/subclass/class_impls.rs @@ -10,17 +10,6 @@ use library::*; use traits::*; use codegen::subclass::class_impl; -pub struct SubclassInfo{ - -} - -impl SubclassInfo{ - pub fn new(env: &Env, analysis: &analysis::object::Info) -> Self{ - Self{} - } -} - - pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec, traits: &mut Vec) { info!("Generate class traits"); diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 61332705c..255a62b03 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -13,7 +13,7 @@ use codegen::parameter::ToParameter; use std::result::Result as StdResult; use std::fmt; -use codegen::subclass::class_impls::SubclassInfo; +use codegen::subclass::class_impl::SubclassInfo; pub fn generate_default_impl( w: &mut Write, @@ -26,8 +26,6 @@ pub fn generate_default_impl( info!("vfunc: {:?}", method_analysis.name); - - try!(writeln!(w)); try!(write!( w, From 1c6eacb338bdc973e5098331da05e08ee1d7f63d Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 20 May 2018 14:06:42 +0200 Subject: [PATCH 021/122] generate trait-ext impl --- src/codegen/subclass/class_impl.rs | 117 ++++++++++++------------ src/codegen/subclass/virtual_methods.rs | 44 ++++----- 2 files changed, 79 insertions(+), 82 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 50fa2667f..675324436 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -23,8 +23,7 @@ use library::*; use analysis::general::StatusedTypeId; pub struct SubclassInfo { - parents: Vec, - interfaces: Vec, + parents: Vec } impl SubclassInfo { @@ -34,45 +33,51 @@ impl SubclassInfo { .iter() .filter(|t| match *env.library.type_(t.type_id) { library::Type::Class(..) => true, - _ => false, - }) - .cloned() - .collect::>(); - - let interfaces = analysis - .supertypes - .iter() - .filter(|t| match *env.library.type_(t.type_id) { library::Type::Interface(..) => true, _ => false, }) .cloned() .collect::>(); - info!("{:?}, {:?}", parents, interfaces); - Self { parents, - interfaces, } } + + fn parent_names(&self, env: &Env, krate_suffix: &str) -> Vec { + self.parents + .iter() + .map(|ref p| { + if p.type_id.ns_id == namespaces::MAIN { + p.name.clone() + } else { + format!( + "{krate}{krate_suffix}::{name}", + krate = env.namespaces[p.type_id.ns_id].crate_name, + krate_suffix = krate_suffix, + name = p.name + ) + } + }) + .collect() + } + } pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> { try!(general::start_comments(w, &env.config)); try!(general::uses(w, env, &analysis.imports)); // TODO: insert gobject-subclass uses - // TODO: insert gobject-subclass uses of parent types let subclass_info = SubclassInfo::new(env, analysis); - generate_impl(w, env, analysis, &subclass_info); + try!(generate_impl(w, env, analysis, &subclass_info)); - generate_impl_ext(w, env, analysis, &subclass_info); + try!(generate_impl_ext(w, env, analysis, &subclass_info)); - generate_any_impl(w, env, analysis, &subclass_info); + try!(generate_any_impl(w, env, analysis, &subclass_info)); - generate_base(w, env, analysis, &subclass_info); + try!(generate_base(w, env, analysis, &subclass_info)); Ok(()) } @@ -86,39 +91,8 @@ pub fn generate_impl( object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo, ) -> Result<()> { - let mut parents: Vec = subclass_info - .parents - .iter() - .map(|ref p| { - if p.type_id.ns_id == namespaces::MAIN { - p.name.clone() - } else { - format!( - "{krate}_subclass::{name}", - krate = env.namespaces[p.type_id.ns_id].crate_name, - name = p.name - ) - } - }) - .collect(); - let mut interfaces: Vec = subclass_info - .interfaces - .iter() - .map(|ref p| { - if p.type_id.ns_id == namespaces::MAIN { - p.name.clone() - } else { - format!( - "{krate}_subclass::{name}", - krate = env.namespaces[p.type_id.ns_id].crate_name, - name = p.name - ) - } - }) - .collect(); - - parents.append(&mut interfaces); + let mut parents = subclass_info.parent_names(env, "_subclass"); let parent_impls: Vec = parents .iter() @@ -130,13 +104,13 @@ pub fn generate_impl( try!(writeln!(w)); try!(writeln!( w, - "pub trait {}: {} ObjectImpl + AnyImpl + 'static {{", + "pub trait {}:{} ObjectImpl + AnyImpl + 'static {{", object_analysis.subclass_impl_trait_name, object_analysis.subclass_base_trait_name, parent_objs )); - info!("supertypes, {:?}, {:?}", parents, interfaces); + info!("supertypes, {:?}", parents); for method_analysis in &object_analysis.virtual_methods { try!(virtual_methods::generate_default_impl( @@ -162,21 +136,48 @@ pub fn generate_impl_ext( object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo, ) -> Result<()> { - // start impl trait + + + let implext_name = format!("{}Ext", object_analysis.subclass_impl_trait_name); + + // start ext trait def try!(writeln!(w)); try!(writeln!( w, - "pub trait {}Ext {{}}", - object_analysis.subclass_impl_trait_name + "pub trait {} {{}}", + implext_name )); - //end impl trait + //end ext trait def try!(writeln!(w)); try!(writeln!(w, "}}")); + + + // start ext trait impl + let mut parents = subclass_info.parent_names(env, ""); + + let parent_impls: Vec = parents + .iter() + .map(|ref p| format!("+ glib::IsA<{}>", p)) + .collect(); + let parent_objs = parent_impls.join(" "); + + + try!(writeln!( + w, + "impl, T: ObjectType {parents}>> {implext_name} for S {{}}", + impl_name = object_analysis.subclass_impl_trait_name, + parents = parent_objs, + implext_name = implext_name + )); + + Ok(()) } + + pub fn generate_base( w: &mut Write, env: &Env, @@ -185,6 +186,8 @@ pub fn generate_base( ) -> Result<()> { let normal_crate_name = nameutil::crate_name(&env.config.library_name); + + // start base trait try!(writeln!(w)); try!(writeln!( diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 255a62b03..077a68d24 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -34,6 +34,9 @@ pub fn generate_default_impl( method_analysis.name, )); + let parent_name = &method_analysis.parameters.rust_parameters[0].name; + + let mut param_str = String::with_capacity(100); for (pos, par) in method_analysis.parameters.rust_parameters.iter().enumerate() { if pos > 0 { @@ -46,7 +49,7 @@ pub fn generate_default_impl( // insert the templated param if pos == 0{ - param_str.push_str(&format!(", {}: &T", object_analysis.name.to_lowercase())); + param_str.push_str(&format!(", {}: &T", parent_name)); } } @@ -54,23 +57,13 @@ pub fn generate_default_impl( try!(writeln!(w, "{}){{", param_str)); - let mut arg_str = String::with_capacity(100); - for (pos, par) in method_analysis.parameters.rust_parameters.iter().enumerate() { - if pos == 0{ - // skip the first one - continue; - } - if pos > 1 { - arg_str.push_str(", "); - } - arg_str.push_str(&par.name); - } + let arg_str = virtual_method_args(method_analysis, false); try!(writeln!( w, "{}{}.parent_{}({})", tabs(indent+1), - object_analysis.name.to_lowercase(), + parent_name, method_analysis.name, arg_str )); @@ -87,17 +80,18 @@ pub fn generate_default_impl( } -fn generate_args(w: &mut Write, - env: &Env, - object_analysis: &analysis::object::Info, - method_analysys: &analysis::virtual_methods::Info, - subclass_info: &SubclassInfo) -> Result<()> +fn virtual_method_args(method_analysis: &analysis::virtual_methods::Info, include_parent: bool) -> String { - - // for ref param in &method.parameters { - // try!(write!(w, "{}:{}", param.name, param.typ.full_name(&env.library))); - // - // } - - Ok(()) + let mut arg_str = String::with_capacity(100); + for (pos, par) in method_analysis.parameters.rust_parameters.iter().enumerate() { + if !include_parent && pos == 0{ + // skip the first one, + continue; + } + if pos > 1 { + arg_str.push_str(", "); + } + arg_str.push_str(&par.name); + } + arg_str } From 9d491824fc38db0c46b00db318ac70bc75d2086b Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 21 May 2018 09:41:21 +0200 Subject: [PATCH 022/122] start generating base impl --- src/codegen/subclass/class_impl.rs | 32 +++++++++--- src/codegen/subclass/virtual_methods.rs | 69 +++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 8 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 675324436..ebdef6bf9 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -96,9 +96,9 @@ pub fn generate_impl( let parent_impls: Vec = parents .iter() - .map(|ref p| format!("{}Impl + ", p)) + .map(|ref p| format!(" {}Impl +", p)) .collect(); - let parent_objs = parent_impls.join(" "); + let parent_objs = parent_impls.join(""); // start impl trait try!(writeln!(w)); @@ -153,9 +153,8 @@ pub fn generate_impl_ext( try!(writeln!(w, "}}")); - // start ext trait impl - let mut parents = subclass_info.parent_names(env, ""); + let parents = subclass_info.parent_names(env, ""); let parent_impls: Vec = parents .iter() @@ -181,21 +180,38 @@ pub fn generate_impl_ext( pub fn generate_base( w: &mut Write, env: &Env, - analysis: &analysis::object::Info, + object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo, ) -> Result<()> { - let normal_crate_name = nameutil::crate_name(&env.config.library_name); + let parents = subclass_info.parent_names(env, ""); + let parent_impls: Vec = parents + .iter() + .map(|ref p| format!("+ glib::IsA<{}>", p)) + .collect(); + let parent_objs = parent_impls.join(" "); // start base trait try!(writeln!(w)); try!(writeln!( w, - "pub unsafe trait {}: IsA<{}::{}> + ObjectType {{", - analysis.subclass_base_trait_name, normal_crate_name, analysis.name + "pub unsafe trait {}: ObjectType {}{{", + object_analysis.subclass_base_trait_name, + parent_objs )); + for method_analysis in &object_analysis.virtual_methods { + try!(virtual_methods::generate_base_impl( + w, + env, + object_analysis, + method_analysis, + subclass_info, + 1 + )); + } + //end base trait try!(writeln!(w)); try!(writeln!(w, "}}")); diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 077a68d24..0b4ddd236 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -95,3 +95,72 @@ fn virtual_method_args(method_analysis: &analysis::virtual_methods::Info, includ } arg_str } + + +pub fn generate_base_impl( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + method_analysis: &analysis::virtual_methods::Info, + subclass_info: &SubclassInfo, + indent: usize, +) -> Result<()> { + info!("vfunc: {:?}", method_analysis.name); + + + try!(writeln!(w)); + try!(write!( + w, + "{}fn parent_{}(", + tabs(indent), + method_analysis.name, + )); + + let mut param_str = String::with_capacity(100); + for (pos, par) in method_analysis.parameters.rust_parameters.iter().enumerate() { + if pos > 0 { + param_str.push_str(", "); + } + + let c_par = &method_analysis.parameters.c_parameters[par.ind_c]; + let s = c_par.to_parameter(env, &method_analysis.bounds); + param_str.push_str(&s); + + } + + + try!(writeln!(w, "{}){{", param_str)); + + + + // fn parent_startup(&self) { + // unsafe { + // let klass = self.get_class(); + // let parent_klass = (*klass).get_parent_class() as *const gio_ffi::GApplicationClass; + // (*parent_klass) + // .startup + // .map(|f| f(self.to_glib_none().0)) + // .unwrap_or(()) + // } + // } + + + // try!(writeln!( + // w, + // "{}{}.parent_{}({})", + // tabs(indent+1), + // parent_name, + // method_analysis.name, + // arg_str + // )); + + + try!(writeln!( + w, + "{}}}", + tabs(indent), + )); + + Ok(()) + +} From d96c184160e6ca27815cde5d8e36e2efcbc77261 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 21 May 2018 21:02:27 +0200 Subject: [PATCH 023/122] start figuring out how builder works --- src/codegen/subclass/mod.rs | 1 + src/codegen/subclass/virtual_method_bodies.rs | 81 +++++++++++++++++++ src/codegen/subclass/virtual_methods.rs | 7 ++ 3 files changed, 89 insertions(+) create mode 100644 src/codegen/subclass/virtual_method_bodies.rs diff --git a/src/codegen/subclass/mod.rs b/src/codegen/subclass/mod.rs index 431d2c323..252992325 100644 --- a/src/codegen/subclass/mod.rs +++ b/src/codegen/subclass/mod.rs @@ -4,6 +4,7 @@ mod object; mod class_impls; mod class_impl; mod virtual_methods; +mod virtual_method_bodies; use codegen::generate_single_version_file; diff --git a/src/codegen/subclass/virtual_method_bodies.rs b/src/codegen/subclass/virtual_method_bodies.rs new file mode 100644 index 000000000..a557f6645 --- /dev/null +++ b/src/codegen/subclass/virtual_method_bodies.rs @@ -0,0 +1,81 @@ +use analysis::conversion_type::ConversionType; +use analysis::functions::{AsyncTrampoline, find_index_to_ignore}; +use analysis::function_parameters::CParameter as AnalysisCParameter; +use analysis::function_parameters::{Transformation, TransformationType}; +use analysis::out_parameters::Mode; +use analysis::namespaces; +use analysis::return_value; +use analysis::rust_type::rust_type; +use analysis::safety_assertion_mode::SafetyAssertionMode; +use chunk::{Chunk, Param, TupleMode}; +use chunk::parameter_ffi_call_out; +use env::Env; +use library::{self, ParameterDirection}; +use nameutil; + + +#[derive(Default)] +pub struct BaseBuilder { + method_name: String, + trampoline_name: String, + in_trait: bool, + function_type_string: String, +} + +impl BaseBuilder { + pub fn new() -> BaseBuilder { + Default::default() + } + + // pub fn method_name(&mut self, name: &str) -> &mut BaseBuilder { + // self.signal_name = name.into(); + // self + // } + + pub fn trampoline_name(&mut self, name: &str) -> &mut BaseBuilder { + self.trampoline_name = name.into(); + self + } + + pub fn in_trait(&mut self, value: bool) -> &mut BaseBuilder { + self.in_trait = value; + self + } + + pub fn function_type_string(&mut self, type_: &str) -> &mut BaseBuilder { + self.function_type_string = type_.into(); + self + } + + pub fn generate(&self, env: &Env) -> Chunk { + let mut body = Vec::new(); + + + // body.push(self.let_func()); + // body.push(self.connect()); + + let unsafe_ = Chunk::Unsafe(body); + + let mut chunks = Vec::new(); + chunks.push(unsafe_); + Chunk::BlockHalf(chunks) + } + + // fn let_func(&self) -> Chunk { + // let type_ = format!("Box_>", self.function_type_string); + // Chunk::Let { + // name: "f".to_owned(), + // is_mut: false, + // value: Box::new(Chunk::Custom("Box_::new(Box_::new(f))".to_owned())), + // type_: Some(Box::new(Chunk::Custom(type_))), + // } + // } + + // fn connect(&self) -> Chunk { + // Chunk::Connect { + // signal: self.signal_name.clone(), + // trampoline: self.trampoline_name.clone(), + // in_trait: self.in_trait, + // } + // } +} diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 0b4ddd236..4eced7735 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -14,6 +14,7 @@ use std::result::Result as StdResult; use std::fmt; use codegen::subclass::class_impl::SubclassInfo; +use codegen::subclass::virtual_method_bodies::BaseBuilder; pub fn generate_default_impl( w: &mut Write, @@ -131,6 +132,12 @@ pub fn generate_base_impl( try!(writeln!(w, "{}){{", param_str)); + let builder = BaseBuilder::new(); + let body = builder.generate(env).to_code(env); + for s in body { + try!(writeln!(w, "{}{}", tabs(indent), s)); + } + // fn parent_startup(&self) { From f6d5f5a53f48a7a1060df4034ef80a5ec93f3f62 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 22 May 2018 19:49:25 +0200 Subject: [PATCH 024/122] minor bit of refactoring --- src/codegen/subclass/mod.rs | 2 +- src/codegen/subclass/virtual_method_bodies.rs | 81 ------------- .../subclass/virtual_method_body_chunks.rs | 107 ++++++++++++++++ src/codegen/subclass/virtual_methods.rs | 114 +++++++++++++----- 4 files changed, 192 insertions(+), 112 deletions(-) delete mode 100644 src/codegen/subclass/virtual_method_bodies.rs create mode 100644 src/codegen/subclass/virtual_method_body_chunks.rs diff --git a/src/codegen/subclass/mod.rs b/src/codegen/subclass/mod.rs index 252992325..968aed0a0 100644 --- a/src/codegen/subclass/mod.rs +++ b/src/codegen/subclass/mod.rs @@ -4,7 +4,7 @@ mod object; mod class_impls; mod class_impl; mod virtual_methods; -mod virtual_method_bodies; +mod virtual_method_body_chunks; use codegen::generate_single_version_file; diff --git a/src/codegen/subclass/virtual_method_bodies.rs b/src/codegen/subclass/virtual_method_bodies.rs deleted file mode 100644 index a557f6645..000000000 --- a/src/codegen/subclass/virtual_method_bodies.rs +++ /dev/null @@ -1,81 +0,0 @@ -use analysis::conversion_type::ConversionType; -use analysis::functions::{AsyncTrampoline, find_index_to_ignore}; -use analysis::function_parameters::CParameter as AnalysisCParameter; -use analysis::function_parameters::{Transformation, TransformationType}; -use analysis::out_parameters::Mode; -use analysis::namespaces; -use analysis::return_value; -use analysis::rust_type::rust_type; -use analysis::safety_assertion_mode::SafetyAssertionMode; -use chunk::{Chunk, Param, TupleMode}; -use chunk::parameter_ffi_call_out; -use env::Env; -use library::{self, ParameterDirection}; -use nameutil; - - -#[derive(Default)] -pub struct BaseBuilder { - method_name: String, - trampoline_name: String, - in_trait: bool, - function_type_string: String, -} - -impl BaseBuilder { - pub fn new() -> BaseBuilder { - Default::default() - } - - // pub fn method_name(&mut self, name: &str) -> &mut BaseBuilder { - // self.signal_name = name.into(); - // self - // } - - pub fn trampoline_name(&mut self, name: &str) -> &mut BaseBuilder { - self.trampoline_name = name.into(); - self - } - - pub fn in_trait(&mut self, value: bool) -> &mut BaseBuilder { - self.in_trait = value; - self - } - - pub fn function_type_string(&mut self, type_: &str) -> &mut BaseBuilder { - self.function_type_string = type_.into(); - self - } - - pub fn generate(&self, env: &Env) -> Chunk { - let mut body = Vec::new(); - - - // body.push(self.let_func()); - // body.push(self.connect()); - - let unsafe_ = Chunk::Unsafe(body); - - let mut chunks = Vec::new(); - chunks.push(unsafe_); - Chunk::BlockHalf(chunks) - } - - // fn let_func(&self) -> Chunk { - // let type_ = format!("Box_>", self.function_type_string); - // Chunk::Let { - // name: "f".to_owned(), - // is_mut: false, - // value: Box::new(Chunk::Custom("Box_::new(Box_::new(f))".to_owned())), - // type_: Some(Box::new(Chunk::Custom(type_))), - // } - // } - - // fn connect(&self) -> Chunk { - // Chunk::Connect { - // signal: self.signal_name.clone(), - // trampoline: self.trampoline_name.clone(), - // in_trait: self.in_trait, - // } - // } -} diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs new file mode 100644 index 000000000..586da693a --- /dev/null +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -0,0 +1,107 @@ +use analysis::conversion_type::ConversionType; +use analysis::functions::{AsyncTrampoline, find_index_to_ignore}; +use analysis::function_parameters::CParameter as AnalysisCParameter; +use analysis::function_parameters::{Transformation, TransformationType}; +use analysis::out_parameters::Mode; +use analysis::namespaces; +use analysis::return_value; +use analysis::rust_type::rust_type; +use analysis::safety_assertion_mode::SafetyAssertionMode; +use analysis; +use chunk::{Chunk, Param, TupleMode}; +use chunk::parameter_ffi_call_out; +use env::Env; +use library::{self, ParameterDirection}; +use nameutil; + + +#[derive(Default)] +pub struct Builder { + object_class_c_type: String, + ffi_crate_name: String +} + +impl Builder { + pub fn new() -> Builder { + Default::default() + } + + pub fn object_class_c_type(&mut self, c_class_type: &str) -> &mut Builder { + self.object_class_c_type = c_class_type.into(); + self + } + + pub fn ffi_crate_name(&mut self, ns: &str) -> &mut Builder { + self.ffi_crate_name = ns.into(); + self + } + // + // pub fn in_trait(&mut self, value: bool) -> &mut Builder { + // self.in_trait = value; + // self + // } + // + // pub fn function_type_string(&mut self, type_: &str) -> &mut Builder { + // self.function_type_string = type_.into(); + // self + // } + + pub fn generate(&self, env: &Env) -> Chunk { + let mut body = Vec::new(); + + + body.push(self.let_klass()); + body.push(self.let_parent_klass()); + + + // fn parent_startup(&self) { + // unsafe { + // let klass = self.get_class(); + // let parent_klass = (*klass).get_parent_class() as *const gio_ffi::GApplicationClass; + // (*parent_klass) + // .startup + // .map(|f| f(self.to_glib_none().0)) + // .unwrap_or(()) + // } + // } + + + let unsafe_ = Chunk::Unsafe(body); + + let mut chunks = Vec::new(); + chunks.push(unsafe_); + Chunk::Chunks(chunks) + } + + fn let_klass(&self) -> Chunk { + Chunk::Let { + name: "klass".to_owned(), + is_mut: false, + value: Box::new(Chunk::Custom("self.get_class()".to_owned())), + type_: None + } + } + + fn let_parent_klass(&self) -> Chunk { + Chunk::Let { + name: "parent_klass".to_owned(), + is_mut: false, + value: Box::new( + Chunk::Cast { + name: "(*klass).get_parent_class()".to_owned(), + type_: format!("*const {}::{}", self.ffi_crate_name, self.object_class_c_type).to_owned() + }), + type_: None + } + } + + //let parent_klass = (*klass).get_parent_class() as *const gio_ffi::GApplicationClass; + + // fn connect(&self) -> Chunk { + // Chunk::Connect { + // signal: self.signal_name.clone(), + // trampoline: self.trampoline_name.clone(), + // in_trait: self.in_trait, + // } + // } +} diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 4eced7735..64674b67c 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -2,19 +2,21 @@ use std::io::{Result, Write}; use library; use analysis; -use analysis::bounds::Bounds; +use analysis::bounds::{BoundType, Bounds}; +use analysis::ref_mode::RefMode; use analysis::functions::Visibility; use analysis::namespaces; use env::Env; use writer::primitives::tabs; use writer::ToCode; use codegen::parameter::ToParameter; +use chunk::{ffi_function_todo, Chunk}; use std::result::Result as StdResult; use std::fmt; use codegen::subclass::class_impl::SubclassInfo; -use codegen::subclass::virtual_method_bodies::BaseBuilder; +use codegen::subclass::virtual_method_body_chunks::Builder; pub fn generate_default_impl( w: &mut Write, @@ -80,6 +82,71 @@ pub fn generate_default_impl( } +// fn func_parameters( +// env: &Env, +// analysis: &analysis::virtual_methods::Info, +// bound_replace: Option<(char, &str)>, +// closure: bool, +// ) -> String { +// let mut param_str = String::with_capacity(100); +// +// for (pos, par) in analysis.parameters.rust_parameters.iter().enumerate() { +// if pos > 0 { +// param_str.push_str(", "); +// if !closure { +// param_str.push_str(&format!("{}: ", par.name)); +// } +// } else if !closure { +// param_str.push_str("&self"); +// continue; +// } +// +// let s = func_parameter(env, par, &analysis.bounds, bound_replace); +// param_str.push_str(&s); +// } +// +// param_str +// } +// +// fn func_parameter( +// env: &Env, +// par: &RustParameter, +// bounds: &Bounds, +// bound_replace: Option<(char, &str)>, +// ) -> String { +// //TODO: restore mutable support +// //let mut_str = if par.ref_mode == RefMode::ByRefMut { "mut " } else { "" }; +// let mut_str = ""; +// let ref_mode = if par.ref_mode == RefMode::ByRefMut { +// RefMode::ByRef +// } else { +// par.ref_mode +// }; +// +// match bounds.get_parameter_alias_info(&par.name) { +// Some((t, bound_type)) => match bound_type { +// BoundType::NoWrapper => unreachable!(), +// BoundType::IsA(_) => if *par.nullable { +// format!("&Option<{}{}>", mut_str, t) +// } else if let Some((from, to)) = bound_replace { +// if from == t { +// format!("&{}{}", mut_str, to) +// } else { +// format!("&{}{}", mut_str, t) +// } +// } else { +// format!("&{}{}", mut_str, t) +// }, +// BoundType::AsRef(_) | BoundType::Into(_, _) => t.to_string(), +// }, +// None => { +// let rust_type = +// parameter_rust_type(env, par.typ, par.direction, par.nullable, ref_mode); +// rust_type.into_string().replace("Option<&", "&Option<") +// } +// } +// } + fn virtual_method_args(method_analysis: &analysis::virtual_methods::Info, include_parent: bool) -> String { @@ -126,42 +193,16 @@ pub fn generate_base_impl( let c_par = &method_analysis.parameters.c_parameters[par.ind_c]; let s = c_par.to_parameter(env, &method_analysis.bounds); param_str.push_str(&s); - } try!(writeln!(w, "{}){{", param_str)); - let builder = BaseBuilder::new(); - let body = builder.generate(env).to_code(env); + let body = base_impl_body_chunk(env, object_analysis, method_analysis, subclass_info).to_code(env); for s in body { - try!(writeln!(w, "{}{}", tabs(indent), s)); + try!(writeln!(w, "{}{}", tabs(indent+1), s)); } - - - // fn parent_startup(&self) { - // unsafe { - // let klass = self.get_class(); - // let parent_klass = (*klass).get_parent_class() as *const gio_ffi::GApplicationClass; - // (*parent_klass) - // .startup - // .map(|f| f(self.to_glib_none().0)) - // .unwrap_or(()) - // } - // } - - - // try!(writeln!( - // w, - // "{}{}.parent_{}({})", - // tabs(indent+1), - // parent_name, - // method_analysis.name, - // arg_str - // )); - - try!(writeln!( w, "{}}}", @@ -169,5 +210,18 @@ pub fn generate_base_impl( )); Ok(()) +} + +pub fn base_impl_body_chunk(env: &Env, + object_analysis: &analysis::object::Info, + method_analysis: &analysis::virtual_methods::Info, + subclass_info: &SubclassInfo + ) -> Chunk +{ + let mut builder = Builder::new(); + builder.object_class_c_type(object_analysis.c_class_type.as_ref().unwrap()) + .ffi_crate_name(&env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name); + + builder.generate(env) } From 2c6ac918295d79cdf574e814587d08b166d3cce6 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 23 May 2018 08:08:17 +0200 Subject: [PATCH 025/122] generate base impl --- src/chunk/chunk.rs | 4 + src/codegen/function_body_chunk.rs | 8 +- .../subclass/virtual_method_body_chunks.rs | 121 ++++++++++++++---- src/codegen/subclass/virtual_methods.rs | 98 +++++--------- src/writer/to_code.rs | 10 +- 5 files changed, 146 insertions(+), 95 deletions(-) diff --git a/src/chunk/chunk.rs b/src/chunk/chunk.rs index 382eb1fbb..270b4bee3 100644 --- a/src/chunk/chunk.rs +++ b/src/chunk/chunk.rs @@ -71,6 +71,10 @@ pub enum Chunk { func_name: String, arguments: Vec, }, + Closure{ + arguments: Vec, + body: Box, + } } pub struct Param { diff --git a/src/codegen/function_body_chunk.rs b/src/codegen/function_body_chunk.rs index 0de33f2b1..b9b3f9fe3 100644 --- a/src/codegen/function_body_chunk.rs +++ b/src/codegen/function_body_chunk.rs @@ -14,7 +14,7 @@ use library::{self, ParameterDirection}; use nameutil; #[derive(Clone, Debug)] -enum Parameter { +pub enum Parameter { //Used to separate in and out parameters in `add_in_array_lengths` // and `generate_func_parameters` In, @@ -25,7 +25,7 @@ enum Parameter { } #[derive(Clone, Debug, Eq, PartialEq)] -enum OutMemMode { +pub enum OutMemMode { Uninitialized, UninitializedNamed(String), NullPtr, @@ -33,7 +33,7 @@ enum OutMemMode { } #[derive(Clone, Default)] -struct ReturnValue { +pub struct ReturnValue { pub ret: return_value::Info, } @@ -588,7 +588,7 @@ fn c_type_mem_mode_lib(env: &Env, typ: library::TypeId, caller_allocates: bool, } } -fn c_type_mem_mode(env: &Env, parameter: &AnalysisCParameter) -> OutMemMode { +pub fn c_type_mem_mode(env: &Env, parameter: &AnalysisCParameter) -> OutMemMode { c_type_mem_mode_lib(env, parameter.typ, parameter.caller_allocates, parameter.transfer) } diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index 586da693a..98dac0524 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -1,3 +1,4 @@ +use codegen::function_body_chunk::Parameter::Out; use analysis::conversion_type::ConversionType; use analysis::functions::{AsyncTrampoline, find_index_to_ignore}; use analysis::function_parameters::CParameter as AnalysisCParameter; @@ -13,12 +14,22 @@ use chunk::parameter_ffi_call_out; use env::Env; use library::{self, ParameterDirection}; use nameutil; +use writer::ToCode; + +use codegen::parameter::*; +use codegen::function_body_chunk::{ReturnValue, Parameter, c_type_mem_mode}; #[derive(Default)] pub struct Builder { object_class_c_type: String, - ffi_crate_name: String + ffi_crate_name: String, + method_name: String, + parameters: Vec, + transformations: Vec, + ret: ReturnValue, + outs_as_return: bool, + outs_mode: Mode } impl Builder { @@ -35,35 +46,59 @@ impl Builder { self.ffi_crate_name = ns.into(); self } - // - // pub fn in_trait(&mut self, value: bool) -> &mut Builder { - // self.in_trait = value; - // self - // } - // - // pub fn function_type_string(&mut self, type_: &str) -> &mut Builder { - // self.function_type_string = type_.into(); - // self - // } - pub fn generate(&self, env: &Env) -> Chunk { + pub fn method_name(&mut self, name: &str) -> &mut Builder { + self.method_name = name.into(); + self + } + + pub fn ret(&mut self, ret: &return_value::Info) -> &mut Builder { + self.ret = ReturnValue { ret: ret.clone() }; + self + } + pub fn parameter(&mut self) -> &mut Builder { + self.parameters.push(Parameter::In); + self + } + pub fn out_parameter(&mut self, env: &Env, parameter: &AnalysisCParameter) -> &mut Builder { + let mem_mode = c_type_mem_mode(env, parameter); + self.parameters.push(Parameter::Out { + parameter: parameter_ffi_call_out::Parameter::new(parameter), + mem_mode, + }); + self.outs_as_return = true; + self + } + + pub fn transformations(&mut self, transformations: &[Transformation]) -> &mut Builder { + self.transformations = transformations.to_owned(); + self + } + + pub fn outs_mode(&mut self, mode: Mode) -> &mut Builder { + self.outs_mode = mode; + self + } + + pub fn generate_default_impl(&self, env: &Env) -> Chunk { + //TODO + let mut chunks = Vec::new(); + Chunk::Chunks(chunks) + } + + pub fn generate_base_impl(&self, env: &Env) -> Chunk { let mut body = Vec::new(); body.push(self.let_klass()); body.push(self.let_parent_klass()); - - // fn parent_startup(&self) { - // unsafe { - // let klass = self.get_class(); - // let parent_klass = (*klass).get_parent_class() as *const gio_ffi::GApplicationClass; - // (*parent_klass) - // .startup - // .map(|f| f(self.to_glib_none().0)) - // .unwrap_or(()) - // } - // } + body.push(Chunk::Custom("(*parent_klass)".to_owned())); + body.push(Chunk::Custom(format!(".{}", self.method_name).to_owned())); + let mut args = Vec::new(); + args.push(self.base_impl_body_chunk()); + body.push(Chunk::Call{ func_name: ".map".to_owned(), arguments: args}); + body.push(Chunk::Custom(".unwrap_or(())".to_owned())); let unsafe_ = Chunk::Unsafe(body); @@ -73,6 +108,26 @@ impl Builder { Chunk::Chunks(chunks) } + fn base_impl_body_chunk(&self) -> Chunk { + + Chunk::Closure{ arguments: vec![Chunk::Custom("f".to_owned())], + body: Box::new(Chunk::Call{ + func_name: "f".to_owned(), + arguments: self.generate_func_parameters() + }) + } + + + + // (*parent_klass) + // .startup + // .map(|f| f(self.to_glib_none().0)) + // .unwrap_or(()) + // } + // } + } + + fn let_klass(&self) -> Chunk { Chunk::Let { name: "klass".to_owned(), @@ -95,6 +150,26 @@ impl Builder { } } + fn generate_func_parameters(&self) -> Vec { + let mut params = Vec::new(); + for trans in &self.transformations { + if !trans.transformation_type.is_to_glib() { + continue; + } + let par = &self.parameters[trans.ind_c]; + let chunk = match par { + In => Chunk::FfiCallParameter { + transformation_type: trans.transformation_type.clone(), + }, + Out { ref parameter, .. } => Chunk::FfiCallOutParameter { + par: parameter.clone(), + }, + }; + params.push(chunk); + } + params + } + //let parent_klass = (*klass).get_parent_class() as *const gio_ffi::GApplicationClass; // fn connect(&self) -> Chunk { diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 64674b67c..1acbcdc66 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -82,70 +82,19 @@ pub fn generate_default_impl( } -// fn func_parameters( -// env: &Env, -// analysis: &analysis::virtual_methods::Info, -// bound_replace: Option<(char, &str)>, -// closure: bool, -// ) -> String { -// let mut param_str = String::with_capacity(100); -// -// for (pos, par) in analysis.parameters.rust_parameters.iter().enumerate() { -// if pos > 0 { -// param_str.push_str(", "); -// if !closure { -// param_str.push_str(&format!("{}: ", par.name)); -// } -// } else if !closure { -// param_str.push_str("&self"); -// continue; -// } -// -// let s = func_parameter(env, par, &analysis.bounds, bound_replace); -// param_str.push_str(&s); -// } -// -// param_str -// } -// -// fn func_parameter( -// env: &Env, -// par: &RustParameter, -// bounds: &Bounds, -// bound_replace: Option<(char, &str)>, -// ) -> String { -// //TODO: restore mutable support -// //let mut_str = if par.ref_mode == RefMode::ByRefMut { "mut " } else { "" }; -// let mut_str = ""; -// let ref_mode = if par.ref_mode == RefMode::ByRefMut { -// RefMode::ByRef -// } else { -// par.ref_mode -// }; -// -// match bounds.get_parameter_alias_info(&par.name) { -// Some((t, bound_type)) => match bound_type { -// BoundType::NoWrapper => unreachable!(), -// BoundType::IsA(_) => if *par.nullable { -// format!("&Option<{}{}>", mut_str, t) -// } else if let Some((from, to)) = bound_replace { -// if from == t { -// format!("&{}{}", mut_str, to) -// } else { -// format!("&{}{}", mut_str, t) -// } -// } else { -// format!("&{}{}", mut_str, t) -// }, -// BoundType::AsRef(_) | BoundType::Into(_, _) => t.to_string(), -// }, -// None => { -// let rust_type = -// parameter_rust_type(env, par.typ, par.direction, par.nullable, ref_mode); -// rust_type.into_string().replace("Option<&", "&Option<") -// } -// } -// } +pub fn default_impl_body_chunk(env: &Env, + object_analysis: &analysis::object::Info, + method_analysis: &analysis::virtual_methods::Info, + subclass_info: &SubclassInfo + ) -> Chunk +{ + let mut builder = Builder::new(); + builder.object_class_c_type(object_analysis.c_class_type.as_ref().unwrap()) + .ffi_crate_name(&env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name); + + + builder.generate_default_impl(env) +} fn virtual_method_args(method_analysis: &analysis::virtual_methods::Info, include_parent: bool) -> String @@ -219,9 +168,24 @@ pub fn base_impl_body_chunk(env: &Env, ) -> Chunk { let mut builder = Builder::new(); - builder.object_class_c_type(object_analysis.c_class_type.as_ref().unwrap()) - .ffi_crate_name(&env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name); + let outs_as_return = !method_analysis.outs.is_empty(); - builder.generate(env) + builder.object_class_c_type(object_analysis.c_class_type.as_ref().unwrap()) + .ffi_crate_name(&env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name) + .method_name(&method_analysis.name) + .ret(&method_analysis.ret) + .transformations(&method_analysis.parameters.transformations) + .outs_mode(method_analysis.outs.mode); + + for par in &method_analysis.parameters.c_parameters { + if outs_as_return && method_analysis.outs.iter().any(|p| p.name == par.name) { + builder.out_parameter(env, par); + } else { + builder.parameter(); + } + } + + + builder.generate_base_impl(env) } diff --git a/src/writer/to_code.rs b/src/writer/to_code.rs index 67f3f2ee0..ce9849429 100644 --- a/src/writer/to_code.rs +++ b/src/writer/to_code.rs @@ -163,8 +163,16 @@ impl ToCode for Chunk { .flat_map(|arg| arg.to_code(env)) .collect(); let s = format_block_one_line("(", ")", &args, "", ","); - vec![format!("{}{};", func_name, s)] + vec![format!("{}{}", func_name, s)] //TODO: removed the trailing ';' here }, + Closure { ref arguments, ref body } => { + let args: Vec<_> = arguments.iter() + .flat_map(|arg| arg.to_code(env)) + .collect(); + let s = format_block_one_line("|", "|", &args, "", ""); + let code = format_block_one_line("{", "}", &body.to_code(env), " ", " "); + vec![format!("{}{}", s, code)] + } } } } From 935c24ce9ed5c644626f534b6f897421a22b8359 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 24 May 2018 08:48:26 +0200 Subject: [PATCH 026/122] generate ext trait --- src/chunk/chunk.rs | 1 + src/codegen/function_body_chunk.rs | 1 + src/codegen/subclass/class_impl.rs | 50 ++++++++++++- .../subclass/virtual_method_body_chunks.rs | 73 ++++++++----------- src/codegen/subclass/virtual_methods.rs | 69 +++++++++++++++++- src/writer/to_code.rs | 5 +- 6 files changed, 149 insertions(+), 50 deletions(-) diff --git a/src/chunk/chunk.rs b/src/chunk/chunk.rs index 270b4bee3..a1525b019 100644 --- a/src/chunk/chunk.rs +++ b/src/chunk/chunk.rs @@ -70,6 +70,7 @@ pub enum Chunk { Call { func_name: String, arguments: Vec, + as_return: bool }, Closure{ arguments: Vec, diff --git a/src/codegen/function_body_chunk.rs b/src/codegen/function_body_chunk.rs index b9b3f9fe3..154d1dc03 100644 --- a/src/codegen/function_body_chunk.rs +++ b/src/codegen/function_body_chunk.rs @@ -234,6 +234,7 @@ impl Builder { Chunk::Call { func_name: "callback".to_string(), arguments: vec![Chunk::Name("result".to_string())], + as_return: false } ); diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index ebdef6bf9..5c33cf354 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -79,6 +79,9 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> try!(generate_base(w, env, analysis, &subclass_info)); + try!(generate_ext(w, env, analysis, &subclass_info)); + + Ok(()) } @@ -225,15 +228,58 @@ pub fn generate_base( fn generate_any_impl( w: &mut Write, _env: &Env, - analysis: &analysis::object::Info, + object_analysis: &analysis::object::Info, _subclass_info: &SubclassInfo, ) -> Result<()> { try!(writeln!(w)); try!(writeln!( w, "any_impl!({}, {});", - analysis.subclass_base_trait_name, analysis.subclass_impl_trait_name + object_analysis.subclass_base_trait_name, + object_analysis.subclass_impl_trait_name + )); + + Ok(()) +} + + +fn generate_ext( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + subclass_info: &SubclassInfo, +) -> Result<()> { + + if object_analysis.class_type.is_none(){ + return Ok(()); + } + + + let classext_name = format!("{}Ext", object_analysis.class_type.as_ref().unwrap()); + + // start base trait + try!(writeln!(w)); + try!(writeln!( + w, + "pub unsafe trait {} + where + T::ImplType: {}{{", + classext_name, + object_analysis.subclass_base_trait_name, + object_analysis.subclass_impl_trait_name + )); + + + try!(virtual_methods::generate_override_vfuncs( + w, + env, + object_analysis, + subclass_info, + 1 )); + try!(writeln!(w)); + try!(writeln!(w, "}}")); + Ok(()) } diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index 98dac0524..4bb9e7c73 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -1,24 +1,23 @@ -use codegen::function_body_chunk::Parameter::Out; +use analysis; use analysis::conversion_type::ConversionType; -use analysis::functions::{AsyncTrampoline, find_index_to_ignore}; use analysis::function_parameters::CParameter as AnalysisCParameter; use analysis::function_parameters::{Transformation, TransformationType}; -use analysis::out_parameters::Mode; +use analysis::functions::{find_index_to_ignore, AsyncTrampoline}; use analysis::namespaces; +use analysis::out_parameters::Mode; use analysis::return_value; use analysis::rust_type::rust_type; use analysis::safety_assertion_mode::SafetyAssertionMode; -use analysis; -use chunk::{Chunk, Param, TupleMode}; use chunk::parameter_ffi_call_out; +use chunk::{Chunk, Param, TupleMode}; +use codegen::function_body_chunk::Parameter::Out; use env::Env; use library::{self, ParameterDirection}; use nameutil; use writer::ToCode; +use codegen::function_body_chunk::{c_type_mem_mode, Parameter, ReturnValue}; use codegen::parameter::*; -use codegen::function_body_chunk::{ReturnValue, Parameter, c_type_mem_mode}; - #[derive(Default)] pub struct Builder { @@ -29,7 +28,7 @@ pub struct Builder { transformations: Vec, ret: ReturnValue, outs_as_return: bool, - outs_mode: Mode + outs_mode: Mode, } impl Builder { @@ -89,7 +88,6 @@ impl Builder { pub fn generate_base_impl(&self, env: &Env) -> Chunk { let mut body = Vec::new(); - body.push(self.let_klass()); body.push(self.let_parent_klass()); @@ -97,10 +95,13 @@ impl Builder { body.push(Chunk::Custom(format!(".{}", self.method_name).to_owned())); let mut args = Vec::new(); args.push(self.base_impl_body_chunk()); - body.push(Chunk::Call{ func_name: ".map".to_owned(), arguments: args}); + body.push(Chunk::Call { + func_name: ".map".to_owned(), + arguments: args, + as_return: true, + }); body.push(Chunk::Custom(".unwrap_or(())".to_owned())); - let unsafe_ = Chunk::Unsafe(body); let mut chunks = Vec::new(); @@ -108,32 +109,24 @@ impl Builder { Chunk::Chunks(chunks) } - fn base_impl_body_chunk(&self) -> Chunk { - Chunk::Closure{ arguments: vec![Chunk::Custom("f".to_owned())], - body: Box::new(Chunk::Call{ - func_name: "f".to_owned(), - arguments: self.generate_func_parameters() - }) + fn base_impl_body_chunk(&self) -> Chunk { + Chunk::Closure { + arguments: vec![Chunk::Custom("f".to_owned())], + body: Box::new(Chunk::Call { + func_name: "f".to_owned(), + arguments: self.generate_func_parameters(), + as_return: true, + }), } - - - - // (*parent_klass) - // .startup - // .map(|f| f(self.to_glib_none().0)) - // .unwrap_or(()) - // } - // } } - fn let_klass(&self) -> Chunk { Chunk::Let { name: "klass".to_owned(), is_mut: false, value: Box::new(Chunk::Custom("self.get_class()".to_owned())), - type_: None + type_: None, } } @@ -141,12 +134,14 @@ impl Builder { Chunk::Let { name: "parent_klass".to_owned(), is_mut: false, - value: Box::new( - Chunk::Cast { - name: "(*klass).get_parent_class()".to_owned(), - type_: format!("*const {}::{}", self.ffi_crate_name, self.object_class_c_type).to_owned() - }), - type_: None + value: Box::new(Chunk::Cast { + name: "(*klass).get_parent_class()".to_owned(), + type_: format!( + "*const {}::{}", + self.ffi_crate_name, self.object_class_c_type + ).to_owned(), + }), + type_: None, } } @@ -169,14 +164,4 @@ impl Builder { } params } - - //let parent_klass = (*klass).get_parent_class() as *const gio_ffi::GApplicationClass; - - // fn connect(&self) -> Chunk { - // Chunk::Connect { - // signal: self.signal_name.clone(), - // trampoline: self.trampoline_name.clone(), - // in_trait: self.in_trait, - // } - // } } diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 1acbcdc66..7be219f5d 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -161,11 +161,66 @@ pub fn generate_base_impl( Ok(()) } -pub fn base_impl_body_chunk(env: &Env, +pub fn generate_override_vfuncs( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + subclass_info: &SubclassInfo, + indent: usize, +) -> Result<()> { + + if object_analysis.c_class_type.is_none(){ + return Ok(()); + } + + + try!(writeln!(w)); + try!(write!( + w, + "{}fn override_vfuncs(&mut self, _: &ClassInitToken){{", + tabs(indent) + )); + + let mut body_chunks = Vec::new(); + body_chunks.push(Chunk::Let{ + name: "klass".to_owned(), + is_mut: false, + value: Box::new(Chunk::Custom(format!("&mut *(self as *const Self as *mut {}::{})", + &env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name, + object_analysis.c_class_type.as_ref().unwrap()).to_owned())), + type_: None, + }); + + + for method_analysis in &object_analysis.virtual_methods { + body_chunks.push(Chunk::Custom( + format!("klass.{mname} = Some({cname}_{mname}::);", mname=method_analysis.name, + cname=object_analysis.name.to_lowercase()).to_owned() + )); + } + + + let unsafe_ = Chunk::Unsafe(body_chunks); + + let mut chunks = Vec::new(); + chunks.push(unsafe_); + let body = Chunk::Chunks(chunks).to_code(env); + + for s in body { + try!(writeln!(w, "{}{}", tabs(indent+1), s)); + } + + Ok(()) + +} + + + +pub fn body_chunk_builder(env: &Env, object_analysis: &analysis::object::Info, method_analysis: &analysis::virtual_methods::Info, subclass_info: &SubclassInfo - ) -> Chunk + ) -> Builder { let mut builder = Builder::new(); @@ -186,6 +241,16 @@ pub fn base_impl_body_chunk(env: &Env, } } + builder +} + +pub fn base_impl_body_chunk(env: &Env, + object_analysis: &analysis::object::Info, + method_analysis: &analysis::virtual_methods::Info, + subclass_info: &SubclassInfo + ) -> Chunk +{ + let mut builder = body_chunk_builder(env, object_analysis, method_analysis, subclass_info); builder.generate_base_impl(env) } diff --git a/src/writer/to_code.rs b/src/writer/to_code.rs index ce9849429..a5657b150 100644 --- a/src/writer/to_code.rs +++ b/src/writer/to_code.rs @@ -158,12 +158,13 @@ impl ToCode for Chunk { code }, Cast { ref name, ref type_ } => vec![format!("{} as {}", name, type_)], - Call { ref func_name, ref arguments } => { + Call { ref func_name, ref arguments, as_return } => { let args: Vec<_> = arguments.iter() .flat_map(|arg| arg.to_code(env)) .collect(); let s = format_block_one_line("(", ")", &args, "", ","); - vec![format!("{}{}", func_name, s)] //TODO: removed the trailing ';' here + let d = if as_return {""} else {";"}; + vec![format!("{}{}{}", func_name, s, d)] }, Closure { ref arguments, ref body } => { let args: Vec<_> = arguments.iter() From d7087c2714b9db3d38bf36647a8e191a8018aa81 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 25 May 2018 07:30:38 +0200 Subject: [PATCH 027/122] add stubs for generating the remaining items --- src/codegen/subclass/class_impl.rs | 216 ++++++++++++++++++++---- src/codegen/subclass/virtual_methods.rs | 5 +- 2 files changed, 183 insertions(+), 38 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 5c33cf354..65ea49bca 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -23,7 +23,7 @@ use library::*; use analysis::general::StatusedTypeId; pub struct SubclassInfo { - parents: Vec + parents: Vec, } impl SubclassInfo { @@ -39,29 +39,26 @@ impl SubclassInfo { .cloned() .collect::>(); - Self { - parents, - } + Self { parents } } fn parent_names(&self, env: &Env, krate_suffix: &str) -> Vec { self.parents .iter() - .map(|ref p| { + .map(|ref p| /*{ if p.type_id.ns_id == namespaces::MAIN { p.name.clone() - } else { + } else*/ { format!( "{krate}{krate_suffix}::{name}", krate = env.namespaces[p.type_id.ns_id].crate_name, krate_suffix = krate_suffix, name = p.name ) - } + //} }) .collect() } - } pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> { @@ -81,20 +78,29 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> try!(generate_ext(w, env, analysis, &subclass_info)); + try!(generate_glib_wrapper(w, env, analysis, &subclass_info)); + + try!(generate_impl_base(w, env, analysis, &subclass_info)); + + try!(generate_class(w, env, analysis, &subclass_info)); + + try!(generate_parent_impls(w, env, analysis, &subclass_info)); + + try!(generate_box_impl(w, env, analysis, &subclass_info)); + + try!(generate_impl_objecttype(w, env, analysis, &subclass_info)); + + try!(generate_extern_c_funcs(w, env, analysis, &subclass_info)); Ok(()) } -// pub fn generate_impl --> -// pub trait ApplicationImpl: ObjectImpl + AnyImpl + 'static { - pub fn generate_impl( w: &mut Write, env: &Env, object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo, ) -> Result<()> { - let mut parents = subclass_info.parent_names(env, "_subclass"); let parent_impls: Vec = parents @@ -139,23 +145,16 @@ pub fn generate_impl_ext( object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo, ) -> Result<()> { - - let implext_name = format!("{}Ext", object_analysis.subclass_impl_trait_name); // start ext trait def try!(writeln!(w)); - try!(writeln!( - w, - "pub trait {} {{}}", - implext_name - )); + try!(writeln!(w, "pub trait {} {{}}", implext_name)); //end ext trait def try!(writeln!(w)); try!(writeln!(w, "}}")); - // start ext trait impl let parents = subclass_info.parent_names(env, ""); @@ -165,7 +164,6 @@ pub fn generate_impl_ext( .collect(); let parent_objs = parent_impls.join(" "); - try!(writeln!( w, "impl, T: ObjectType {parents}>> {implext_name} for S {{}}", @@ -174,19 +172,15 @@ pub fn generate_impl_ext( implext_name = implext_name )); - Ok(()) } - - pub fn generate_base( w: &mut Write, env: &Env, object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo, ) -> Result<()> { - let parents = subclass_info.parent_names(env, ""); let parent_impls: Vec = parents @@ -200,8 +194,7 @@ pub fn generate_base( try!(writeln!( w, "pub unsafe trait {}: ObjectType {}{{", - object_analysis.subclass_base_trait_name, - parent_objs + object_analysis.subclass_base_trait_name, parent_objs )); for method_analysis in &object_analysis.virtual_methods { @@ -235,41 +228,35 @@ fn generate_any_impl( try!(writeln!( w, "any_impl!({}, {});", - object_analysis.subclass_base_trait_name, - object_analysis.subclass_impl_trait_name + object_analysis.subclass_base_trait_name, object_analysis.subclass_impl_trait_name )); Ok(()) } - fn generate_ext( w: &mut Write, env: &Env, object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo, ) -> Result<()> { - - if object_analysis.class_type.is_none(){ + if object_analysis.class_type.is_none() { return Ok(()); } - let classext_name = format!("{}Ext", object_analysis.class_type.as_ref().unwrap()); // start base trait try!(writeln!(w)); try!(writeln!( w, - "pub unsafe trait {} - where - T::ImplType: {}{{", + "pub unsafe trait {}\nwhere\n{}T::ImplType: {}{{", classext_name, object_analysis.subclass_base_trait_name, + tabs(1), object_analysis.subclass_impl_trait_name )); - try!(virtual_methods::generate_override_vfuncs( w, env, @@ -283,3 +270,158 @@ fn generate_ext( Ok(()) } + +fn generate_glib_wrapper( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + subclass_info: &SubclassInfo, +) -> Result<()> { + // start base trait + try!(writeln!(w)); + try!(writeln!(w, "glib_wrapper! {{")); + + try!(writeln!(w)); + try!(write!( + w, + "{tabs1}pub struct {obj}(Object>)", + tabs1 = tabs(1), + obj = object_analysis.name + )); + + if subclass_info.parents.len() > 0 { + try!(write!(w, ":\n [")); + for parent in &subclass_info.parents {} + + try!(writeln!(w, "]")); + } + + // [gio::Application => gio_ffi::GApplication, + // gio::ActionGroup => gio_ffi::GActionGroup, + // gio::ActionMap => gio_ffi::GActionMap]; + + try!(writeln!(w, "{tabs1};", tabs1 = tabs(1))); + try!(writeln!( + w, + "{tabs1}match fn {{ \n \ + {tabs2}get_type => || get_type::<{obj}>(),\n \ + {tabs1}}}", + tabs1 = tabs(1), + tabs2 = tabs(2), + obj = object_analysis.name + )); + + try!(writeln!(w)); + try!(writeln!(w, "}}")); + + Ok(()) +} + +fn generate_impl_base( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + subclass_info: &SubclassInfo, +) -> Result<()> { + // unsafe impl + ObjectType> ApplicationBase for T {} + + Ok(()) +} + +fn generate_class( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + subclass_info: &SubclassInfo, +) -> Result<()> { + + writeln!( + w, + "pub type {obj}Class = ClassStruct<{obj}>;", + obj = object_analysis.name + ); + + Ok(()) +} + +fn generate_parent_impls( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + subclass_info: &SubclassInfo, +) -> Result<()> { + // // FIXME: Boilerplate + // unsafe impl ApplicationClassExt for ApplicationClass {} + // unsafe impl ObjectClassExt for ApplicationClass {} + + writeln!(w, "// FIXME: Boilerplate"); + if subclass_info.parents.len() > 0 {} + + Ok(()) +} + +fn generate_box_impl( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + subclass_info: &SubclassInfo, +) -> Result<()> { + // #[macro_export] + // macro_rules! box_gapplication_impl( + // ($name:ident) => { + // box_object_impl!($name); + // + // impl $crate::application::ApplicationImpl for Box<$name> + // { + // fn startup(&self, application: &T){ + // let imp: &$name = self.as_ref(); + // imp.startup(application) + // } + + Ok(()) +} + +fn generate_impl_objecttype( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + subclass_info: &SubclassInfo, +) -> Result<()> { + // impl ObjectType for Application { + // const NAME: &'static str = "RsGApplication"; + // type ParentType = gio::Application; + // type ImplType = Box>; + // type InstanceStructType = InstanceStruct; + // + // fn class_init(token: &ClassInitToken, klass: &mut ApplicationClass) { + // ObjectClassExt::override_vfuncs(klass, token); + // ApplicationClassExt::override_vfuncs(klass, token); + // } + // + // object_type_fns!(); + // } + + Ok(()) +} + +fn generate_extern_c_funcs( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + subclass_info: &SubclassInfo, +) -> Result<()> { + // unsafe extern "C" fn application_startup(ptr: *mut gio_ffi::GApplication) + // where + // T::ImplType: ApplicationImpl, + // { + // callback_guard!(); + // floating_reference_guard!(ptr); + // let application = &*(ptr as *mut T::InstanceStructType); + // let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType); + // let imp = application.get_impl(); + // + // imp.startup(&wrap) + // } + + Ok(()) +} diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 7be219f5d..0f8a6c72c 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -175,7 +175,7 @@ pub fn generate_override_vfuncs( try!(writeln!(w)); - try!(write!( + try!(writeln!( w, "{}fn override_vfuncs(&mut self, _: &ClassInitToken){{", tabs(indent) @@ -210,6 +210,9 @@ pub fn generate_override_vfuncs( try!(writeln!(w, "{}{}", tabs(indent+1), s)); } + try!(writeln!(w, "{}}}", tabs(indent))); + + Ok(()) } From 7cc5f09f52996e24a9c83771d4a9b6a3637fc744 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 25 May 2018 20:28:39 +0200 Subject: [PATCH 028/122] wip: implement glib wrapper and base impl --- src/codegen/subclass/class_impl.rs | 88 +++++++++++++++++++++++------- 1 file changed, 69 insertions(+), 19 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 65ea49bca..7ec923f16 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -215,9 +215,6 @@ pub fn generate_base( Ok(()) } -// pub fn generate_base --> -// pub unsafe trait ApplicationBase: IsA + ObjectType { - fn generate_any_impl( w: &mut Write, _env: &Env, @@ -290,15 +287,21 @@ fn generate_glib_wrapper( )); if subclass_info.parents.len() > 0 { - try!(write!(w, ":\n [")); - for parent in &subclass_info.parents {} - - try!(writeln!(w, "]")); + try!(write!(w, ":[")); + for parent in &subclass_info.parents { + let t = env.library.type_(parent.type_id); + let k = &env.namespaces[parent.type_id.ns_id].crate_name; + try!(write!(w, "\n{tabs} {krate}::{ty} => {krate}_ffi::{cty}", + tabs=tabs(2), + krate=k, + ty=t.get_name(), + cty=t.get_glib_name().unwrap())); + + } + + try!(write!(w, "]")); } - // [gio::Application => gio_ffi::GApplication, - // gio::ActionGroup => gio_ffi::GActionGroup, - // gio::ActionMap => gio_ffi::GActionMap]; try!(writeln!(w, "{tabs1};", tabs1 = tabs(1))); try!(writeln!( @@ -323,7 +326,22 @@ fn generate_impl_base( object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo, ) -> Result<()> { - // unsafe impl + ObjectType> ApplicationBase for T {} + + let parents = subclass_info.parent_names(env, ""); + + let parent_impls: Vec = parents + .iter() + .map(|ref p| format!("+ glib::IsA<{}>", p)) + .collect(); + let parent_objs = parent_impls.join(" "); + + try!(writeln!(w)); + try!(writeln!( + w, + "unsafe impl {} for T {{}}", + parent_objs, + object_analysis.subclass_base_trait_name + )); Ok(()) } @@ -335,6 +353,8 @@ fn generate_class( subclass_info: &SubclassInfo, ) -> Result<()> { + try!(writeln!(w)); + writeln!( w, "pub type {obj}Class = ClassStruct<{obj}>;", @@ -350,12 +370,19 @@ fn generate_parent_impls( object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo, ) -> Result<()> { - // // FIXME: Boilerplate - // unsafe impl ApplicationClassExt for ApplicationClass {} - // unsafe impl ObjectClassExt for ApplicationClass {} + + try!(writeln!(w)); writeln!(w, "// FIXME: Boilerplate"); - if subclass_info.parents.len() > 0 {} + if subclass_info.parents.len() > 0 { + for parent in &subclass_info.parents { + let t = env.library.type_(parent.type_id); + try!(writeln!(w, "unsafe impl {par}ClassExt<{obj}> for {obj}Class {}", + obj=object_analysis.name, + par=t.get_name())); + + } + } Ok(()) } @@ -366,10 +393,28 @@ fn generate_box_impl( object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo, ) -> Result<()> { - // #[macro_export] - // macro_rules! box_gapplication_impl( - // ($name:ident) => { - // box_object_impl!($name); + + try!(writeln!(w)); + + try!(writeln!(w, "#[macro_export]")); + try!(writeln!(w, "macro_rules! box_{}_impl(", object_analysis.name.to_lowercase())); + + try!(writeln!(w, "{}($name:ident) => {{", tabs(1))); + + if subclass_info.parents.len() > 0{ + + for parent in &subclass_info.parents { + if !env.analysis.objects.contains_key(&parent.type_id.full_name(&env.library)){ + continue; + } + try!(writeln!(w, "{}box_{}_impl!($name);", tabs(2), o.name.to_lowercase())); + } + + let n = subclass_info.parents.len() - 1; + }else{ + try!(writeln!(w, "{}box_object_impl!($name);", tabs(2))); + } + // // impl $crate::application::ApplicationImpl for Box<$name> // { @@ -378,6 +423,11 @@ fn generate_box_impl( // imp.startup(application) // } + try!(writeln!(w, "{}}}", tabs(1))); + + try!(writeln!(w, ");")); + + Ok(()) } From e613e57588b974b5b37bdd520b95aa8adbfbc86b Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 25 May 2018 21:29:08 +0200 Subject: [PATCH 029/122] generate box impl --- src/codegen/subclass/class_impl.rs | 91 ++++++++++++++++--------- src/codegen/subclass/virtual_methods.rs | 89 +++++++++++++++++++----- 2 files changed, 129 insertions(+), 51 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 7ec923f16..bfab51312 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -291,18 +291,19 @@ fn generate_glib_wrapper( for parent in &subclass_info.parents { let t = env.library.type_(parent.type_id); let k = &env.namespaces[parent.type_id.ns_id].crate_name; - try!(write!(w, "\n{tabs} {krate}::{ty} => {krate}_ffi::{cty}", - tabs=tabs(2), - krate=k, - ty=t.get_name(), - cty=t.get_glib_name().unwrap())); - + try!(write!( + w, + "\n{tabs} {krate}::{ty} => {krate}_ffi::{cty}", + tabs = tabs(2), + krate = k, + ty = t.get_name(), + cty = t.get_glib_name().unwrap() + )); } try!(write!(w, "]")); } - try!(writeln!(w, "{tabs1};", tabs1 = tabs(1))); try!(writeln!( w, @@ -326,7 +327,6 @@ fn generate_impl_base( object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo, ) -> Result<()> { - let parents = subclass_info.parent_names(env, ""); let parent_impls: Vec = parents @@ -339,8 +339,7 @@ fn generate_impl_base( try!(writeln!( w, "unsafe impl {} for T {{}}", - parent_objs, - object_analysis.subclass_base_trait_name + parent_objs, object_analysis.subclass_base_trait_name )); Ok(()) @@ -352,7 +351,6 @@ fn generate_class( object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo, ) -> Result<()> { - try!(writeln!(w)); writeln!( @@ -370,17 +368,18 @@ fn generate_parent_impls( object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo, ) -> Result<()> { - try!(writeln!(w)); writeln!(w, "// FIXME: Boilerplate"); if subclass_info.parents.len() > 0 { for parent in &subclass_info.parents { let t = env.library.type_(parent.type_id); - try!(writeln!(w, "unsafe impl {par}ClassExt<{obj}> for {obj}Class {}", - obj=object_analysis.name, - par=t.get_name())); - + try!(writeln!( + w, + "unsafe impl {par}ClassExt<{obj}> for {obj}Class {}", + obj = object_analysis.name, + par = t.get_name() + )); } } @@ -393,40 +392,64 @@ fn generate_box_impl( object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo, ) -> Result<()> { - try!(writeln!(w)); try!(writeln!(w, "#[macro_export]")); - try!(writeln!(w, "macro_rules! box_{}_impl(", object_analysis.name.to_lowercase())); + try!(writeln!( + w, + "macro_rules! box_{}_impl(", + object_analysis.name.to_lowercase() + )); try!(writeln!(w, "{}($name:ident) => {{", tabs(1))); - if subclass_info.parents.len() > 0{ - + if subclass_info.parents.len() > 0 { for parent in &subclass_info.parents { - if !env.analysis.objects.contains_key(&parent.type_id.full_name(&env.library)){ + if !env.analysis + .objects + .contains_key(&parent.type_id.full_name(&env.library)) + { continue; } - try!(writeln!(w, "{}box_{}_impl!($name);", tabs(2), o.name.to_lowercase())); + let o = &env.analysis.objects[&parent.type_id.full_name(&env.library)]; + try!(writeln!( + w, + "{}box_{}_impl!($name);", + tabs(2), + o.name.to_lowercase() + )); } - - let n = subclass_info.parents.len() - 1; - }else{ + } else { try!(writeln!(w, "{}box_object_impl!($name);", tabs(2))); } - // - // impl $crate::application::ApplicationImpl for Box<$name> - // { - // fn startup(&self, application: &T){ - // let imp: &$name = self.as_ref(); - // imp.startup(application) - // } + let obj = &env.config.objects[&object_analysis.full_name]; + let mod_name = obj.module_name.clone().unwrap_or_else(|| { + nameutil::module_name(nameutil::split_namespace_name(&object_analysis.full_name).1) + }); - try!(writeln!(w, "{}}}", tabs(1))); + try!(writeln!(w, "{tabs}impl $crate::{mo}::{impl} for Box<$name>{{", + tabs=tabs(2), + mo=mod_name, + base=object_analysis.subclass_base_trait_name, + impl=object_analysis.subclass_impl_trait_name)); - try!(writeln!(w, ");")); + for method_analysis in &object_analysis.virtual_methods { + try!(virtual_methods::generate_box_impl( + w, + env, + object_analysis, + method_analysis, + subclass_info, + 3 + )); + } + + try!(writeln!(w, "{}}}", tabs(2))); + + try!(writeln!(w, "{}}}", tabs(1))); + try!(writeln!(w, ");")); Ok(()) } diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 0f8a6c72c..cbeb751a3 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -39,23 +39,7 @@ pub fn generate_default_impl( let parent_name = &method_analysis.parameters.rust_parameters[0].name; - - let mut param_str = String::with_capacity(100); - for (pos, par) in method_analysis.parameters.rust_parameters.iter().enumerate() { - if pos > 0 { - param_str.push_str(", "); - } - - let c_par = &method_analysis.parameters.c_parameters[par.ind_c]; - let s = c_par.to_parameter(env, &method_analysis.bounds); - param_str.push_str(&s); - - // insert the templated param - if pos == 0{ - param_str.push_str(&format!(", {}: &T", parent_name)); - } - } - + let param_str = virtual_method_params(env, method_analysis, parent_name, true); try!(writeln!(w, "{}){{", param_str)); @@ -113,6 +97,26 @@ fn virtual_method_args(method_analysis: &analysis::virtual_methods::Info, includ arg_str } +fn virtual_method_params(env: &Env, method_analysis: &analysis::virtual_methods::Info, parent_name: &String, include_templated: bool) -> String +{ + let mut param_str = String::with_capacity(100); + for (pos, par) in method_analysis.parameters.rust_parameters.iter().enumerate() { + if pos > 0 { + param_str.push_str(", "); + } + + let c_par = &method_analysis.parameters.c_parameters[par.ind_c]; + let s = c_par.to_parameter(env, &method_analysis.bounds); + param_str.push_str(&s); + + // insert the templated param + if include_templated && pos == 0{ + param_str.push_str(&format!(", {}: &T", parent_name)); + } + } + param_str +} + pub fn generate_base_impl( w: &mut Write, @@ -217,6 +221,57 @@ pub fn generate_override_vfuncs( } +pub fn generate_box_impl( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + method_analysis: &analysis::virtual_methods::Info, + subclass_info: &SubclassInfo, + indent: usize, +) -> Result<()> { + + try!(writeln!(w)); + try!(write!( + w, + "{}fn {}(", + tabs(indent), + method_analysis.name, + )); + + let parent_name = &method_analysis.parameters.rust_parameters[0].name; + + let param_str = virtual_method_params(env, method_analysis, parent_name, true); + try!(writeln!(w, "{}){{", param_str)); + + + let arg_str = virtual_method_args(method_analysis, false); + + + try!(writeln!( + w, + "{}let imp: &$name = self.as_ref();", + tabs(indent+1) + )); + + + try!(writeln!( + w, + "{}imp.{}({})", + tabs(indent+1), + method_analysis.name, + arg_str + )); + + + try!(writeln!( + w, + "{}}}", + tabs(indent), + )); + + Ok(()) +} + pub fn body_chunk_builder(env: &Env, From adaf643ad4304a7a99bb0e2a657f3efbdcf9b35b Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 25 May 2018 21:31:28 +0200 Subject: [PATCH 030/122] fix typo in impl classext --- src/codegen/subclass/class_impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index bfab51312..4dd29fed0 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -376,7 +376,7 @@ fn generate_parent_impls( let t = env.library.type_(parent.type_id); try!(writeln!( w, - "unsafe impl {par}ClassExt<{obj}> for {obj}Class {}", + "unsafe impl {par}ClassExt<{obj}> for {obj}Class {{}}", obj = object_analysis.name, par = t.get_name() )); From c7cb8563ae1951d2f6799f92ec384d586dd2bc63 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 26 May 2018 08:10:44 +0200 Subject: [PATCH 031/122] generate objecttype --- src/codegen/subclass/class_impl.rs | 97 ++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 13 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 4dd29fed0..e835ccc5a 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -59,6 +59,28 @@ impl SubclassInfo { }) .collect() } + + fn parent<'a>(&self, env: &'a Env) -> Option<&'a analysis::object::Info>{ + // get the actual superclass object + if self.parents.len() == 0 { + return None + } + for parent in &self.parents { + if !env.analysis + .objects + .contains_key(&parent.type_id.full_name(&env.library)) + { + continue; + } + + let o = &env.analysis.objects[&parent.type_id.full_name(&env.library)]; + if !o.is_interface{ + return Some(o); + } + } + None + } + } pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> { @@ -460,19 +482,68 @@ fn generate_impl_objecttype( object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo, ) -> Result<()> { - // impl ObjectType for Application { - // const NAME: &'static str = "RsGApplication"; - // type ParentType = gio::Application; - // type ImplType = Box>; - // type InstanceStructType = InstanceStruct; - // - // fn class_init(token: &ClassInitToken, klass: &mut ApplicationClass) { - // ObjectClassExt::override_vfuncs(klass, token); - // ApplicationClassExt::override_vfuncs(klass, token); - // } - // - // object_type_fns!(); - // } + + + try!(writeln!(w)); + + try!(writeln!(w, "impl ObjectType for {}{{", + object_analysis.name + )); + + try!(writeln!(w, "{}const NAME: &'static str = \"Rs{}\";", + tabs(1), + object_analysis.full_name + )); + + let parent = subclass_info.parent(env); + + if parent.is_some(){ + + let p = parent.as_ref().unwrap(); + + let (ns, n) = nameutil::split_namespace_name(&p.full_name); + + try!(writeln!(w, "{}type ParentType = {}::{};", + tabs(1), + ns.unwrap_or("").to_lowercase(), + n + )); + } + + try!(writeln!(w, "{}type ImplType = Box<{}>;", + tabs(1), + object_analysis.subclass_impl_trait_name + )); + + try!(writeln!(w, "{}type InstanceStructType = InstanceStruct;", + tabs(1) + )); + + try!(writeln!(w, "{}fn class_init(token: &ClassInitToken, klass: &mut {}Class) {{", + tabs(1), + object_analysis.name + )); + + try!(writeln!(w, "{}ObjectClassExt::override_vfuncs(klass, token);", + tabs(2) + )); + + + for parent in &subclass_info.parents { + try!(writeln!(w, "{}{}ClassExt::override_vfuncs(klass, token);", + tabs(2), + parent.name)); + } + + try!(writeln!(w, "{}}}", tabs(1))); + + + try!(writeln!(w, "{}object_type_fns!();", + tabs(1) + )); + + try!(writeln!(w, "}}")); + Ok(()) } From c38db4666eb2a499a3726e69a443009f9bfed610 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 26 May 2018 10:36:44 +0200 Subject: [PATCH 032/122] generate extern c functions --- src/codegen/subclass/class_impl.rs | 25 +-- .../subclass/virtual_method_body_chunks.rs | 39 +++++ src/codegen/subclass/virtual_methods.rs | 143 +++++++++++++++--- src/codegen/sys/mod.rs | 2 +- 4 files changed, 179 insertions(+), 30 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index e835ccc5a..3dfedf4be 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -18,6 +18,7 @@ use std::result::Result as StdResult; use codegen::general; use codegen::subclass::virtual_methods; use codegen::sys::fields; + use library::*; use analysis::general::StatusedTypeId; @@ -554,18 +555,18 @@ fn generate_extern_c_funcs( object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo, ) -> Result<()> { - // unsafe extern "C" fn application_startup(ptr: *mut gio_ffi::GApplication) - // where - // T::ImplType: ApplicationImpl, - // { - // callback_guard!(); - // floating_reference_guard!(ptr); - // let application = &*(ptr as *mut T::InstanceStructType); - // let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType); - // let imp = application.get_impl(); - // - // imp.startup(&wrap) - // } + + + for method_analysis in &object_analysis.virtual_methods { + try!(virtual_methods::generate_extern_c_func( + w, + env, + object_analysis, + method_analysis, + subclass_info, + 0 + )); + } Ok(()) } diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index 4bb9e7c73..086f7fa25 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -21,6 +21,7 @@ use codegen::parameter::*; #[derive(Default)] pub struct Builder { + object_name: String, object_class_c_type: String, ffi_crate_name: String, method_name: String, @@ -36,6 +37,11 @@ impl Builder { Default::default() } + pub fn object_name(&mut self, name: &str) -> &mut Builder { + self.object_name = name.into(); + self + } + pub fn object_class_c_type(&mut self, c_class_type: &str) -> &mut Builder { self.object_class_c_type = c_class_type.into(); self @@ -109,6 +115,39 @@ impl Builder { Chunk::Chunks(chunks) } + pub fn generate_extern_c_func(&self, env: &Env) -> Chunk { + let mut chunks = Vec::new(); + + chunks.push(Chunk::Custom("callback_guard!();".to_owned())); + chunks.push(Chunk::Custom("floating_reference_guard!(ptr);".to_owned())); + + chunks.push(Chunk::Let{ is_mut:false, + name: self.object_name.to_lowercase(), + value: Box::new(Chunk::Custom("&*(ptr as *mut T::InstanceStructType)".to_owned())), + type_: None + }); + + chunks.push(Chunk::Let{ is_mut:false, + name: "wrap".to_owned(), + value: Box::new(Chunk::Custom("from_glib_borrow(ptr as *mut T::InstanceStructType))".to_owned())), + type_: Some(Box::new(Chunk::Custom("T".to_owned()))) + }); + + chunks.push(Chunk::Let{ is_mut:false, + name: "imp".to_owned(), + value: Box::new(Chunk::Custom(format!("{}.get_impl())", + self.object_name.to_lowercase()).to_owned())), + type_: None + }); + + chunks.push(Chunk::Custom(format!("imp.{}({})", + self.method_name, + &"").to_owned())); + + Chunk::Chunks(chunks) + } + + fn base_impl_body_chunk(&self) -> Chunk { Chunk::Closure { diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index cbeb751a3..37d7f0829 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -11,12 +11,16 @@ use writer::primitives::tabs; use writer::ToCode; use codegen::parameter::ToParameter; use chunk::{ffi_function_todo, Chunk}; +use traits::IntoString; +use nameutil; use std::result::Result as StdResult; use std::fmt; use codegen::subclass::class_impl::SubclassInfo; use codegen::subclass::virtual_method_body_chunks::Builder; +use codegen::sys::ffi_type::ffi_type; +use codegen::function_body_chunk::{Parameter, ReturnValue}; pub fn generate_default_impl( w: &mut Write, @@ -39,7 +43,7 @@ pub fn generate_default_impl( let parent_name = &method_analysis.parameters.rust_parameters[0].name; - let param_str = virtual_method_params(env, method_analysis, parent_name, true); + let param_str = virtual_method_params(env, method_analysis, Some(parent_name)); try!(writeln!(w, "{}){{", param_str)); @@ -97,7 +101,7 @@ fn virtual_method_args(method_analysis: &analysis::virtual_methods::Info, includ arg_str } -fn virtual_method_params(env: &Env, method_analysis: &analysis::virtual_methods::Info, parent_name: &String, include_templated: bool) -> String +fn virtual_method_params(env: &Env, method_analysis: &analysis::virtual_methods::Info, parent_name: Option<&String>) -> String { let mut param_str = String::with_capacity(100); for (pos, par) in method_analysis.parameters.rust_parameters.iter().enumerate() { @@ -106,12 +110,15 @@ fn virtual_method_params(env: &Env, method_analysis: &analysis::virtual_methods: } let c_par = &method_analysis.parameters.c_parameters[par.ind_c]; - let s = c_par.to_parameter(env, &method_analysis.bounds); + + // generate types, not trait bounds + let bounds = Bounds::default(); + let s = c_par.to_parameter(env, &bounds); param_str.push_str(&s); // insert the templated param - if include_templated && pos == 0{ - param_str.push_str(&format!(", {}: &T", parent_name)); + if parent_name.is_some() && pos == 0{ + param_str.push_str(&format!(", {}: &T", parent_name.as_ref().unwrap())); } } param_str @@ -137,16 +144,7 @@ pub fn generate_base_impl( method_analysis.name, )); - let mut param_str = String::with_capacity(100); - for (pos, par) in method_analysis.parameters.rust_parameters.iter().enumerate() { - if pos > 0 { - param_str.push_str(", "); - } - - let c_par = &method_analysis.parameters.c_parameters[par.ind_c]; - let s = c_par.to_parameter(env, &method_analysis.bounds); - param_str.push_str(&s); - } + let mut param_str = virtual_method_params(env, method_analysis, None); try!(writeln!(w, "{}){{", param_str)); @@ -240,7 +238,7 @@ pub fn generate_box_impl( let parent_name = &method_analysis.parameters.rust_parameters[0].name; - let param_str = virtual_method_params(env, method_analysis, parent_name, true); + let param_str = virtual_method_params(env, method_analysis, Some(parent_name)); try!(writeln!(w, "{}){{", param_str)); @@ -272,7 +270,56 @@ pub fn generate_box_impl( Ok(()) } +pub fn generate_extern_c_func( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + method_analysis: &analysis::virtual_methods::Info, + subclass_info: &SubclassInfo, + indent: usize, +) -> Result<()> { + + try!(writeln!(w)); + + try!(writeln!( + w, + "unsafe extern \"C\" fn {}_{}", + object_analysis.name.to_lowercase(), + method_analysis.name, + object_analysis.subclass_base_trait_name + )); + + let (_, sig) = function_signature(env, method_analysis, false); + + try!(writeln!( + w, + "{}", + sig + )); + try!(writeln!( + w, + "where\n{}T::ImplType: {}", + tabs(indent+1), + object_analysis.subclass_impl_trait_name + )); + try!(writeln!( + w, + "{{" + )); + + let body = extern_c_func_body_chunk(env, object_analysis, method_analysis, subclass_info).to_code(env); + for s in body { + try!(writeln!(w, "{}{}", tabs(indent+1), s)); + } + + try!(writeln!( + w, + "}}" + )); + + Ok(()) +} pub fn body_chunk_builder(env: &Env, object_analysis: &analysis::object::Info, @@ -284,7 +331,8 @@ pub fn body_chunk_builder(env: &Env, let outs_as_return = !method_analysis.outs.is_empty(); - builder.object_class_c_type(object_analysis.c_class_type.as_ref().unwrap()) + builder.object_name(&object_analysis.name) + .object_class_c_type(object_analysis.c_class_type.as_ref().unwrap()) .ffi_crate_name(&env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name) .method_name(&method_analysis.name) .ret(&method_analysis.ret) @@ -312,3 +360,64 @@ pub fn base_impl_body_chunk(env: &Env, builder.generate_base_impl(env) } + +pub fn extern_c_func_body_chunk(env: &Env, + object_analysis: &analysis::object::Info, + method_analysis: &analysis::virtual_methods::Info, + subclass_info: &SubclassInfo + ) -> Chunk +{ + let mut builder = body_chunk_builder(env, object_analysis, method_analysis, subclass_info); + + builder.generate_extern_c_func(env) +} + + +pub fn function_signature(env: &Env, method: &analysis::virtual_methods::Info, bare: bool) -> (bool, String) { + let (mut commented, ret_str) = function_return_value(env, method); + + let mut parameter_strs: Vec = Vec::new(); + for par in &method.parameters.c_parameters { + let (c, par_str) = function_parameter(env, par, bare); + parameter_strs.push(par_str); + if c { + commented = true; + } + } + + ( + commented, + format!("({}){}", parameter_strs.join(", "), ret_str), + ) +} + +fn function_return_value(env: &Env, method: &analysis::virtual_methods::Info) -> (bool, String) { + if method.ret.parameter.is_none(){ + return (false, "".to_string()); + } + let ret = method.ret.parameter.as_ref().unwrap(); + if ret.typ == Default::default() { + return (false, String::new()); + } + let ffi_type = ffi_type(env, ret.typ, &ret.c_type); + let commented = ffi_type.is_err(); + (commented, format!(" -> {}", ffi_type.into_string())) +} + +fn function_parameter(env: &Env, par: &analysis::function_parameters::CParameter, bare: bool) -> (bool, String) { + if let library::Type::Fundamental(library::Fundamental::VarArgs) = *env.library.type_(par.typ) { + return (false, "...".into()); + } + let ffi_type = ffi_type(env, par.typ, &par.c_type); + let commented = ffi_type.is_err(); + let res = if bare { + ffi_type.into_string() + } else { + format!( + "{}: {}", + nameutil::mangle_keywords(&*par.name), + ffi_type.into_string() + ) + }; + (commented, res) +} diff --git a/src/codegen/sys/mod.rs b/src/codegen/sys/mod.rs index bfdedf3c6..8176713eb 100644 --- a/src/codegen/sys/mod.rs +++ b/src/codegen/sys/mod.rs @@ -5,7 +5,7 @@ mod build; mod cargo_toml; pub mod ffi_type; pub mod fields; -mod functions; +pub mod functions; mod lib_; mod statics; mod tests; From 0d64a7c493a66d0170f2e9ffde83d5f5e86a4334 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 26 May 2018 11:18:29 +0200 Subject: [PATCH 033/122] fix after rebase on master --- src/analysis/functions.rs | 2 +- src/analysis/virtual_methods.rs | 53 ++++++++------------------------- 2 files changed, 14 insertions(+), 41 deletions(-) diff --git a/src/analysis/functions.rs b/src/analysis/functions.rs index cd3038a58..753ec2a79 100644 --- a/src/analysis/functions.rs +++ b/src/analysis/functions.rs @@ -412,7 +412,7 @@ pub fn is_carray_with_direct_elements(env: &Env, typ: library::TypeId) -> bool { } } -fn analyze_async( +pub fn analyze_async( env: &Env, func: &library::Function, callback_info: Option, diff --git a/src/analysis/virtual_methods.rs b/src/analysis/virtual_methods.rs index 455394995..345af7889 100644 --- a/src/analysis/virtual_methods.rs +++ b/src/analysis/virtual_methods.rs @@ -10,7 +10,7 @@ use super::trampolines; use traits::*; use version::Version; -use analysis::bounds::Bounds; +use analysis::bounds::{Bounds, CallbackInfo}; use analysis::function_parameters::{self, Parameters, Transformation, TransformationType}; use analysis::out_parameters::use_function_return_for_result; use analysis::imports::Imports; @@ -28,7 +28,8 @@ use super::functions::{ AsyncTrampoline, is_carray_with_direct_elements, finish_function_name, - find_function + find_function, + analyze_async }; @@ -167,48 +168,20 @@ fn analyze_virtual_method( if let Ok(s) = used_rust_type(env, par.typ) { used_types.push(s); } - let (to_glib_extra, type_string) = bounds.add_for_parameter(env, method, par, async); + let (to_glib_extra, callback_info) = bounds.add_for_parameter(env, method, par, async); if let Some(to_glib_extra) = to_glib_extra { to_glib_extras.insert(pos, to_glib_extra); } - if let Some((callback_type, success_parameters, error_parameters, bound_name)) = type_string { - // Checks for /*Ignored*/ or other error comments - if callback_type.find("/*").is_some() { - commented = true; - } - let func_name = method.c_identifier.as_ref().unwrap(); - let finish_func_name = finish_function_name(func_name); - let mut output_params = vec![]; - let mut ffi_ret = None; - if let Some(function) = find_function(env, &finish_func_name) { - if use_function_return_for_result(env, function.ret.typ) { - ffi_ret = Some(function.ret.clone()); - } - output_params.extend(function.parameters.clone()); - for param in &mut output_params { - if nameutil::needs_mangling(¶m.name) { - param.name = nameutil::mangle_keywords(&*param.name).into_owned(); - } - } - } - trampoline = Some(AsyncTrampoline { - is_method: true, - name: format!("{}_trampoline", method.name), - finish_func_name, - callback_type, - bound_name, - output_params, - ffi_ret, - }); - - async_future = Some(AsyncFuture { - is_method: true, - name: format!("{}_future", method.name), - success_parameters, - error_parameters, - }); - } + analyze_async( + env, + method, + callback_info, + &mut commented, + &mut trampoline, + &mut async_future + ); + let type_error = !(async && *env.library.type_(par.typ) == Type::Fundamental(library::Fundamental::Pointer)) && parameter_rust_type(env, par.typ, par.direction, Nullable(false), RefMode::None) From 80ea0056af6594554b0088af2df33904c05776fa Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 28 May 2018 20:11:07 +0200 Subject: [PATCH 034/122] add return types for functions --- src/codegen/return_value.rs | 2 +- src/codegen/subclass/virtual_methods.rs | 161 +++++++++++++++++++----- 2 files changed, 128 insertions(+), 35 deletions(-) diff --git a/src/codegen/return_value.rs b/src/codegen/return_value.rs index 1b1fdc3f7..a0bf22547 100644 --- a/src/codegen/return_value.rs +++ b/src/codegen/return_value.rs @@ -114,7 +114,7 @@ pub fn out_parameters_as_return(env: &Env, analysis: &analysis::functions::Info) return_str } -fn out_parameter_as_return(par: &library::Parameter, env: &Env) -> String { +pub fn out_parameter_as_return(par: &library::Parameter, env: &Env) -> String { //TODO: upcasts? let rust_type = parameter_rust_type( env, diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 37d7f0829..a6ba42796 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -21,6 +21,8 @@ use codegen::subclass::class_impl::SubclassInfo; use codegen::subclass::virtual_method_body_chunks::Builder; use codegen::sys::ffi_type::ffi_type; use codegen::function_body_chunk::{Parameter, ReturnValue}; +use codegen::return_value::{ToReturnValue, out_parameter_as_return}; + pub fn generate_default_impl( w: &mut Write, @@ -34,18 +36,16 @@ pub fn generate_default_impl( try!(writeln!(w)); - try!(write!( - w, - "{}fn {}(", - tabs(indent), - method_analysis.name, - )); let parent_name = &method_analysis.parameters.rust_parameters[0].name; + let declr = declaration(env, method_analysis, None, Some(parent_name)); - let param_str = virtual_method_params(env, method_analysis, Some(parent_name)); - - try!(writeln!(w, "{}){{", param_str)); + try!(writeln!( + w, + "{}{}{{", + tabs(indent), + declr, + )); let arg_str = virtual_method_args(method_analysis, false); @@ -101,18 +101,29 @@ fn virtual_method_args(method_analysis: &analysis::virtual_methods::Info, includ arg_str } -fn virtual_method_params(env: &Env, method_analysis: &analysis::virtual_methods::Info, parent_name: Option<&String>) -> String -{ + +pub fn declaration(env: &Env, method_analysis: &analysis::virtual_methods::Info, method_name: Option<&String>, parent_name: Option<&String>) -> String { + let outs_as_return = !method_analysis.outs.is_empty(); + let return_str = if outs_as_return { + out_parameters_as_return(env, method_analysis) + } else if method_analysis.ret.bool_return_is_error.is_some() { + if env.namespaces.glib_ns_id == namespaces::MAIN { + " -> Result<(), error::BoolError>".into() + } else { + " -> Result<(), glib::error::BoolError>".into() + } + } else { + method_analysis.ret.to_return_value(env) + }; let mut param_str = String::with_capacity(100); + + // generate types, not trait bounds + let bounds = Bounds::default(); for (pos, par) in method_analysis.parameters.rust_parameters.iter().enumerate() { if pos > 0 { - param_str.push_str(", "); + param_str.push_str(", ") } - let c_par = &method_analysis.parameters.c_parameters[par.ind_c]; - - // generate types, not trait bounds - let bounds = Bounds::default(); let s = c_par.to_parameter(env, &bounds); param_str.push_str(&s); @@ -121,10 +132,96 @@ fn virtual_method_params(env: &Env, method_analysis: &analysis::virtual_methods: param_str.push_str(&format!(", {}: &T", parent_name.as_ref().unwrap())); } } - param_str + + format!( + "fn {}({}){}", + method_name.unwrap_or(&method_analysis.name), + param_str, + return_str + ) +} + + +pub fn out_parameter_as_return_parts( + analysis: &analysis::virtual_methods::Info, +) -> (&'static str, &'static str) { + use analysis::out_parameters::Mode::*; + let num_outs = analysis + .outs + .iter() + .filter(|p| p.array_length.is_none()) + .count(); + match analysis.outs.mode { + Normal | Combined => if num_outs > 1 { + ("(", ")") + } else { + ("", "") + }, + Optional => if num_outs > 1 { + ("Option<(", ")>") + } else { + ("Option<", ">") + }, + Throws(..) => { + if num_outs == 1 + 1 { + //if only one parameter except "glib::Error" + ("Result<", ", Error>") + } else { + ("Result<(", "), Error>") + } + } + None => unreachable!(), + } +} + +pub fn out_parameters_as_return(env: &Env, analysis: &analysis::virtual_methods::Info) -> String { + let (prefix, suffix) = out_parameter_as_return_parts(analysis); + let mut return_str = String::with_capacity(100); + return_str.push_str(" -> "); + return_str.push_str(prefix); + + let array_lengths: Vec<_> = analysis + .outs + .iter() + .filter_map(|p| p.array_length) + .collect(); + + let mut skip = 0; + for (pos, par) in analysis.outs.iter().filter(|par| !par.is_error).enumerate() { + // The actual return value is inserted with an empty name at position 0 + if !par.name.is_empty() { + let mangled_par_name = nameutil::mangle_keywords(par.name.as_str()); + let param_pos = analysis + .parameters + .c_parameters + .iter() + .enumerate() + .filter_map(|(pos, orig_par)| if orig_par.name == mangled_par_name { + Some(pos) + } else { + None + }) + .next() + .unwrap(); + if array_lengths.contains(&(param_pos as u32)) { + skip += 1; + continue; + } + } + + if pos > skip { + return_str.push_str(", ") + } + let s = out_parameter_as_return(par, env); + return_str.push_str(&s); + } + return_str.push_str(suffix); + return_str } + + pub fn generate_base_impl( w: &mut Write, env: &Env, @@ -137,18 +234,15 @@ pub fn generate_base_impl( try!(writeln!(w)); - try!(write!( + + let declr = declaration(env, method_analysis, Some(&format!("parent_{}", method_analysis.name)), None); + try!(writeln!( w, - "{}fn parent_{}(", + "{}{}{{", tabs(indent), - method_analysis.name, + declr, )); - let mut param_str = virtual_method_params(env, method_analysis, None); - - - try!(writeln!(w, "{}){{", param_str)); - let body = base_impl_body_chunk(env, object_analysis, method_analysis, subclass_info).to_code(env); for s in body { try!(writeln!(w, "{}{}", tabs(indent+1), s)); @@ -229,18 +323,17 @@ pub fn generate_box_impl( ) -> Result<()> { try!(writeln!(w)); - try!(write!( - w, - "{}fn {}(", - tabs(indent), - method_analysis.name, - )); - let parent_name = &method_analysis.parameters.rust_parameters[0].name; - let param_str = virtual_method_params(env, method_analysis, Some(parent_name)); - try!(writeln!(w, "{}){{", param_str)); + let parent_name = &method_analysis.parameters.rust_parameters[0].name; + let declr = declaration(env, method_analysis, None, Some(parent_name)); + try!(writeln!( + w, + "{}{}{{", + tabs(indent), + declr, + )); let arg_str = virtual_method_args(method_analysis, false); From 2b50141a4646d59f096e3c32c275caab7f687620 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 28 May 2018 21:15:51 +0200 Subject: [PATCH 035/122] rename self ffi param to 'ptr' --- src/codegen/subclass/virtual_methods.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index a6ba42796..ed9c610d7 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -470,8 +470,9 @@ pub fn function_signature(env: &Env, method: &analysis::virtual_methods::Info, b let (mut commented, ret_str) = function_return_value(env, method); let mut parameter_strs: Vec = Vec::new(); - for par in &method.parameters.c_parameters { - let (c, par_str) = function_parameter(env, par, bare); + for (pos, par) in method.parameters.c_parameters.iter().enumerate() { + + let (c, par_str) = function_parameter(env, par, bare, Some(&"ptr".to_string())); parameter_strs.push(par_str); if c { commented = true; @@ -497,7 +498,7 @@ fn function_return_value(env: &Env, method: &analysis::virtual_methods::Info) -> (commented, format!(" -> {}", ffi_type.into_string())) } -fn function_parameter(env: &Env, par: &analysis::function_parameters::CParameter, bare: bool) -> (bool, String) { +fn function_parameter(env: &Env, par: &analysis::function_parameters::CParameter, bare: bool, param_name: Option<&String>) -> (bool, String) { if let library::Type::Fundamental(library::Fundamental::VarArgs) = *env.library.type_(par.typ) { return (false, "...".into()); } @@ -508,7 +509,7 @@ fn function_parameter(env: &Env, par: &analysis::function_parameters::CParameter } else { format!( "{}: {}", - nameutil::mangle_keywords(&*par.name), + param_name.unwrap_or(&nameutil::mangle_keywords(&*par.name).into_owned()), ffi_type.into_string() ) }; From 4b6f0a89a8e11cb86c0b0addf300c239cd4e4078 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 28 May 2018 21:18:11 +0200 Subject: [PATCH 036/122] fix 2 typos --- src/codegen/subclass/virtual_method_body_chunks.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index 086f7fa25..d59acce75 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -106,6 +106,8 @@ impl Builder { arguments: args, as_return: true, }); + + //TODO: return variables? body.push(Chunk::Custom(".unwrap_or(())".to_owned())); let unsafe_ = Chunk::Unsafe(body); @@ -129,13 +131,13 @@ impl Builder { chunks.push(Chunk::Let{ is_mut:false, name: "wrap".to_owned(), - value: Box::new(Chunk::Custom("from_glib_borrow(ptr as *mut T::InstanceStructType))".to_owned())), + value: Box::new(Chunk::Custom("from_glib_borrow(ptr as *mut T::InstanceStructType)".to_owned())), type_: Some(Box::new(Chunk::Custom("T".to_owned()))) }); chunks.push(Chunk::Let{ is_mut:false, name: "imp".to_owned(), - value: Box::new(Chunk::Custom(format!("{}.get_impl())", + value: Box::new(Chunk::Custom(format!("{}.get_impl()", self.object_name.to_lowercase()).to_owned())), type_: None }); From 4bb12782ba4b2e8e063d6822605f11734edb1415 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 28 May 2018 22:37:44 +0200 Subject: [PATCH 037/122] not everything should be called 'ptr' --- src/codegen/subclass/virtual_methods.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index ed9c610d7..b3a55f22f 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -472,7 +472,9 @@ pub fn function_signature(env: &Env, method: &analysis::virtual_methods::Info, b let mut parameter_strs: Vec = Vec::new(); for (pos, par) in method.parameters.c_parameters.iter().enumerate() { - let (c, par_str) = function_parameter(env, par, bare, Some(&"ptr".to_string())); + let param_name = if pos == 0 { Some("ptr".to_owned()) } else { None }; + + let (c, par_str) = function_parameter(env, par, bare, param_name.as_ref()); parameter_strs.push(par_str); if c { commented = true; From 6c610013d9db137f6852e65aa2470db08487c34f Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 29 May 2018 07:52:01 +0200 Subject: [PATCH 038/122] import libc crate --- src/codegen/subclass/class_impl.rs | 86 +++++++++++++++++++++++++++++- src/codegen/sys/lib_.rs | 2 +- src/codegen/sys/mod.rs | 2 +- 3 files changed, 87 insertions(+), 3 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 3dfedf4be..82e872c46 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -1,4 +1,5 @@ use std::io::{Result, Write}; +use std::fs; use analysis; use analysis::bounds::Bounds; @@ -7,7 +8,7 @@ use analysis::namespaces; use chunk::{ffi_function_todo, Chunk}; use env::Env; use library; - +use config::ExternalLibrary; use nameutil; use writer::primitives::tabs; use writer::ToCode; @@ -18,6 +19,7 @@ use std::result::Result as StdResult; use codegen::general; use codegen::subclass::virtual_methods; use codegen::sys::fields; +use codegen::sys::statics; use library::*; @@ -87,6 +89,23 @@ impl SubclassInfo { pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> { try!(general::start_comments(w, &env.config)); try!(general::uses(w, env, &analysis.imports)); + + try!(statics::begin(w)); + + try!(generate_extern_crates(w, env)); + try!(include_custom_modules(w, env)); + try!(statics::after_extern_crates(w)); + try!(statics::use_glib(w)); + + // match &*env.config.library_name { + // "GLib" => try!(statics::only_for_glib(w)), + // "GObject" => try!(statics::only_for_gobject(w)), + // "Gtk" => try!(statics::only_for_gtk(w)), + // _ => (), + // } + try!(writeln!(w)); + + // TODO: insert gobject-subclass uses let subclass_info = SubclassInfo::new(env, analysis); @@ -118,6 +137,71 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> Ok(()) } +// TODO: copied from sys +pub fn generate_extern_crates(w: &mut Write, env: &Env) -> Result<()> { + for library in &env.config.external_libraries { + try!(w.write_all(get_extern_crate_string(library).as_bytes())); + } + + Ok(()) +} + +// TODO: copied from sys +fn get_extern_crate_string(library: &ExternalLibrary) -> String { + format!( + "extern crate {}_sys as {};\n", + library.crate_name.replace("-", "_"), + nameutil::crate_name(&library.namespace) + ) +} + +// TODO: copied from sys +fn include_custom_modules(w: &mut Write, env: &Env) -> Result<()> { + let modules = try!(find_modules(env)); + if !modules.is_empty() { + try!(writeln!(w)); + for module in &modules { + try!(writeln!(w, "mod {};", module)); + } + try!(writeln!(w)); + for module in &modules { + try!(writeln!(w, "pub use {}::*;", module)); + } + } + + Ok(()) +} + +// TODO: copied from sys +fn find_modules(env: &Env) -> Result> { + let path = env.config.target_path.join("src"); + + let mut vec = Vec::::new(); + for entry in try!(fs::read_dir(path)) { + let path = try!(entry).path(); + let ext = match path.extension() { + Some(ext) => ext, + None => continue, + }; + if ext != "rs" { + continue; + } + let file_stem = path.file_stem().expect("No file name"); + if file_stem == "lib" { + continue; + } + let file_stem = file_stem + .to_str() + .expect("Can't convert file name to string") + .to_owned(); + vec.push(file_stem); + } + vec.sort(); + + Ok(vec) +} + + pub fn generate_impl( w: &mut Write, env: &Env, diff --git a/src/codegen/sys/lib_.rs b/src/codegen/sys/lib_.rs index ecf29a70f..ac9bc0994 100644 --- a/src/codegen/sys/lib_.rs +++ b/src/codegen/sys/lib_.rs @@ -76,7 +76,7 @@ fn generate_lib(w: &mut Write, env: &Env) -> Result<()> { Ok(()) } -fn generate_extern_crates(w: &mut Write, env: &Env) -> Result<()> { +pub fn generate_extern_crates(w: &mut Write, env: &Env) -> Result<()> { for library in &env.config.external_libraries { try!(w.write_all(get_extern_crate_string(library).as_bytes())); } diff --git a/src/codegen/sys/mod.rs b/src/codegen/sys/mod.rs index 8176713eb..6ae34e63c 100644 --- a/src/codegen/sys/mod.rs +++ b/src/codegen/sys/mod.rs @@ -7,7 +7,7 @@ pub mod ffi_type; pub mod fields; pub mod functions; mod lib_; -mod statics; +pub mod statics; mod tests; pub fn generate(env: &Env) { From 81fcbad0cf6ec23b4894a9fa958b4d8692f95ffa Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 29 May 2018 07:59:21 +0200 Subject: [PATCH 039/122] move generation of use statements to statics --- src/codegen/subclass/class_impl.rs | 78 +++--------------------------- src/codegen/subclass/mod.rs | 1 + src/codegen/subclass/statics.rs | 71 +++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 71 deletions(-) create mode 100644 src/codegen/subclass/statics.rs diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 82e872c46..cecbf4572 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -17,9 +17,9 @@ use std::fmt; use std::result::Result as StdResult; use codegen::general; -use codegen::subclass::virtual_methods; +use codegen::subclass::{virtual_methods, statics}; use codegen::sys::fields; -use codegen::sys::statics; +use codegen::sys::statics as statics_ffi; use library::*; @@ -90,12 +90,12 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> try!(general::start_comments(w, &env.config)); try!(general::uses(w, env, &analysis.imports)); - try!(statics::begin(w)); + try!(statics_ffi::begin(w)); - try!(generate_extern_crates(w, env)); - try!(include_custom_modules(w, env)); - try!(statics::after_extern_crates(w)); - try!(statics::use_glib(w)); + try!(statics::generate_extern_crates(w, env)); + try!(statics::include_custom_modules(w, env)); + try!(statics_ffi::after_extern_crates(w)); + try!(statics_ffi::use_glib(w)); // match &*env.config.library_name { // "GLib" => try!(statics::only_for_glib(w)), @@ -137,70 +137,6 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> Ok(()) } -// TODO: copied from sys -pub fn generate_extern_crates(w: &mut Write, env: &Env) -> Result<()> { - for library in &env.config.external_libraries { - try!(w.write_all(get_extern_crate_string(library).as_bytes())); - } - - Ok(()) -} - -// TODO: copied from sys -fn get_extern_crate_string(library: &ExternalLibrary) -> String { - format!( - "extern crate {}_sys as {};\n", - library.crate_name.replace("-", "_"), - nameutil::crate_name(&library.namespace) - ) -} - -// TODO: copied from sys -fn include_custom_modules(w: &mut Write, env: &Env) -> Result<()> { - let modules = try!(find_modules(env)); - if !modules.is_empty() { - try!(writeln!(w)); - for module in &modules { - try!(writeln!(w, "mod {};", module)); - } - try!(writeln!(w)); - for module in &modules { - try!(writeln!(w, "pub use {}::*;", module)); - } - } - - Ok(()) -} - -// TODO: copied from sys -fn find_modules(env: &Env) -> Result> { - let path = env.config.target_path.join("src"); - - let mut vec = Vec::::new(); - for entry in try!(fs::read_dir(path)) { - let path = try!(entry).path(); - let ext = match path.extension() { - Some(ext) => ext, - None => continue, - }; - if ext != "rs" { - continue; - } - let file_stem = path.file_stem().expect("No file name"); - if file_stem == "lib" { - continue; - } - let file_stem = file_stem - .to_str() - .expect("Can't convert file name to string") - .to_owned(); - vec.push(file_stem); - } - vec.sort(); - - Ok(vec) -} - pub fn generate_impl( w: &mut Write, diff --git a/src/codegen/subclass/mod.rs b/src/codegen/subclass/mod.rs index 968aed0a0..4247e4642 100644 --- a/src/codegen/subclass/mod.rs +++ b/src/codegen/subclass/mod.rs @@ -1,6 +1,7 @@ use env::Env; mod object; +mod statics; mod class_impls; mod class_impl; mod virtual_methods; diff --git a/src/codegen/subclass/statics.rs b/src/codegen/subclass/statics.rs new file mode 100644 index 000000000..94d801a72 --- /dev/null +++ b/src/codegen/subclass/statics.rs @@ -0,0 +1,71 @@ +use std::io::{Result, Write}; +use std::fs; + +use env::Env; +use config::ExternalLibrary; +use nameutil; + + +// TODO: copied from sys +pub fn generate_extern_crates(w: &mut Write, env: &Env) -> Result<()> { + for library in &env.config.external_libraries { + try!(w.write_all(get_extern_crate_string(library).as_bytes())); + } + + Ok(()) +} + +// TODO: copied from sys +fn get_extern_crate_string(library: &ExternalLibrary) -> String { + format!( + "extern crate {}_sys as {};\n", + library.crate_name.replace("-", "_"), + nameutil::crate_name(&library.namespace) + ) +} + +// TODO: copied from sys +pub fn include_custom_modules(w: &mut Write, env: &Env) -> Result<()> { + let modules = try!(find_modules(env)); + if !modules.is_empty() { + try!(writeln!(w)); + for module in &modules { + try!(writeln!(w, "mod {};", module)); + } + try!(writeln!(w)); + for module in &modules { + try!(writeln!(w, "pub use {}::*;", module)); + } + } + + Ok(()) +} + +// TODO: copied from sys +fn find_modules(env: &Env) -> Result> { + let path = env.config.target_path.join("src"); + + let mut vec = Vec::::new(); + for entry in try!(fs::read_dir(path)) { + let path = try!(entry).path(); + let ext = match path.extension() { + Some(ext) => ext, + None => continue, + }; + if ext != "rs" { + continue; + } + let file_stem = path.file_stem().expect("No file name"); + if file_stem == "lib" { + continue; + } + let file_stem = file_stem + .to_str() + .expect("Can't convert file name to string") + .to_owned(); + vec.push(file_stem); + } + vec.sort(); + + Ok(vec) +} From a1eb6dbb7fac350a65fac260c8b4594f985c49bd Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 29 May 2018 20:59:04 +0200 Subject: [PATCH 040/122] start making stuff specific for interfaces --- src/analysis/object.rs | 6 ++++++ src/codegen/subclass/class_impl.rs | 22 +++++++++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/analysis/object.rs b/src/analysis/object.rs index 83226e91b..6d662775f 100644 --- a/src/analysis/object.rs +++ b/src/analysis/object.rs @@ -377,6 +377,11 @@ pub fn interface(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option Option Result<()> { + try!(writeln!(w)); - try!(writeln!( - w, - "any_impl!({}, {});", - object_analysis.subclass_base_trait_name, object_analysis.subclass_impl_trait_name - )); + + + if object_analysis.is_interface{ + try!(writeln!( + w, + "any_impl!({});", + object_analysis.subclass_base_trait_name + )); + }else{ + try!(writeln!( + w, + "any_impl!({}, {});", + object_analysis.subclass_base_trait_name, object_analysis.subclass_impl_trait_name + )); + } + Ok(()) } From 31ef375d37ee40c41fbedd861d512f734143adb7 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 30 May 2018 07:32:39 +0200 Subject: [PATCH 041/122] ignore a lot of generations for interfaces --- src/codegen/subclass/class_impl.rs | 102 +++++++++++++++--------- src/codegen/subclass/virtual_methods.rs | 25 ++++++ 2 files changed, 88 insertions(+), 39 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 36ce19480..553b5b3aa 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -112,25 +112,22 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> try!(generate_impl(w, env, analysis, &subclass_info)); - try!(generate_impl_ext(w, env, analysis, &subclass_info)); + if !analysis.is_interface{ + try!(generate_impl_ext(w, env, analysis, &subclass_info)); + } try!(generate_any_impl(w, env, analysis, &subclass_info)); - try!(generate_base(w, env, analysis, &subclass_info)); - - try!(generate_ext(w, env, analysis, &subclass_info)); - - try!(generate_glib_wrapper(w, env, analysis, &subclass_info)); - - try!(generate_impl_base(w, env, analysis, &subclass_info)); - - try!(generate_class(w, env, analysis, &subclass_info)); - - try!(generate_parent_impls(w, env, analysis, &subclass_info)); - - try!(generate_box_impl(w, env, analysis, &subclass_info)); - - try!(generate_impl_objecttype(w, env, analysis, &subclass_info)); + if !analysis.is_interface{ + try!(generate_base(w, env, analysis, &subclass_info)); + try!(generate_ext(w, env, analysis, &subclass_info)); + try!(generate_glib_wrapper(w, env, analysis, &subclass_info)); + try!(generate_impl_base(w, env, analysis, &subclass_info)); + try!(generate_class(w, env, analysis, &subclass_info)); + try!(generate_parent_impls(w, env, analysis, &subclass_info)); + try!(generate_box_impl(w, env, analysis, &subclass_info)); + try!(generate_impl_objecttype(w, env, analysis, &subclass_info)); + } try!(generate_extern_c_funcs(w, env, analysis, &subclass_info)); @@ -144,35 +141,62 @@ pub fn generate_impl( object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo, ) -> Result<()> { - let mut parents = subclass_info.parent_names(env, "_subclass"); - - let parent_impls: Vec = parents - .iter() - .map(|ref p| format!(" {}Impl +", p)) - .collect(); - let parent_objs = parent_impls.join(""); // start impl trait try!(writeln!(w)); - try!(writeln!( - w, - "pub trait {}:{} ObjectImpl + AnyImpl + 'static {{", - object_analysis.subclass_impl_trait_name, - object_analysis.subclass_base_trait_name, - parent_objs - )); - info!("supertypes, {:?}", parents); + if object_analysis.is_interface{ - for method_analysis in &object_analysis.virtual_methods { - try!(virtual_methods::generate_default_impl( + // TODO: Can I use a generic parent 'T' here, too? That'd be easier + try!(writeln!( w, - env, - object_analysis, - method_analysis, - subclass_info, - 1 + "pub trait {}: AnyImpl + 'static {{", + object_analysis.subclass_impl_trait_name )); + }else{ + + let parents = subclass_info.parent_names(env, "_subclass"); + + let parent_impls: Vec = parents + .iter() + .map(|ref p| format!(" {}Impl +", p)) + .collect(); + let parent_objs = parent_impls.join(""); + + try!(writeln!( + w, + "pub trait {}:{} ObjectImpl + AnyImpl + 'static {{", + object_analysis.subclass_impl_trait_name, + object_analysis.subclass_base_trait_name, + parent_objs + )); + + info!("supertypes, {:?}", parents); + } + + + for method_analysis in &object_analysis.virtual_methods { + + if object_analysis.is_interface{ + try!(virtual_methods::generate_declaration( + w, + env, + object_analysis, + method_analysis, + subclass_info, + 1 + )); + }else{ + + try!(virtual_methods::generate_default_impl( + w, + env, + object_analysis, + method_analysis, + subclass_info, + 1 + )); + } } //end impl trait @@ -272,7 +296,7 @@ fn generate_any_impl( try!(writeln!( w, "any_impl!({});", - object_analysis.subclass_base_trait_name + object_analysis.subclass_impl_trait_name )); }else{ try!(writeln!( diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index b3a55f22f..74dfb10bb 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -70,6 +70,31 @@ pub fn generate_default_impl( } +pub fn generate_declaration( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + method_analysis: &analysis::virtual_methods::Info, + subclass_info: &SubclassInfo, + indent: usize, +) -> Result<()> { + + try!(writeln!(w)); + + let parent_name = &method_analysis.parameters.rust_parameters[0].name; + let declr = declaration(env, method_analysis, None, Some(parent_name)); + + try!(writeln!( + w, + "{}{};", + tabs(indent), + declr, + )); + + Ok(()) +} + + pub fn default_impl_body_chunk(env: &Env, object_analysis: &analysis::object::Info, method_analysis: &analysis::virtual_methods::Info, From c25c4736cb69ab5a1c60f1f523d7a220faaa557a Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 30 May 2018 22:39:21 +0200 Subject: [PATCH 042/122] stubs for generating interfaces --- src/codegen/subclass/class_impl.rs | 48 ++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 553b5b3aa..c9f90d1fa 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -127,6 +127,8 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> try!(generate_parent_impls(w, env, analysis, &subclass_info)); try!(generate_box_impl(w, env, analysis, &subclass_info)); try!(generate_impl_objecttype(w, env, analysis, &subclass_info)); + }else{ + try!(generate_impl_static(w, env, analysis, &subclass_info)); } try!(generate_extern_c_funcs(w, env, analysis, &subclass_info)); @@ -605,6 +607,38 @@ fn generate_impl_objecttype( Ok(()) } +fn generate_impl_static( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + subclass_info: &SubclassInfo, +) -> Result<()> { + try!(writeln!(w)); + + writeln!( + w, + "pub trait {}Static: 'static {{", + object_analysis.subclass_impl_trait_name + ); + + try!(writeln!(w, "{}fn get_impl<'a>(&self, imp: &'a T::ImplType) -> &'a {};", + tabs(1), + object_analysis.subclass_impl_trait_name + )); + + + // TODO: What other functions are needed here?? + + + writeln!( + w, + "}}" + ); + + Ok(()) +} + + fn generate_extern_c_funcs( w: &mut Write, env: &Env, @@ -624,5 +658,19 @@ fn generate_extern_c_funcs( )); } + if object_analysis.is_interface{ + + // TODO: generate *_get_type( + // see: https://github.com/sdroege/gst-plugin-rs/blob/25af5afb2bb9dfea79a13fd306d4b7fe36d26496/gst-plugin/src/uri_handler.rs#L40 + + // TODO: generate *_init( + // see: https://github.com/sdroege/gst-plugin-rs/blob/25af5afb2bb9dfea79a13fd306d4b7fe36d26496/gst-plugin/src/uri_handler.rs#L104 + + // TODO: generate register_*>( + // see: https://github.com/sdroege/gst-plugin-rs/blob/25af5afb2bb9dfea79a13fd306d4b7fe36d26496/gst-plugin/src/uri_handler.rs#L123 + } + + + Ok(()) } From bb53190dc30de47b441b538d8537b886883edcb0 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 31 May 2018 01:01:31 +0200 Subject: [PATCH 043/122] improve argument conversion in base trait --- .../subclass/virtual_method_body_chunks.rs | 342 +++++++++++++++++- src/codegen/subclass/virtual_methods.rs | 5 + 2 files changed, 332 insertions(+), 15 deletions(-) diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index d59acce75..80546024f 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -16,20 +16,21 @@ use library::{self, ParameterDirection}; use nameutil; use writer::ToCode; -use codegen::function_body_chunk::{c_type_mem_mode, Parameter, ReturnValue}; -use codegen::parameter::*; +use codegen::function_body_chunk::{c_type_mem_mode, Parameter, ReturnValue, OutMemMode}; #[derive(Default)] pub struct Builder { object_name: String, object_class_c_type: String, ffi_crate_name: String, + glib_name: String, method_name: String, parameters: Vec, transformations: Vec, ret: ReturnValue, outs_as_return: bool, outs_mode: Mode, + assertion: SafetyAssertionMode, } impl Builder { @@ -42,6 +43,11 @@ impl Builder { self } + pub fn glib_name(&mut self, name: &str) -> &mut Builder { + self.glib_name = name.into(); + self + } + pub fn object_class_c_type(&mut self, c_class_type: &str) -> &mut Builder { self.object_class_c_type = c_class_type.into(); self @@ -57,14 +63,21 @@ impl Builder { self } + pub fn assertion(&mut self, assertion: SafetyAssertionMode) -> &mut Builder { + self.assertion = assertion; + self + } + pub fn ret(&mut self, ret: &return_value::Info) -> &mut Builder { self.ret = ReturnValue { ret: ret.clone() }; self } + pub fn parameter(&mut self) -> &mut Builder { self.parameters.push(Parameter::In); self } + pub fn out_parameter(&mut self, env: &Env, parameter: &AnalysisCParameter) -> &mut Builder { let mem_mode = c_type_mem_mode(env, parameter); self.parameters.push(Parameter::Out { @@ -107,58 +120,84 @@ impl Builder { as_return: true, }); + + + //TODO: return variables? body.push(Chunk::Custom(".unwrap_or(())".to_owned())); + let unsafe_ = Chunk::Unsafe(body); let mut chunks = Vec::new(); + + self.add_into_conversion(&mut chunks); + self.add_in_array_lengths(&mut chunks); + // self.add_assertion(&mut chunks); + chunks.push(unsafe_); Chunk::Chunks(chunks) } pub fn generate_extern_c_func(&self, env: &Env) -> Chunk { - let mut chunks = Vec::new(); + let mut body = Vec::new(); - chunks.push(Chunk::Custom("callback_guard!();".to_owned())); - chunks.push(Chunk::Custom("floating_reference_guard!(ptr);".to_owned())); + body.push(Chunk::Custom("callback_guard!();".to_owned())); + body.push(Chunk::Custom("floating_reference_guard!(ptr);".to_owned())); - chunks.push(Chunk::Let{ is_mut:false, + body.push(Chunk::Let{ is_mut:false, name: self.object_name.to_lowercase(), value: Box::new(Chunk::Custom("&*(ptr as *mut T::InstanceStructType)".to_owned())), type_: None }); - chunks.push(Chunk::Let{ is_mut:false, + body.push(Chunk::Let{ is_mut:false, name: "wrap".to_owned(), value: Box::new(Chunk::Custom("from_glib_borrow(ptr as *mut T::InstanceStructType)".to_owned())), type_: Some(Box::new(Chunk::Custom("T".to_owned()))) }); - chunks.push(Chunk::Let{ is_mut:false, + body.push(Chunk::Let{ is_mut:false, name: "imp".to_owned(), value: Box::new(Chunk::Custom(format!("{}.get_impl()", self.object_name.to_lowercase()).to_owned())), type_: None }); - chunks.push(Chunk::Custom(format!("imp.{}({})", + + + body.push(Chunk::Custom(format!("imp.{}({})", self.method_name, &"").to_owned())); - Chunk::Chunks(chunks) + Chunk::Chunks(body) } fn base_impl_body_chunk(&self) -> Chunk { + + let mut body = Vec::new(); + + if self.outs_as_return { + self.write_out_variables(&mut body); + } + + let call = self.generate_ffi_call(Some("f".to_owned())); + let call = self.generate_ffi_call_conversion(call); + + let ret = self.generate_out_return(); + let (call, ret) = self.apply_outs_mode(call, ret); + + body.push(call); + if let Some(chunk) = ret { + body.push(chunk); + } + Chunk::Closure { arguments: vec![Chunk::Custom("f".to_owned())], - body: Box::new(Chunk::Call { - func_name: "f".to_owned(), - arguments: self.generate_func_parameters(), - as_return: true, - }), + body: Box::new(Chunk::Chunks(body) + ), } } @@ -205,4 +244,277 @@ impl Builder { } params } + + fn write_out_variables(&self, v: &mut Vec) { + let outs = self.get_outs(); + for par in outs { + if let Out { + ref parameter, + ref mem_mode, + } = *par + { + let val = self.get_uninitialized(mem_mode); + let chunk = Chunk::Let { + name: parameter.name.clone(), + is_mut: true, + value: Box::new(val), + type_: None, + }; + v.push(chunk); + } + } + } + fn get_uninitialized(&self, mem_mode: &OutMemMode) -> Chunk { + use self::OutMemMode::*; + match *mem_mode { + Uninitialized => Chunk::Uninitialized, + UninitializedNamed(ref name) => Chunk::UninitializedNamed { name: name.clone() }, + NullPtr => Chunk::NullPtr, + NullMutPtr => Chunk::NullMutPtr, + } + } + + fn get_outs(&self) -> Vec<&Parameter> { + self.parameters + .iter() + .filter_map(|par| if let Out { .. } = *par { + Some(par) + } else { + None + }) + .collect() + } + fn get_outs_without_error(&self) -> Vec<&Parameter> { + self.parameters + .iter() + .filter_map(|par| if let Out { ref parameter, .. } = *par { + if parameter.is_error { + None + } else { + Some(par) + } + } else { + None + }) + .collect() + } + + fn generate_ffi_call(&self, func_name: Option) -> Chunk { + let params = self.generate_func_parameters(); + let func = Chunk::Call { + func_name: func_name.unwrap_or(self.glib_name.clone()), + arguments: params, + as_return: true, + }; + func + } + fn generate_ffi_call_conversion(&self, call: Chunk) -> Chunk { + Chunk::FfiCallConversion { + ret: self.ret.ret.clone(), + array_length_name: self.find_array_length_name(""), + call: Box::new(call), + } + } + fn find_array_length_name(&self, array_name_: &str) -> Option { + self.transformations + .iter() + .filter_map(|tr| { + if let TransformationType::Length { + ref array_name, + ref array_length_name, + .. + } = tr.transformation_type + { + if array_name == array_name_ { + Some(array_length_name.clone()) + } else { + None + } + } else { + None + } + }) + .next() + } + + fn generate_out_return(&self) -> Option { + if !self.outs_as_return { + return None; + } + let outs = self.get_outs_without_error(); + let mut chs: Vec = Vec::with_capacity(outs.len()); + for par in outs { + if let Out { + ref parameter, + ref mem_mode, + } = *par + { + if self.transformations + .iter() + .any(|tr| match tr.transformation_type { + TransformationType::Length { + ref array_length_name, + .. + } if array_length_name == ¶meter.name => + { + true + } + _ => false, + }) { + continue; + } + + chs.push(self.out_parameter_to_return(parameter, mem_mode)); + } + } + let chunk = Chunk::Tuple(chs, TupleMode::Auto); + Some(chunk) + } + fn out_parameter_to_return( + &self, + parameter: ¶meter_ffi_call_out::Parameter, + mem_mode: &OutMemMode, + ) -> Chunk { + let value = Chunk::Custom(parameter.name.clone()); + if let OutMemMode::UninitializedNamed(_) = *mem_mode { + value + } else { + Chunk::FromGlibConversion { + mode: parameter.into(), + array_length_name: self.find_array_length_name(¶meter.name), + value: Box::new(value), + } + } + } + fn apply_outs_mode(&self, call: Chunk, ret: Option) -> (Chunk, Option) { + use analysis::out_parameters::Mode::*; + match self.outs_mode { + None => (call, ret), + Normal => (call, ret), + Optional => { + let call = Chunk::Let { + name: "ret".into(), + is_mut: false, + value: Box::new(call), + type_: Option::None, + }; + let ret = ret.expect("No return in optional outs mode"); + let ret = Chunk::OptionalReturn { + condition: "ret".into(), + value: Box::new(ret), + }; + (call, Some(ret)) + } + Combined => { + let call = Chunk::Let { + name: "ret".into(), + is_mut: false, + value: Box::new(call), + type_: Option::None, + }; + let mut ret = ret.expect("No return in combined outs mode"); + if let Chunk::Tuple(ref mut vec, _) = ret { + vec.insert(0, Chunk::Custom("ret".into())); + } + (call, Some(ret)) + } + Throws(use_ret) => { + //extracting original FFI function call + let (boxed_call, array_length_name, ret_info) = if let Chunk::FfiCallConversion { + call: inner, + array_length_name, + ret: ret_info, + } = call + { + (inner, array_length_name, ret_info) + } else { + panic!("Call without Chunk::FfiCallConversion") + }; + let call = if use_ret { + Chunk::Let { + name: "ret".into(), + is_mut: false, + value: boxed_call, + type_: Option::None, + } + } else { + Chunk::Let { + name: "_".into(), + is_mut: false, + value: boxed_call, + type_: Option::None, + } + }; + let mut ret = ret.expect("No return in throws outs mode"); + if let Chunk::Tuple(ref mut vec, ref mut mode) = ret { + *mode = TupleMode::WithUnit; + if use_ret { + let val = Chunk::Custom("ret".into()); + let conv = Chunk::FfiCallConversion { + call: Box::new(val), + array_length_name, + ret: ret_info, + }; + vec.insert(0, conv); + } + } else { + panic!("Return is not Tuple") + } + ret = Chunk::ErrorResultReturn { + value: Box::new(ret), + }; + (call, Some(ret)) + } + } + } + + fn add_into_conversion(&self, chunks: &mut Vec) { + for trans in &self.transformations { + if let TransformationType::Into { + ref name, + with_stash, + } = trans.transformation_type + { + let value = Chunk::Custom(format!("{}.into()", name)); + chunks.push(Chunk::Let { + name: name.clone(), + is_mut: false, + value: Box::new(value), + type_: None, + }); + if with_stash { + let value = Chunk::Custom(format!("{}.to_glib_none()", name)); + chunks.push(Chunk::Let { + name: name.clone(), + is_mut: false, + value: Box::new(value), + type_: None, + }); + } + } + } + } + + fn add_in_array_lengths(&self, chunks: &mut Vec) { + for trans in &self.transformations { + if let TransformationType::Length { + ref array_name, + ref array_length_name, + ref array_length_type, + } = trans.transformation_type + { + if let Parameter::In = self.parameters[trans.ind_c] { + let value = + Chunk::Custom(format!("{}.len() as {}", array_name, array_length_type)); + chunks.push(Chunk::Let { + name: array_length_name.clone(), + is_mut: false, + value: Box::new(value), + type_: None, + }); + } + } + } + } + } diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 74dfb10bb..8a615b432 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -452,11 +452,14 @@ pub fn body_chunk_builder(env: &Env, builder.object_name(&object_analysis.name) .object_class_c_type(object_analysis.c_class_type.as_ref().unwrap()) .ffi_crate_name(&env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name) + .glib_name(&method_analysis.glib_name) .method_name(&method_analysis.name) + .assertion(method_analysis.assertion) .ret(&method_analysis.ret) .transformations(&method_analysis.parameters.transformations) .outs_mode(method_analysis.outs.mode); + for par in &method_analysis.parameters.c_parameters { if outs_as_return && method_analysis.outs.iter().any(|p| p.name == par.name) { builder.out_parameter(env, par); @@ -487,6 +490,8 @@ pub fn extern_c_func_body_chunk(env: &Env, { let mut builder = body_chunk_builder(env, object_analysis, method_analysis, subclass_info); + info!("TRAMPOLINE {:?}", method_analysis.trampoline); + builder.generate_extern_c_func(env) } From 07e6920c71da2f4335d608c00c7fd561edeed542 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 31 May 2018 18:20:59 +0200 Subject: [PATCH 044/122] wip: generate the interface type init function --- src/codegen/subclass/class_impl.rs | 35 +++++++++++++++++- src/codegen/subclass/virtual_methods.rs | 47 +++++++++++++++++++++++-- 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index c9f90d1fa..b3d564407 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -125,10 +125,11 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> try!(generate_impl_base(w, env, analysis, &subclass_info)); try!(generate_class(w, env, analysis, &subclass_info)); try!(generate_parent_impls(w, env, analysis, &subclass_info)); + try!(generate_interface_impls(w, env, analysis, &subclass_info)); try!(generate_box_impl(w, env, analysis, &subclass_info)); try!(generate_impl_objecttype(w, env, analysis, &subclass_info)); }else{ - try!(generate_impl_static(w, env, analysis, &subclass_info)); + // try!(generate_impl_static(w, env, analysis, &subclass_info)); } try!(generate_extern_c_funcs(w, env, analysis, &subclass_info)); @@ -467,6 +468,30 @@ fn generate_parent_impls( Ok(()) } +fn generate_interface_impls( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + subclass_info: &SubclassInfo, +) -> Result<()> { + try!(writeln!(w)); + + writeln!(w, "// FIXME: Boilerplate"); + if subclass_info.parents.len() > 0 { + for parent in &subclass_info.parents { + let t = env.library.type_(parent.type_id); + try!(writeln!( + w, + "unsafe impl {par}ClassExt<{obj}> for {obj}Class {{}}", + obj = object_analysis.name, + par = t.get_name() + )); + } + } + + Ok(()) +} + fn generate_box_impl( w: &mut Write, env: &Env, @@ -666,6 +691,14 @@ fn generate_extern_c_funcs( // TODO: generate *_init( // see: https://github.com/sdroege/gst-plugin-rs/blob/25af5afb2bb9dfea79a13fd306d4b7fe36d26496/gst-plugin/src/uri_handler.rs#L104 + try!(virtual_methods::generate_interface_init( + w, + env, + object_analysis, + subclass_info, + 0 + )); + // TODO: generate register_*>( // see: https://github.com/sdroege/gst-plugin-rs/blob/25af5afb2bb9dfea79a13fd306d4b7fe36d26496/gst-plugin/src/uri_handler.rs#L123 } diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 8a615b432..6395e6abe 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -399,6 +399,8 @@ pub fn generate_extern_c_func( try!(writeln!(w)); + // TODO: use Chunk::ExternCFunc + try!(writeln!( w, "unsafe extern \"C\" fn {}_{}", @@ -490,8 +492,6 @@ pub fn extern_c_func_body_chunk(env: &Env, { let mut builder = body_chunk_builder(env, object_analysis, method_analysis, subclass_info); - info!("TRAMPOLINE {:?}", method_analysis.trampoline); - builder.generate_extern_c_func(env) } @@ -547,3 +547,46 @@ fn function_parameter(env: &Env, par: &analysis::function_parameters::CParameter }; (commented, res) } + +pub fn generate_interface_init( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + subclass_info: &SubclassInfo, + indent: usize, +) -> Result<()> { + + try!(writeln!( + w, + " +unsafe extern \"C\" fn {}_init + iface: glib_ffi::gpointer, + iface_data: glib_ffi::gpointer, +) {", + object_analysis.name.to_lowercase() + )); + + // unsafe extern "C" fn uri_handler_init( + // iface: glib_ffi::gpointer, + // iface_data: glib_ffi::gpointer, + // ) { + // callback_guard!(); + // let uri_handler_iface = &mut *(iface as *mut gst_ffi::GstURIHandlerInterface); + // + // let iface_type = (*(iface as *const gobject_ffi::GTypeInterface)).g_type; + // let type_ = (*(iface as *const gobject_ffi::GTypeInterface)).g_instance_type; + // let klass = &mut *(gobject_ffi::g_type_class_ref(type_) as *mut ClassStruct); + // let interfaces_static = &mut *(klass.interfaces_static as *mut Vec<_>); + // interfaces_static.push((iface_type, iface_data)); + // + // uri_handler_iface.get_type = Some(uri_handler_get_type::); + // uri_handler_iface.get_protocols = Some(uri_handler_get_protocols::); + // uri_handler_iface.get_uri = Some(uri_handler_get_uri::); + // uri_handler_iface.set_uri = Some(uri_handler_set_uri::); + // } + + try!(writeln!(w,"}}")); + + Ok(()) + +} From 118b0837d9615b99607ec20564393e1b92639d89 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 31 May 2018 23:10:03 +0200 Subject: [PATCH 045/122] generate interface init boilerplate --- .../subclass/virtual_method_body_chunks.rs | 71 ++++++++++++++++++- src/codegen/subclass/virtual_methods.rs | 31 ++++---- 2 files changed, 80 insertions(+), 22 deletions(-) diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index 80546024f..3a1f8f794 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -132,7 +132,6 @@ impl Builder { let mut chunks = Vec::new(); self.add_into_conversion(&mut chunks); - self.add_in_array_lengths(&mut chunks); // self.add_assertion(&mut chunks); chunks.push(unsafe_); @@ -173,8 +172,6 @@ impl Builder { Chunk::Chunks(body) } - - fn base_impl_body_chunk(&self) -> Chunk { let mut body = Vec::new(); @@ -183,6 +180,8 @@ impl Builder { self.write_out_variables(&mut body); } + self.add_in_array_lengths(&mut body); + let call = self.generate_ffi_call(Some("f".to_owned())); let call = self.generate_ffi_call_conversion(call); @@ -201,6 +200,71 @@ impl Builder { } } + pub fn generate_interface_init(&self, env: &Env, virtual_methods: &Vec) -> Chunk { + + let mut body = Vec::new(); + + let iface_name = format!("{}_iface", self.object_name.to_lowercase()).to_owned(); + let iface_get_type = format!("{}_get_type", self.object_name.to_lowercase()).to_owned(); + + body.push(Chunk::Custom("callback_guard!();".to_owned())); + body.push(Chunk::Let { + name: iface_name.clone(), + is_mut: false, + value: Box::new(Chunk::Custom(format!("&mut *(iface as *mut {}::{})", + self.ffi_crate_name, self.object_class_c_type + ).to_owned(), + )), + type_: None, + }); + body.push(Chunk::Let { + name: "iface_type".to_owned(), + is_mut: false, + value: Box::new(Chunk::Custom("(*(iface as *const gobject_ffi::GTypeInterface)).g_type".to_owned(), + )), + type_: None, + }); + body.push(Chunk::Let { + name: "type_".to_owned(), + is_mut: false, + value: Box::new(Chunk::Custom("(*(iface as *const gobject_ffi::GTypeInterface)).g_instance_type".to_owned(), + )), + type_: None, + }); + + body.push(Chunk::Let { + name: "klass".to_owned(), + is_mut: false, + value: Box::new(Chunk::Custom("&mut *(gobject_ffi::g_type_class_ref(type_) as *mut ClassStruct)".to_owned(), + )), + type_: None, + }); + + body.push(Chunk::Let { + name: "interfaces_static".to_owned(), + is_mut: false, + value: Box::new(Chunk::Custom("&mut *(klass.interfaces_static as *mut Vec<_>)".to_owned(), + )), + type_: None, + }); + + body.push(Chunk::Custom("interfaces_static.push((iface_type, iface_data))".to_owned())); + + + for method_analysis in virtual_methods { + body.push(Chunk::Custom( + format!("{iface}.{mname} = Some({type_fn}_{mname}::);", + mname=method_analysis.name, + iface=iface_name, + type_fn=iface_get_type).to_owned() + )); + } + + + Chunk::Chunks(body) + + } + fn let_klass(&self) -> Chunk { Chunk::Let { name: "klass".to_owned(), @@ -225,6 +289,7 @@ impl Builder { } } + fn generate_func_parameters(&self) -> Vec { let mut params = Vec::new(); for trans in &self.transformations { diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 6395e6abe..abed26fa0 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -562,28 +562,21 @@ pub fn generate_interface_init( unsafe extern \"C\" fn {}_init iface: glib_ffi::gpointer, iface_data: glib_ffi::gpointer, -) {", +) {{", object_analysis.name.to_lowercase() )); - // unsafe extern "C" fn uri_handler_init( - // iface: glib_ffi::gpointer, - // iface_data: glib_ffi::gpointer, - // ) { - // callback_guard!(); - // let uri_handler_iface = &mut *(iface as *mut gst_ffi::GstURIHandlerInterface); - // - // let iface_type = (*(iface as *const gobject_ffi::GTypeInterface)).g_type; - // let type_ = (*(iface as *const gobject_ffi::GTypeInterface)).g_instance_type; - // let klass = &mut *(gobject_ffi::g_type_class_ref(type_) as *mut ClassStruct); - // let interfaces_static = &mut *(klass.interfaces_static as *mut Vec<_>); - // interfaces_static.push((iface_type, iface_data)); - // - // uri_handler_iface.get_type = Some(uri_handler_get_type::); - // uri_handler_iface.get_protocols = Some(uri_handler_get_protocols::); - // uri_handler_iface.get_uri = Some(uri_handler_get_uri::); - // uri_handler_iface.set_uri = Some(uri_handler_set_uri::); - // } + let mut builder = Builder::new(); + + builder.object_name(&object_analysis.name) + .object_class_c_type(object_analysis.c_class_type.as_ref().unwrap()) + .ffi_crate_name(&env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name); + + + let body = builder.generate_interface_init(env, &object_analysis.virtual_methods).to_code(env); + for s in body { + try!(writeln!(w, "{}{}", tabs(indent+1), s)); + } try!(writeln!(w,"}}")); From bba7f5dfacb0937f34b4417adfed51214870f734 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 1 Jun 2018 08:06:55 +0200 Subject: [PATCH 046/122] tailor extern c functions for interfaces --- .../subclass/virtual_method_body_chunks.rs | 258 ++++++++++++------ src/codegen/subclass/virtual_methods.rs | 6 +- 2 files changed, 177 insertions(+), 87 deletions(-) diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index 3a1f8f794..409def9e7 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -16,7 +16,7 @@ use library::{self, ParameterDirection}; use nameutil; use writer::ToCode; -use codegen::function_body_chunk::{c_type_mem_mode, Parameter, ReturnValue, OutMemMode}; +use codegen::function_body_chunk::{c_type_mem_mode, OutMemMode, Parameter, ReturnValue}; #[derive(Default)] pub struct Builder { @@ -120,13 +120,9 @@ impl Builder { as_return: true, }); - - - //TODO: return variables? body.push(Chunk::Custom(".unwrap_or(())".to_owned())); - let unsafe_ = Chunk::Unsafe(body); let mut chunks = Vec::new(); @@ -138,42 +134,122 @@ impl Builder { Chunk::Chunks(chunks) } - pub fn generate_extern_c_func(&self, env: &Env) -> Chunk { + pub fn generate_object_extern_c_func(&self, env: &Env) -> Chunk { let mut body = Vec::new(); - body.push(Chunk::Custom("callback_guard!();".to_owned())); - body.push(Chunk::Custom("floating_reference_guard!(ptr);".to_owned())); + body.push(self.callback_guard()); + body.push(self.floating_reference_guard("ptr")); + + body.push(Chunk::Let { + is_mut: false, + name: self.object_name.to_lowercase(), + value: Box::new(Chunk::Custom( + "&*(ptr as *mut T::InstanceStructType)".to_owned(), + )), + type_: None, + }); + + body.push(Chunk::Let { + is_mut: false, + name: "wrap".to_owned(), + value: Box::new(Chunk::Custom( + "from_glib_borrow(ptr as *mut T::InstanceStructType)".to_owned(), + )), + type_: Some(Box::new(Chunk::Custom("T".to_owned()))), + }); + + body.push(Chunk::Let { + is_mut: false, + name: "imp".to_owned(), + value: Box::new(Chunk::Custom( + format!("{}.get_impl()", self.object_name.to_lowercase()).to_owned(), + )), + type_: None, + }); - body.push(Chunk::Let{ is_mut:false, - name: self.object_name.to_lowercase(), - value: Box::new(Chunk::Custom("&*(ptr as *mut T::InstanceStructType)".to_owned())), - type_: None - }); + // TODO: call imp function + body.push(Chunk::Custom( + format!("imp.{}({})", self.method_name, &"").to_owned(), + )); - body.push(Chunk::Let{ is_mut:false, - name: "wrap".to_owned(), - value: Box::new(Chunk::Custom("from_glib_borrow(ptr as *mut T::InstanceStructType)".to_owned())), - type_: Some(Box::new(Chunk::Custom("T".to_owned()))) - }); + Chunk::Chunks(body) + } - body.push(Chunk::Let{ is_mut:false, - name: "imp".to_owned(), - value: Box::new(Chunk::Custom(format!("{}.get_impl()", - self.object_name.to_lowercase()).to_owned())), - type_: None - }); + pub fn generate_interface_extern_c_func(&self, env: &Env) -> Chunk { + let mut body = Vec::new(); + + body.push(self.callback_guard()); + body.push(self.floating_reference_guard("ptr")); + + body.push(Chunk::Let { + is_mut: false, + name: "klass".to_owned(), + value: Box::new(Chunk::Custom( + format!( + "&**({} as *const *const ClassStruct)", + self.object_name.to_lowercase() + ).to_owned(), + )), + type_: None, + }); + body.push(Chunk::Let { + is_mut: false, + name: "interface_static".to_owned(), + value: Box::new(Chunk::Custom( + format!( + "klass.get_interface_static({}::{}_get_type()) + as *const URIHandlerStatic", + self.ffi_crate_name, + self.object_name.to_lowercase() + ).to_owned(), + )), + type_: None, + }); + body.push(Chunk::Let { + is_mut: false, + name: "interface_static".to_owned(), + value: Box::new(Chunk::Custom( + format!( + "&*({} as *const T::InstanceStructType)", + self.object_name.to_lowercase() + ).to_owned(), + )), + type_: None, + }); + body.push(Chunk::Let { + is_mut: false, + name: "imp".to_owned(), + value: Box::new(Chunk::Custom("instance.get_impl()".to_owned())), + type_: None, + }); + body.push(Chunk::Let { + is_mut: false, + name: "imp".to_owned(), + value: Box::new(Chunk::Custom( + "(*(*interface_static).imp_static).get_impl(imp)".to_owned(), + )), + type_: None, + }); - body.push(Chunk::Custom(format!("imp.{}({})", - self.method_name, - &"").to_owned())); + // TODO: call imp function + body.push(Chunk::Custom( + format!("imp.{}({})", self.method_name, &"").to_owned(), + )); Chunk::Chunks(body) } - fn base_impl_body_chunk(&self) -> Chunk { + fn callback_guard(&self) -> Chunk { + Chunk::Custom("callback_guard!();".to_owned()) + } + fn floating_reference_guard(&self, p: &str) -> Chunk { + Chunk::Custom(format!("floating_reference_guard!({});", p).to_owned()) + } + + fn base_impl_body_chunk(&self) -> Chunk { let mut body = Vec::new(); if self.outs_as_return { @@ -195,74 +271,82 @@ impl Builder { Chunk::Closure { arguments: vec![Chunk::Custom("f".to_owned())], - body: Box::new(Chunk::Chunks(body) - ), + body: Box::new(Chunk::Chunks(body)), } } - pub fn generate_interface_init(&self, env: &Env, virtual_methods: &Vec) -> Chunk { - + pub fn generate_interface_init( + &self, + env: &Env, + virtual_methods: &Vec, + ) -> Chunk { let mut body = Vec::new(); let iface_name = format!("{}_iface", self.object_name.to_lowercase()).to_owned(); - let iface_get_type = format!("{}_get_type", self.object_name.to_lowercase()).to_owned(); - body.push(Chunk::Custom("callback_guard!();".to_owned())); + body.push(self.callback_guard()); body.push(Chunk::Let { - name: iface_name.clone(), - is_mut: false, - value: Box::new(Chunk::Custom(format!("&mut *(iface as *mut {}::{})", - self.ffi_crate_name, self.object_class_c_type - ).to_owned(), - )), - type_: None, - }); + name: iface_name.clone(), + is_mut: false, + value: Box::new(Chunk::Custom( + format!( + "&mut *(iface as *mut {}::{})", + self.ffi_crate_name, self.object_class_c_type + ).to_owned(), + )), + type_: None, + }); body.push(Chunk::Let { - name: "iface_type".to_owned(), - is_mut: false, - value: Box::new(Chunk::Custom("(*(iface as *const gobject_ffi::GTypeInterface)).g_type".to_owned(), - )), - type_: None, - }); + name: "iface_type".to_owned(), + is_mut: false, + value: Box::new(Chunk::Custom( + "(*(iface as *const gobject_ffi::GTypeInterface)).g_type".to_owned(), + )), + type_: None, + }); body.push(Chunk::Let { - name: "type_".to_owned(), - is_mut: false, - value: Box::new(Chunk::Custom("(*(iface as *const gobject_ffi::GTypeInterface)).g_instance_type".to_owned(), - )), - type_: None, - }); + name: "type_".to_owned(), + is_mut: false, + value: Box::new(Chunk::Custom( + "(*(iface as *const gobject_ffi::GTypeInterface)).g_instance_type".to_owned(), + )), + type_: None, + }); body.push(Chunk::Let { - name: "klass".to_owned(), - is_mut: false, - value: Box::new(Chunk::Custom("&mut *(gobject_ffi::g_type_class_ref(type_) as *mut ClassStruct)".to_owned(), - )), - type_: None, - }); + name: "klass".to_owned(), + is_mut: false, + value: Box::new(Chunk::Custom( + "&mut *(gobject_ffi::g_type_class_ref(type_) as *mut ClassStruct)".to_owned(), + )), + type_: None, + }); body.push(Chunk::Let { - name: "interfaces_static".to_owned(), - is_mut: false, - value: Box::new(Chunk::Custom("&mut *(klass.interfaces_static as *mut Vec<_>)".to_owned(), - )), - type_: None, - }); - - body.push(Chunk::Custom("interfaces_static.push((iface_type, iface_data))".to_owned())); + name: "interfaces_static".to_owned(), + is_mut: false, + value: Box::new(Chunk::Custom( + "&mut *(klass.interfaces_static as *mut Vec<_>)".to_owned(), + )), + type_: None, + }); + body.push(Chunk::Custom( + "interfaces_static.push((iface_type, iface_data))".to_owned(), + )); for method_analysis in virtual_methods { body.push(Chunk::Custom( - format!("{iface}.{mname} = Some({type_fn}_{mname}::);", - mname=method_analysis.name, - iface=iface_name, - type_fn=iface_get_type).to_owned() + format!( + "{iface}.{mname} = Some({obj}_{mname}::);", + mname = method_analysis.name, + iface = iface_name, + obj = self.object_name.to_lowercase() + ).to_owned(), )); } - Chunk::Chunks(body) - } fn let_klass(&self) -> Chunk { @@ -289,7 +373,6 @@ impl Builder { } } - fn generate_func_parameters(&self) -> Vec { let mut params = Vec::new(); for trans in &self.transformations { @@ -342,24 +425,28 @@ impl Builder { fn get_outs(&self) -> Vec<&Parameter> { self.parameters .iter() - .filter_map(|par| if let Out { .. } = *par { - Some(par) - } else { - None + .filter_map(|par| { + if let Out { .. } = *par { + Some(par) + } else { + None + } }) .collect() } fn get_outs_without_error(&self) -> Vec<&Parameter> { self.parameters .iter() - .filter_map(|par| if let Out { ref parameter, .. } = *par { - if parameter.is_error { - None + .filter_map(|par| { + if let Out { ref parameter, .. } = *par { + if parameter.is_error { + None + } else { + Some(par) + } } else { - Some(par) + None } - } else { - None }) .collect() } @@ -581,5 +668,4 @@ impl Builder { } } } - } diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index abed26fa0..7f0cc6b11 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -492,7 +492,11 @@ pub fn extern_c_func_body_chunk(env: &Env, { let mut builder = body_chunk_builder(env, object_analysis, method_analysis, subclass_info); - builder.generate_extern_c_func(env) + if object_analysis.is_interface{ + return builder.generate_interface_extern_c_func(env); + }else{ + return builder.generate_object_extern_c_func(env); + } } From 543ee17da6ee10c6257849be9d7594a803b5c607 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 1 Jun 2018 08:22:46 +0200 Subject: [PATCH 047/122] wip: generate get_type function --- src/codegen/subclass/class_impl.rs | 37 ++++++++++++++---- src/codegen/subclass/virtual_methods.rs | 52 +++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 7 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index b3d564407..629902918 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -129,7 +129,7 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> try!(generate_box_impl(w, env, analysis, &subclass_info)); try!(generate_impl_objecttype(w, env, analysis, &subclass_info)); }else{ - // try!(generate_impl_static(w, env, analysis, &subclass_info)); + try!(generate_impl_static(w, env, analysis, &subclass_info)); } try!(generate_extern_c_funcs(w, env, analysis, &subclass_info)); @@ -660,6 +660,27 @@ fn generate_impl_static( "}}" ); + try!(writeln!(w)); + + + writeln!( + w, + "pub trait {}Static{{", + object_analysis.name + ); + + + try!(writeln!(w, "{}imp_static: *const {}Static;", + tabs(1), + object_analysis.subclass_impl_trait_name + )); + + writeln!( + w, + "}}" + ); + + Ok(()) } @@ -685,12 +706,6 @@ fn generate_extern_c_funcs( if object_analysis.is_interface{ - // TODO: generate *_get_type( - // see: https://github.com/sdroege/gst-plugin-rs/blob/25af5afb2bb9dfea79a13fd306d4b7fe36d26496/gst-plugin/src/uri_handler.rs#L40 - - // TODO: generate *_init( - // see: https://github.com/sdroege/gst-plugin-rs/blob/25af5afb2bb9dfea79a13fd306d4b7fe36d26496/gst-plugin/src/uri_handler.rs#L104 - try!(virtual_methods::generate_interface_init( w, env, @@ -699,6 +714,14 @@ fn generate_extern_c_funcs( 0 )); + try!(virtual_methods::generate_interface_get_type( + w, + env, + object_analysis, + subclass_info, + 0 + )); + // TODO: generate register_*>( // see: https://github.com/sdroege/gst-plugin-rs/blob/25af5afb2bb9dfea79a13fd306d4b7fe36d26496/gst-plugin/src/uri_handler.rs#L123 } diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 7f0cc6b11..d0a844592 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -587,3 +587,55 @@ unsafe extern \"C\" fn {}_init Ok(()) } + + + +pub fn generate_interface_get_type( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + subclass_info: &SubclassInfo, + indent: usize, +) -> Result<()> { + + + +// unsafe extern "C" fn uri_handler_get_type( +// type_: glib_ffi::GType, +// ) -> gst_ffi::GstURIType { +// callback_guard!(); +// let klass = gobject_ffi::g_type_class_peek(type_); +// let klass = &*(klass as *const ClassStruct); +// let interface_static = klass.get_interface_static(gst_ffi::gst_uri_handler_get_type()) +// as *const URIHandlerStatic; +// (*(*interface_static).imp_static).get_type().to_glib() +// } + + try!(writeln!( + w, + " +unsafe extern \"C\" fn {}_get_type + type_: glib_ffi::GType, +) -> {}::{} {{", + object_analysis.name.to_lowercase(), + "","" //TODO! + )); + + let ffi_crate_name = &env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name; + + try!(writeln!(w,"{}callback_guard!();", tabs(1))); + try!(writeln!(w,"{}let klass = gobject_ffi::g_type_class_peek(type_);", tabs(1))); + try!(writeln!(w,"{}let klass = &*(klass as *const ClassStruct);", tabs(1))); + try!(writeln!(w,"{}let interface_static = klass.get_interface_static({}::{}_get_type()) as *const {}Static;", + tabs(1), + ffi_crate_name, + object_analysis.name.to_lowercase(), + object_analysis.name)); + try!(writeln!(w,"{}(*(*interface_static).imp_static).get_type().to_glib()", tabs(1))); + + + try!(writeln!(w,"}}")); + + Ok(()) + +} From dfd05924bbecc3761f5a0298a1375e078d5fe09f Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 1 Jun 2018 08:25:54 +0200 Subject: [PATCH 048/122] fix variable name in interface extern functions --- .../subclass/virtual_method_body_chunks.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index 409def9e7..d2c7e044e 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -185,10 +185,8 @@ impl Builder { is_mut: false, name: "klass".to_owned(), value: Box::new(Chunk::Custom( - format!( - "&**({} as *const *const ClassStruct)", - self.object_name.to_lowercase() - ).to_owned(), + "&**(ptr as *const *const ClassStruct)" + .to_owned(), )), type_: None, }); @@ -199,9 +197,10 @@ impl Builder { value: Box::new(Chunk::Custom( format!( "klass.get_interface_static({}::{}_get_type()) - as *const URIHandlerStatic", + as *const {}Static", self.ffi_crate_name, - self.object_name.to_lowercase() + self.object_name.to_lowercase(), + self.object_name ).to_owned(), )), type_: None, @@ -211,10 +210,7 @@ impl Builder { is_mut: false, name: "interface_static".to_owned(), value: Box::new(Chunk::Custom( - format!( - "&*({} as *const T::InstanceStructType)", - self.object_name.to_lowercase() - ).to_owned(), + "&*(ptr as *const T::InstanceStructType)".to_owned(), )), type_: None, }); From 5634796dd671a998cb650ddee05f71525678238e Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 2 Jun 2018 20:15:03 +0200 Subject: [PATCH 049/122] generate initial mod.rs --- src/codegen/subclass/class_impl.rs | 63 +++++++++++++++++++------ src/codegen/subclass/class_impls.rs | 4 +- src/codegen/subclass/mod.rs | 23 ++++++++- src/codegen/subclass/virtual_methods.rs | 54 ++++++++------------- 4 files changed, 91 insertions(+), 53 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 629902918..73746fe55 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -88,14 +88,13 @@ impl SubclassInfo { pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> { try!(general::start_comments(w, &env.config)); - try!(general::uses(w, env, &analysis.imports)); try!(statics_ffi::begin(w)); - - try!(statics::generate_extern_crates(w, env)); - try!(statics::include_custom_modules(w, env)); try!(statics_ffi::after_extern_crates(w)); try!(statics_ffi::use_glib(w)); + try!(statics::include_custom_modules(w, env)); + try!(general::uses(w, env, &analysis.imports)); + // match &*env.config.library_name { // "GLib" => try!(statics::only_for_glib(w)), @@ -137,6 +136,32 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> Ok(()) } +pub fn generate_exports( + env: &Env, + analysis: &analysis::object::Info, + module_name: &str, + contents: &mut Vec, +) { + let cfg_condition = general::cfg_condition_string(&analysis.cfg_condition, false, 0); + let version_cfg = general::version_condition_string(env, analysis.version, false, 0); + let mut cfg = String::new(); + if let Some(s) = cfg_condition { + cfg.push_str(&s); + cfg.push('\n'); + }; + if let Some(s) = version_cfg { + cfg.push_str(&s); + cfg.push('\n'); + }; + contents.push("".to_owned()); + contents.push(format!("{}pub mod {};", cfg, module_name)); + // contents.push(format!( + // "{}pub use self::{}::{};", + // cfg, + // module_name, + // analysis.name + // )); +} pub fn generate_impl( w: &mut Write, @@ -323,18 +348,26 @@ fn generate_ext( return Ok(()); } - let classext_name = format!("{}Ext", object_analysis.class_type.as_ref().unwrap()); + let ext_name = if object_analysis.is_interface{ + format!("{}InterfaceExt", object_analysis.name) + }else{ + format!("{}Ext", object_analysis.class_type.as_ref().unwrap()) + }; + + + + // start base trait + try!(writeln!(w)); + try!(writeln!( + w, + "pub unsafe trait {}\nwhere\n{}T::ImplType: {}{{", + ext_name, + object_analysis.subclass_base_trait_name, + tabs(1), + object_analysis.subclass_impl_trait_name + )); + - // start base trait - try!(writeln!(w)); - try!(writeln!( - w, - "pub unsafe trait {}\nwhere\n{}T::ImplType: {}{{", - classext_name, - object_analysis.subclass_base_trait_name, - tabs(1), - object_analysis.subclass_impl_trait_name - )); try!(virtual_methods::generate_override_vfuncs( w, diff --git a/src/codegen/subclass/class_impls.rs b/src/codegen/subclass/class_impls.rs index ff915379a..09c3c9cf0 100644 --- a/src/codegen/subclass/class_impls.rs +++ b/src/codegen/subclass/class_impls.rs @@ -11,7 +11,7 @@ use traits::*; use codegen::subclass::class_impl; -pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec, traits: &mut Vec) { +pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec) { info!("Generate class traits"); @@ -34,6 +34,6 @@ pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec, traits: & class_impl::generate(w, env, object_analysis) }); - // super::object::generate_reexports(env, class_analysis, &mod_name, mod_rs, traits); + super::class_impl::generate_exports(env, object_analysis, &mod_name, mod_rs); } } diff --git a/src/codegen/subclass/mod.rs b/src/codegen/subclass/mod.rs index 4247e4642..2a7a93656 100644 --- a/src/codegen/subclass/mod.rs +++ b/src/codegen/subclass/mod.rs @@ -1,4 +1,8 @@ use env::Env; +use codegen::general; +use std::path::Path; + +use file_saver::*; mod object; mod statics; @@ -15,14 +19,29 @@ pub fn generate(env: &Env) { let root_path = env.config.target_path.join("src").join("auto"); let mut mod_rs: Vec = Vec::new(); - let mut traits: Vec = Vec::new(); + let mut modules: Vec = Vec::new(); generate_single_version_file(env); - class_impls::generate(env, &root_path, &mut mod_rs, &mut traits); + class_impls::generate(env, &root_path, &mut mod_rs); + + generate_mod_rs(env, &root_path, &mod_rs); // lib_::generate(env); // build::generate(env); // let crate_name = cargo_toml::generate(env); // tests::generate(env, &crate_name); } + + +pub fn generate_mod_rs(env: &Env, root_path: &Path, mod_rs: &[String]) { + + let path = root_path.join("mod.rs"); + save_to_file(path, env.config.make_backup, |w| { + try!(general::start_comments(w, &env.config)); + try!(writeln!(w)); + try!(statics::generate_extern_crates(w, env)); + try!(writeln!(w)); + general::write_vec(w, mod_rs) + }); +} diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index d0a844592..4b424bf8d 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -290,10 +290,6 @@ pub fn generate_override_vfuncs( indent: usize, ) -> Result<()> { - if object_analysis.c_class_type.is_none(){ - return Ok(()); - } - try!(writeln!(w)); try!(writeln!( @@ -303,24 +299,28 @@ pub fn generate_override_vfuncs( )); let mut body_chunks = Vec::new(); - body_chunks.push(Chunk::Let{ - name: "klass".to_owned(), - is_mut: false, - value: Box::new(Chunk::Custom(format!("&mut *(self as *const Self as *mut {}::{})", - &env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name, - object_analysis.c_class_type.as_ref().unwrap()).to_owned())), - type_: None, - }); - - - for method_analysis in &object_analysis.virtual_methods { - body_chunks.push(Chunk::Custom( - format!("klass.{mname} = Some({cname}_{mname}::);", mname=method_analysis.name, - cname=object_analysis.name.to_lowercase()).to_owned() - )); - } + if !object_analysis.is_interface{ + body_chunks.push(Chunk::Let{ + name: "klass".to_owned(), + is_mut: false, + value: Box::new(Chunk::Custom(format!("&mut *(self as *const Self as *mut {}::{})", + &env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name, + object_analysis.c_class_type.as_ref().unwrap()).to_owned())), + type_: None, + }); + + + for method_analysis in &object_analysis.virtual_methods { + body_chunks.push(Chunk::Custom( + format!("klass.{mname} = Some({cname}_{mname}::);", mname=method_analysis.name, + cname=object_analysis.name.to_lowercase()).to_owned() + )); + } + + } + let unsafe_ = Chunk::Unsafe(body_chunks); let mut chunks = Vec::new(); @@ -573,7 +573,6 @@ unsafe extern \"C\" fn {}_init let mut builder = Builder::new(); builder.object_name(&object_analysis.name) - .object_class_c_type(object_analysis.c_class_type.as_ref().unwrap()) .ffi_crate_name(&env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name); @@ -598,19 +597,6 @@ pub fn generate_interface_get_type( indent: usize, ) -> Result<()> { - - -// unsafe extern "C" fn uri_handler_get_type( -// type_: glib_ffi::GType, -// ) -> gst_ffi::GstURIType { -// callback_guard!(); -// let klass = gobject_ffi::g_type_class_peek(type_); -// let klass = &*(klass as *const ClassStruct); -// let interface_static = klass.get_interface_static(gst_ffi::gst_uri_handler_get_type()) -// as *const URIHandlerStatic; -// (*(*interface_static).imp_static).get_type().to_glib() -// } - try!(writeln!( w, " From 6ae1b232fa7491e5de90530b65e1204f14ee5647 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 2 Jun 2018 23:38:24 +0200 Subject: [PATCH 050/122] insert subclass dependencies --- src/codegen/subclass/statics.rs | 41 +++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/codegen/subclass/statics.rs b/src/codegen/subclass/statics.rs index 94d801a72..57ebb7564 100644 --- a/src/codegen/subclass/statics.rs +++ b/src/codegen/subclass/statics.rs @@ -4,26 +4,63 @@ use std::fs; use env::Env; use config::ExternalLibrary; use nameutil; +use analysis::namespaces; // TODO: copied from sys pub fn generate_extern_crates(w: &mut Write, env: &Env) -> Result<()> { + for library in &env.config.external_libraries { + try!(w.write_all(get_extern_crate_string_ffi(library).as_bytes())); + } for library in &env.config.external_libraries { try!(w.write_all(get_extern_crate_string(library).as_bytes())); } + for library in &env.config.external_libraries { + + if library.crate_name == "glib"{ + continue; + } + + let ns = &env.namespaces[namespaces::MAIN]; + if ns.crate_name == library.crate_name { + continue; + } + + try!(w.write_all(get_extern_crate_string_subclass(library).as_bytes())); + } Ok(()) } -// TODO: copied from sys fn get_extern_crate_string(library: &ExternalLibrary) -> String { + + let mut m = ""; + if library.crate_name == "glib"{ + m = "#[macro_use]\n"; + } + + format!( + "{}extern crate {};\n", + m, + library.crate_name.replace("-", "_") + ) +} +fn get_extern_crate_string_ffi(library: &ExternalLibrary) -> String { format!( - "extern crate {}_sys as {};\n", + "extern crate {}_sys as {}_ffi;\n", library.crate_name.replace("-", "_"), nameutil::crate_name(&library.namespace) ) } +fn get_extern_crate_string_subclass(library: &ExternalLibrary) -> String { + format!( + "#[macro_use]\nextern crate {}_subclass;\n", + library.crate_name.replace("-", "_") + ) +} + + // TODO: copied from sys pub fn include_custom_modules(w: &mut Write, env: &Env) -> Result<()> { let modules = try!(find_modules(env)); From 3bec7d42e63a850d338e3e44bdc3ab532a483dc1 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 3 Jun 2018 21:47:13 +0200 Subject: [PATCH 051/122] generate lib instead of mod --- src/codegen/subclass/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/codegen/subclass/mod.rs b/src/codegen/subclass/mod.rs index 2a7a93656..d9a17fd98 100644 --- a/src/codegen/subclass/mod.rs +++ b/src/codegen/subclass/mod.rs @@ -18,14 +18,14 @@ pub fn generate(env: &Env) { info!("Generating subclasssing traits {:?}", env.config.target_path); let root_path = env.config.target_path.join("src").join("auto"); - let mut mod_rs: Vec = Vec::new(); + let mut lib_rs: Vec = Vec::new(); let mut modules: Vec = Vec::new(); generate_single_version_file(env); - class_impls::generate(env, &root_path, &mut mod_rs); + class_impls::generate(env, &root_path, &mut lib_rs); - generate_mod_rs(env, &root_path, &mod_rs); + generate_lib_rs(env, &root_path, &lib_rs); // lib_::generate(env); // build::generate(env); @@ -34,14 +34,14 @@ pub fn generate(env: &Env) { } -pub fn generate_mod_rs(env: &Env, root_path: &Path, mod_rs: &[String]) { +pub fn generate_lib_rs(env: &Env, root_path: &Path, lib_rs: &[String]) { - let path = root_path.join("mod.rs"); + let path = root_path.join("lib.rs"); save_to_file(path, env.config.make_backup, |w| { try!(general::start_comments(w, &env.config)); try!(writeln!(w)); try!(statics::generate_extern_crates(w, env)); try!(writeln!(w)); - general::write_vec(w, mod_rs) + general::write_vec(w, lib_rs) }); } From acaa79902b4b4b73aba8b3a67e4d106fcd5431b7 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 4 Jun 2018 19:46:51 +0200 Subject: [PATCH 052/122] remove erroneous commas --- src/codegen/subclass/virtual_methods.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 4b424bf8d..9abf813f9 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -565,7 +565,7 @@ pub fn generate_interface_init( " unsafe extern \"C\" fn {}_init iface: glib_ffi::gpointer, - iface_data: glib_ffi::gpointer, + iface_data: glib_ffi::gpointer ) {{", object_analysis.name.to_lowercase() )); @@ -601,7 +601,7 @@ pub fn generate_interface_get_type( w, " unsafe extern \"C\" fn {}_get_type - type_: glib_ffi::GType, + type_: glib_ffi::GType ) -> {}::{} {{", object_analysis.name.to_lowercase(), "","" //TODO! From c3bea581991454fc8cc492e3c8465567f6208c8e Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 4 Jun 2018 19:48:54 +0200 Subject: [PATCH 053/122] fix return type of get_type --- src/codegen/subclass/virtual_methods.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 9abf813f9..3567e78de 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -602,7 +602,7 @@ pub fn generate_interface_get_type( " unsafe extern \"C\" fn {}_get_type type_: glib_ffi::GType -) -> {}::{} {{", +) -> glib::Type {{", object_analysis.name.to_lowercase(), "","" //TODO! )); From ed8b51e7c829b7e688c388412499ee314782ce47 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 4 Jun 2018 19:50:04 +0200 Subject: [PATCH 054/122] fix format statement --- src/codegen/subclass/virtual_methods.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 3567e78de..0339712fc 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -603,8 +603,7 @@ pub fn generate_interface_get_type( unsafe extern \"C\" fn {}_get_type type_: glib_ffi::GType ) -> glib::Type {{", - object_analysis.name.to_lowercase(), - "","" //TODO! + object_analysis.name.to_lowercase() )); let ffi_crate_name = &env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name; From ddfa66b92290a32d7bca4137f4337e25f3b7ad40 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 4 Jun 2018 19:52:28 +0200 Subject: [PATCH 055/122] fix interface function definitions --- src/codegen/subclass/virtual_methods.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 0339712fc..41a3ba395 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -563,7 +563,7 @@ pub fn generate_interface_init( try!(writeln!( w, " -unsafe extern \"C\" fn {}_init +unsafe extern \"C\" fn {}_init( iface: glib_ffi::gpointer, iface_data: glib_ffi::gpointer ) {{", @@ -600,7 +600,7 @@ pub fn generate_interface_get_type( try!(writeln!( w, " -unsafe extern \"C\" fn {}_get_type +unsafe extern \"C\" fn {}_get_type( type_: glib_ffi::GType ) -> glib::Type {{", object_analysis.name.to_lowercase() From 4ef47ff3cf6fd80afc0c891f71c046ac3cb6c209 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 4 Jun 2018 19:56:28 +0200 Subject: [PATCH 056/122] change trait to struct --- src/codegen/subclass/class_impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 73746fe55..e37ba68a4 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -698,7 +698,7 @@ fn generate_impl_static( writeln!( w, - "pub trait {}Static{{", + "struct {}Static{{", object_analysis.name ); From c82401e018396d631f1e23eecedd45e69811210a Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 4 Jun 2018 19:57:56 +0200 Subject: [PATCH 057/122] fix typo --- src/codegen/subclass/class_impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index e37ba68a4..8e22d346b 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -703,7 +703,7 @@ fn generate_impl_static( ); - try!(writeln!(w, "{}imp_static: *const {}Static;", + try!(writeln!(w, "{}imp_static: *const {}Static", tabs(1), object_analysis.subclass_impl_trait_name )); From 6b0cfa014dde55dea604f8ce47edd05881e6ddb8 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 4 Jun 2018 21:02:51 +0200 Subject: [PATCH 058/122] remove faulty closing bracket --- src/codegen/subclass/class_impl.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 8e22d346b..f1d37a6a7 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -246,10 +246,6 @@ pub fn generate_impl_ext( try!(writeln!(w)); try!(writeln!(w, "pub trait {} {{}}", implext_name)); - //end ext trait def - try!(writeln!(w)); - try!(writeln!(w, "}}")); - // start ext trait impl let parents = subclass_info.parent_names(env, ""); From 4f1e4ed5d0ae3d934c4bec11bb5e471646f14e05 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 5 Jun 2018 07:45:28 +0200 Subject: [PATCH 059/122] use gobject-subclass modules --- src/codegen/subclass/class_impl.rs | 4 ++-- src/codegen/subclass/mod.rs | 4 ++-- src/codegen/subclass/statics.rs | 13 ++++++++----- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index f1d37a6a7..1e5e1dd7f 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -89,10 +89,10 @@ impl SubclassInfo { pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> { try!(general::start_comments(w, &env.config)); - try!(statics_ffi::begin(w)); try!(statics_ffi::after_extern_crates(w)); try!(statics_ffi::use_glib(w)); try!(statics::include_custom_modules(w, env)); + try!(statics::use_subclass_modules(w, env)); try!(general::uses(w, env, &analysis.imports)); @@ -257,7 +257,7 @@ pub fn generate_impl_ext( try!(writeln!( w, - "impl, T: ObjectType {parents}>> {implext_name} for S {{}}", + "impl, T: ObjectType {parents}> {implext_name} for S {{}}", impl_name = object_analysis.subclass_impl_trait_name, parents = parent_objs, implext_name = implext_name diff --git a/src/codegen/subclass/mod.rs b/src/codegen/subclass/mod.rs index d9a17fd98..0a4a61bab 100644 --- a/src/codegen/subclass/mod.rs +++ b/src/codegen/subclass/mod.rs @@ -11,7 +11,7 @@ mod class_impl; mod virtual_methods; mod virtual_method_body_chunks; - +use codegen::sys::statics as statics_ffi; use codegen::generate_single_version_file; pub fn generate(env: &Env) { @@ -19,7 +19,6 @@ pub fn generate(env: &Env) { let root_path = env.config.target_path.join("src").join("auto"); let mut lib_rs: Vec = Vec::new(); - let mut modules: Vec = Vec::new(); generate_single_version_file(env); @@ -40,6 +39,7 @@ pub fn generate_lib_rs(env: &Env, root_path: &Path, lib_rs: &[String]) { save_to_file(path, env.config.make_backup, |w| { try!(general::start_comments(w, &env.config)); try!(writeln!(w)); + try!(statics_ffi::begin(w)); try!(statics::generate_extern_crates(w, env)); try!(writeln!(w)); general::write_vec(w, lib_rs) diff --git a/src/codegen/subclass/statics.rs b/src/codegen/subclass/statics.rs index 57ebb7564..3aca2fc31 100644 --- a/src/codegen/subclass/statics.rs +++ b/src/codegen/subclass/statics.rs @@ -60,15 +60,18 @@ fn get_extern_crate_string_subclass(library: &ExternalLibrary) -> String { ) } +pub fn use_subclass_modules(w: &mut Write, env: &Env) -> Result<()> { + try!(writeln!(w)); + try!(writeln!(w, "use gobject_subclass::anyimpl::*;")); + try!(writeln!(w, "use gobject_subclass::object::*;")); + + Ok(()) +} + -// TODO: copied from sys pub fn include_custom_modules(w: &mut Write, env: &Env) -> Result<()> { let modules = try!(find_modules(env)); if !modules.is_empty() { - try!(writeln!(w)); - for module in &modules { - try!(writeln!(w, "mod {};", module)); - } try!(writeln!(w)); for module in &modules { try!(writeln!(w, "pub use {}::*;", module)); From 1ba61716659c4e8b220fadf69d7daa6c7ec2df38 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 6 Jun 2018 19:39:55 +0200 Subject: [PATCH 060/122] interface impl: use correct type --- src/codegen/subclass/class_impl.rs | 8 --- src/codegen/subclass/virtual_methods.rs | 67 ++++++++----------------- 2 files changed, 22 insertions(+), 53 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 1e5e1dd7f..27a721483 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -743,14 +743,6 @@ fn generate_extern_c_funcs( 0 )); - try!(virtual_methods::generate_interface_get_type( - w, - env, - object_analysis, - subclass_info, - 0 - )); - // TODO: generate register_*>( // see: https://github.com/sdroege/gst-plugin-rs/blob/25af5afb2bb9dfea79a13fd306d4b7fe36d26496/gst-plugin/src/uri_handler.rs#L123 } diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 41a3ba395..acf13ac74 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -5,6 +5,7 @@ use analysis; use analysis::bounds::{BoundType, Bounds}; use analysis::ref_mode::RefMode; use analysis::functions::Visibility; +use analysis::rust_type::parameter_rust_type; use analysis::namespaces; use env::Env; use writer::primitives::tabs; @@ -38,7 +39,7 @@ pub fn generate_default_impl( try!(writeln!(w)); let parent_name = &method_analysis.parameters.rust_parameters[0].name; - let declr = declaration(env, method_analysis, None, Some(parent_name)); + let declr = declaration(env, method_analysis, None, Some(&format!("{}: &T", parent_name))); try!(writeln!( w, @@ -81,8 +82,22 @@ pub fn generate_declaration( try!(writeln!(w)); - let parent_name = &method_analysis.parameters.rust_parameters[0].name; - let declr = declaration(env, method_analysis, None, Some(parent_name)); + let param = &method_analysis.parameters.rust_parameters[0]; + let parent_name = ¶m.name; + let bounds = Bounds::default(); + let c_par = &method_analysis.parameters.c_parameters[param.ind_c]; + + let rust_type = parameter_rust_type( + env, + c_par.typ, + c_par.direction, + c_par.nullable, + c_par.ref_mode, + ); + let parent_type = rust_type.into_string(); + + + let declr = declaration(env, method_analysis, None, Some(&format!("{}: {}", parent_name, parent_type))); try!(writeln!( w, @@ -127,7 +142,7 @@ fn virtual_method_args(method_analysis: &analysis::virtual_methods::Info, includ } -pub fn declaration(env: &Env, method_analysis: &analysis::virtual_methods::Info, method_name: Option<&String>, parent_name: Option<&String>) -> String { +pub fn declaration(env: &Env, method_analysis: &analysis::virtual_methods::Info, method_name: Option<&String>, parent: Option<&String>) -> String { let outs_as_return = !method_analysis.outs.is_empty(); let return_str = if outs_as_return { out_parameters_as_return(env, method_analysis) @@ -153,8 +168,8 @@ pub fn declaration(env: &Env, method_analysis: &analysis::virtual_methods::Info, param_str.push_str(&s); // insert the templated param - if parent_name.is_some() && pos == 0{ - param_str.push_str(&format!(", {}: &T", parent_name.as_ref().unwrap())); + if parent.is_some() && pos == 0{ + param_str.push_str(&format!(", {}", parent.as_ref().unwrap())); } } @@ -351,7 +366,7 @@ pub fn generate_box_impl( let parent_name = &method_analysis.parameters.rust_parameters[0].name; - let declr = declaration(env, method_analysis, None, Some(parent_name)); + let declr = declaration(env, method_analysis, None, Some(&format!("{}: &T", parent_name))); try!(writeln!( w, @@ -586,41 +601,3 @@ unsafe extern \"C\" fn {}_init( Ok(()) } - - - -pub fn generate_interface_get_type( - w: &mut Write, - env: &Env, - object_analysis: &analysis::object::Info, - subclass_info: &SubclassInfo, - indent: usize, -) -> Result<()> { - - try!(writeln!( - w, - " -unsafe extern \"C\" fn {}_get_type( - type_: glib_ffi::GType -) -> glib::Type {{", - object_analysis.name.to_lowercase() - )); - - let ffi_crate_name = &env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name; - - try!(writeln!(w,"{}callback_guard!();", tabs(1))); - try!(writeln!(w,"{}let klass = gobject_ffi::g_type_class_peek(type_);", tabs(1))); - try!(writeln!(w,"{}let klass = &*(klass as *const ClassStruct);", tabs(1))); - try!(writeln!(w,"{}let interface_static = klass.get_interface_static({}::{}_get_type()) as *const {}Static;", - tabs(1), - ffi_crate_name, - object_analysis.name.to_lowercase(), - object_analysis.name)); - try!(writeln!(w,"{}(*(*interface_static).imp_static).get_type().to_glib()", tabs(1))); - - - try!(writeln!(w,"}}")); - - Ok(()) - -} From a4a09c512f48dec397b371298076b8537b3cbfef Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 6 Jun 2018 19:46:25 +0200 Subject: [PATCH 061/122] use correct ffi type for interface" --- src/codegen/subclass/virtual_method_body_chunks.rs | 8 +++++++- src/codegen/subclass/virtual_methods.rs | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index d2c7e044e..3a215aea2 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -22,6 +22,7 @@ use codegen::function_body_chunk::{c_type_mem_mode, OutMemMode, Parameter, Retur pub struct Builder { object_name: String, object_class_c_type: String, + object_c_type: String, ffi_crate_name: String, glib_name: String, method_name: String, @@ -53,6 +54,11 @@ impl Builder { self } + pub fn object_c_type(&mut self, c_type: &str) -> &mut Builder { + self.object_c_type = c_type.into(); + self + } + pub fn ffi_crate_name(&mut self, ns: &str) -> &mut Builder { self.ffi_crate_name = ns.into(); self @@ -287,7 +293,7 @@ impl Builder { value: Box::new(Chunk::Custom( format!( "&mut *(iface as *mut {}::{})", - self.ffi_crate_name, self.object_class_c_type + self.ffi_crate_name, self.object_c_type ).to_owned(), )), type_: None, diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index acf13ac74..81b7524e4 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -588,6 +588,7 @@ unsafe extern \"C\" fn {}_init( let mut builder = Builder::new(); builder.object_name(&object_analysis.name) + .object_c_type(&object_analysis.c_type) .ffi_crate_name(&env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name); From eabb443fc7583edbd6e9f7bdd8dedeae6cc5a6e0 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 6 Jun 2018 19:48:40 +0200 Subject: [PATCH 062/122] fix incorrect variable name --- src/codegen/subclass/virtual_method_body_chunks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index 3a215aea2..3e2a02fad 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -214,7 +214,7 @@ impl Builder { body.push(Chunk::Let { is_mut: false, - name: "interface_static".to_owned(), + name: "instance".to_owned(), value: Box::new(Chunk::Custom( "&*(ptr as *const T::InstanceStructType)".to_owned(), )), From 1ab854dbf8234b1f349ffe2bf52b8a46a51d44cb Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 7 Jun 2018 09:15:19 +0200 Subject: [PATCH 063/122] various fixes to interface generation --- .../subclass/virtual_method_body_chunks.rs | 13 ++++++++++--- src/codegen/subclass/virtual_methods.rs | 19 ++++++++++--------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index 3e2a02fad..4a677c587 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -175,7 +175,7 @@ impl Builder { // TODO: call imp function body.push(Chunk::Custom( - format!("imp.{}({})", self.method_name, &"").to_owned(), + format!("imp.{}({})", self.method_name, &"&wrap").to_owned(), )); Chunk::Chunks(body) @@ -235,9 +235,16 @@ impl Builder { type_: None, }); + body.push(Chunk::Let { + is_mut: false, + name: "wrap".to_owned(), + value: Box::new(Chunk::Custom("from_glib_borrow(instance)".to_owned())), + type_: Some(Box::new(Chunk::Custom("T".to_owned()))), + }); + // TODO: call imp function body.push(Chunk::Custom( - format!("imp.{}({})", self.method_name, &"").to_owned(), + format!("imp.{}({})", self.method_name, &"&wrap").to_owned(), )); Chunk::Chunks(body) @@ -334,7 +341,7 @@ impl Builder { }); body.push(Chunk::Custom( - "interfaces_static.push((iface_type, iface_data))".to_owned(), + "interfaces_static.push((iface_type, iface_data));".to_owned(), )); for method_analysis in virtual_methods { diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 81b7524e4..23b6c35d7 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -418,10 +418,9 @@ pub fn generate_extern_c_func( try!(writeln!( w, - "unsafe extern \"C\" fn {}_{}", + "unsafe extern \"C\" fn {}_{}", object_analysis.name.to_lowercase(), - method_analysis.name, - object_analysis.subclass_base_trait_name + method_analysis.name )); let (_, sig) = function_signature(env, method_analysis, false); @@ -432,12 +431,14 @@ pub fn generate_extern_c_func( sig )); - try!(writeln!( - w, - "where\n{}T::ImplType: {}", - tabs(indent+1), - object_analysis.subclass_impl_trait_name - )); + if !object_analysis.is_interface{ + try!(writeln!( + w, + "where\n{}T::ImplType: {}", + tabs(indent+1), + object_analysis.subclass_impl_trait_name + )); + } try!(writeln!( w, "{{" From 9b839f2a70c7733f7e876d54c04ab0635ff92a39 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 7 Jun 2018 16:09:50 +0200 Subject: [PATCH 064/122] wip: convert trampoline parameters --- src/codegen/subclass/virtual_methods.rs | 64 +++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 23b6c35d7..878469016 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -14,16 +14,17 @@ use codegen::parameter::ToParameter; use chunk::{ffi_function_todo, Chunk}; use traits::IntoString; use nameutil; - +use config; use std::result::Result as StdResult; use std::fmt; - +use analysis::conversion_type::ConversionType; +use analysis::function_parameters::TransformationType; use codegen::subclass::class_impl::SubclassInfo; use codegen::subclass::virtual_method_body_chunks::Builder; use codegen::sys::ffi_type::ffi_type; use codegen::function_body_chunk::{Parameter, ReturnValue}; use codegen::return_value::{ToReturnValue, out_parameter_as_return}; - +use codegen::trampoline_from_glib::TrampolineFromGlib; pub fn generate_default_impl( w: &mut Write, @@ -449,6 +450,9 @@ pub fn generate_extern_c_func( try!(writeln!(w, "{}{}", tabs(indent+1), s)); } + let func_str = trampoline_call_parameters(env, method_analysis, false); + try!(writeln!(w, "{}{}", tabs(indent+1), func_str)); + try!(writeln!( w, "}}" @@ -603,3 +607,57 @@ unsafe extern \"C\" fn {}_init( Ok(()) } + + +fn parameter_transformation(env: &Env, analysis: &analysis::virtual_methods::Info, + ind: usize, + par: &analysis::function_parameters::RustParameter) -> analysis::trampoline_parameters::Transformation{ + + let c_par = &analysis.parameters.c_parameters[par.ind_c]; + let transformation = &analysis.parameters.transformations + .iter() + .find(|tr| tr.ind_c == par.ind_c); + + + let conversion_type = match transformation { + &Some(ttype) => match ttype.transformation_type { + TransformationType::ToGlibDirect{..} => ConversionType::Direct, + TransformationType::ToGlibScalar{..} => ConversionType::Scalar, + TransformationType::ToGlibPointer{..} => ConversionType::Pointer, + TransformationType::ToGlibBorrow{..} => ConversionType::Borrow, + TransformationType::ToGlibUnknown{..} => ConversionType::Unknown, + TransformationType::ToGlibStash{..} => ConversionType::Unknown, + TransformationType::Into{..} => ConversionType::Unknown, + TransformationType::Length{..} => ConversionType::Unknown, + TransformationType::IntoRaw{..} => ConversionType::Unknown, + TransformationType::ToSome{..} => ConversionType::Unknown + }, + &None => ConversionType::Unknown + }; + + analysis::trampoline_parameters::Transformation{ + ind_c: par.ind_c, + ind_rust: ind, + transformation: config::signals::TransformationType::None, + name: par.name.clone(), + typ: par.typ, + transfer: c_par.transfer, + ref_mode: c_par.ref_mode, + conversion_type: conversion_type, + } +} + + +fn trampoline_call_parameters(env: &Env, analysis: &analysis::virtual_methods::Info, in_trait: bool) -> String { + let mut need_downcast = in_trait; + let mut parameter_strs: Vec = Vec::new(); + for (ind, par) in analysis.parameters.rust_parameters.iter().enumerate() { + let transformation = parameter_transformation(env, analysis, ind, par); + + let par_str = transformation.trampoline_from_glib(env, need_downcast); + parameter_strs.push(par_str); + need_downcast = false; //Only downcast first parameter + } + + parameter_strs.join(", ") +} From 29ef5e16b3efe4fa23c2702533b50763e82a7e67 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 7 Jun 2018 16:18:59 +0200 Subject: [PATCH 065/122] call trampoline with correct parameters --- src/codegen/subclass/virtual_method_body_chunks.rs | 10 ---------- src/codegen/subclass/virtual_methods.rs | 13 +++++++++---- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index 4a677c587..504022b22 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -173,11 +173,6 @@ impl Builder { type_: None, }); - // TODO: call imp function - body.push(Chunk::Custom( - format!("imp.{}({})", self.method_name, &"&wrap").to_owned(), - )); - Chunk::Chunks(body) } @@ -242,11 +237,6 @@ impl Builder { type_: Some(Box::new(Chunk::Custom("T".to_owned()))), }); - // TODO: call imp function - body.push(Chunk::Custom( - format!("imp.{}({})", self.method_name, &"&wrap").to_owned(), - )); - Chunk::Chunks(body) } diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 878469016..d3098c6bb 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -450,8 +450,13 @@ pub fn generate_extern_c_func( try!(writeln!(w, "{}{}", tabs(indent+1), s)); } - let func_str = trampoline_call_parameters(env, method_analysis, false); - try!(writeln!(w, "{}{}", tabs(indent+1), func_str)); + let mut func_params = trampoline_call_parameters(env, method_analysis, false); + func_params.insert(0, "&wrap".to_string()); + + try!(writeln!(w, "{}imp.{}({})", + tabs(indent+1), + &method_analysis.name, + func_params.join(", "))); try!(writeln!( w, @@ -648,7 +653,7 @@ fn parameter_transformation(env: &Env, analysis: &analysis::virtual_methods::Inf } -fn trampoline_call_parameters(env: &Env, analysis: &analysis::virtual_methods::Info, in_trait: bool) -> String { +fn trampoline_call_parameters(env: &Env, analysis: &analysis::virtual_methods::Info, in_trait: bool) -> Vec { let mut need_downcast = in_trait; let mut parameter_strs: Vec = Vec::new(); for (ind, par) in analysis.parameters.rust_parameters.iter().enumerate() { @@ -659,5 +664,5 @@ fn trampoline_call_parameters(env: &Env, analysis: &analysis::virtual_methods::I need_downcast = false; //Only downcast first parameter } - parameter_strs.join(", ") + parameter_strs } From ca5985f6104c6fda52bcc5c18c1c38cfc85a536c Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 7 Jun 2018 16:33:19 +0200 Subject: [PATCH 066/122] convert trampoline return values --- src/codegen/subclass/virtual_methods.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index d3098c6bb..0e4c9f80f 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -25,6 +25,7 @@ use codegen::sys::ffi_type::ffi_type; use codegen::function_body_chunk::{Parameter, ReturnValue}; use codegen::return_value::{ToReturnValue, out_parameter_as_return}; use codegen::trampoline_from_glib::TrampolineFromGlib; +use codegen::trampoline_to_glib::TrampolineToGlib; pub fn generate_default_impl( w: &mut Write, @@ -451,12 +452,14 @@ pub fn generate_extern_c_func( } let mut func_params = trampoline_call_parameters(env, method_analysis, false); + let func_ret = trampoline_call_return(env, method_analysis); func_params.insert(0, "&wrap".to_string()); - try!(writeln!(w, "{}imp.{}({})", + try!(writeln!(w, "{}imp.{}({}){}", tabs(indent+1), &method_analysis.name, - func_params.join(", "))); + func_params.join(", "), + func_ret)); try!(writeln!( w, @@ -666,3 +669,10 @@ fn trampoline_call_parameters(env: &Env, analysis: &analysis::virtual_methods::I parameter_strs } + +fn trampoline_call_return(env: &Env, analysis: &analysis::virtual_methods::Info) -> String { + match analysis.ret.parameter { + Some(ref param) => param.trampoline_to_glib(env), + None => String::new() + } +} From 76bf2a5d9930278dc4ad2077f13b2c2f6abc6ba1 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 8 Jun 2018 00:12:11 +0200 Subject: [PATCH 067/122] allow libraries to be exported under a different name --- src/config/config.rs | 7 +++++++ src/main.rs | 3 +-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/config/config.rs b/src/config/config.rs index 38970fe2d..76c5dee3c 100644 --- a/src/config/config.rs +++ b/src/config/config.rs @@ -20,6 +20,7 @@ pub struct Config { pub girs_version: String, //Version in girs_dir, detected by git pub library_name: String, pub library_version: String, + pub library_export_name: String, pub target_path: PathBuf, /// Path where files generated in normal and sys mode pub auto_path: PathBuf, @@ -97,6 +98,11 @@ impl Config { (Some(a), Some(b)) => (a.to_owned(), b.to_owned()), }; + let library_export_name = match toml.lookup_str("options.library_export", "No options.library_export") { + Ok(s) => s.to_string(), + Err(_) => library_name.clone() + }; + let target_path: PathBuf = match target_path.into() { Some("") | None => { let path = try!(toml.lookup_str( @@ -176,6 +182,7 @@ impl Config { girs_version, library_name, library_version, + library_export_name, target_path, auto_path, doc_target_path, diff --git a/src/main.rs b/src/main.rs index b95abc792..cb0baaae6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -78,8 +78,7 @@ fn do_main() -> Result<(), String> { { let _watcher = statistics.enter("Loading"); - - library = Library::new(&cfg.library_name); + library = Library::new(&cfg.library_export_name); try!(library.read_file(&cfg.girs_dir, &cfg.library_full_name())); } From 889b263234f3bd0e9444b104d81402ba52506639 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 8 Jun 2018 00:16:17 +0200 Subject: [PATCH 068/122] remove unneeded use statement --- src/codegen/subclass/class_impl.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 27a721483..3cfe959bc 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -90,7 +90,6 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> try!(general::start_comments(w, &env.config)); try!(statics_ffi::after_extern_crates(w)); - try!(statics_ffi::use_glib(w)); try!(statics::include_custom_modules(w, env)); try!(statics::use_subclass_modules(w, env)); try!(general::uses(w, env, &analysis.imports)); From 8d61bb8d9ae5e5eff49d38c5236152fe61c449f5 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 8 Jun 2018 08:27:17 +0200 Subject: [PATCH 069/122] use correct ffi crate name for subclass --- src/codegen/sys/ffi_type.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/codegen/sys/ffi_type.rs b/src/codegen/sys/ffi_type.rs index ed4ce7a28..aa6b7c054 100644 --- a/src/codegen/sys/ffi_type.rs +++ b/src/codegen/sys/ffi_type.rs @@ -1,6 +1,7 @@ use analysis::c_type::{implements_c_type, rustify_pointers}; use analysis::namespaces; use analysis::rust_type::{Result, TypeError}; +use config::WorkMode; use env::Env; use library; use library::*; @@ -179,6 +180,15 @@ fn ffi_inner(env: &Env, tid: library::TypeId, mut inner: String) -> Result { } } +fn crate_name<'a>(env: &'a Env, ns_id: u16) -> &'a String{ + if env.config.work_mode == WorkMode::Subclass { + &env.namespaces[ns_id].ffi_crate_name + }else{ + &env.namespaces[ns_id].crate_name + } +} + + fn fix_name(env: &Env, type_id: library::TypeId, name: &str) -> Result { if type_id.ns_id == library::INTERNAL_NAMESPACE { match *env.library.type_(type_id) { @@ -191,7 +201,7 @@ fn fix_name(env: &Env, type_id: library::TypeId, name: &str) -> Result { } else { Ok(format!( "{}::{}", - &env.namespaces[env.namespaces.glib_ns_id].crate_name, + &crate_name(env, env.namespaces.glib_ns_id), name )) }, @@ -201,7 +211,7 @@ fn fix_name(env: &Env, type_id: library::TypeId, name: &str) -> Result { let name_with_prefix = if type_id.ns_id == namespaces::MAIN { name.into() } else { - format!("{}::{}", &env.namespaces[type_id.ns_id].crate_name, name) + format!("{}::{}", &crate_name(env, type_id.ns_id), name) }; if env.type_status_sys(&type_id.full_name(&env.library)) .ignored() From 5287eb1403f894c1bab9863a0ccfe9d0176486e1 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 8 Jun 2018 09:18:00 +0200 Subject: [PATCH 070/122] skip the first interface trampoline parameter --- src/codegen/subclass/virtual_methods.rs | 16 +++++++++------- src/codegen/trampoline.rs | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 0e4c9f80f..1928ef0a2 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -451,7 +451,7 @@ pub fn generate_extern_c_func( try!(writeln!(w, "{}{}", tabs(indent+1), s)); } - let mut func_params = trampoline_call_parameters(env, method_analysis, false); + let mut func_params = trampoline_call_parameters(env, method_analysis); let func_ret = trampoline_call_return(env, method_analysis); func_params.insert(0, "&wrap".to_string()); @@ -637,8 +637,8 @@ fn parameter_transformation(env: &Env, analysis: &analysis::virtual_methods::Inf TransformationType::ToGlibStash{..} => ConversionType::Unknown, TransformationType::Into{..} => ConversionType::Unknown, TransformationType::Length{..} => ConversionType::Unknown, - TransformationType::IntoRaw{..} => ConversionType::Unknown, - TransformationType::ToSome{..} => ConversionType::Unknown + TransformationType::IntoRaw{..} => ConversionType::Pointer, + TransformationType::ToSome{..} => ConversionType::Direct }, &None => ConversionType::Unknown }; @@ -656,15 +656,17 @@ fn parameter_transformation(env: &Env, analysis: &analysis::virtual_methods::Inf } -fn trampoline_call_parameters(env: &Env, analysis: &analysis::virtual_methods::Info, in_trait: bool) -> Vec { - let mut need_downcast = in_trait; +fn trampoline_call_parameters(env: &Env, analysis: &analysis::virtual_methods::Info) -> Vec { let mut parameter_strs: Vec = Vec::new(); for (ind, par) in analysis.parameters.rust_parameters.iter().enumerate() { + if ind == 0{ + continue; + } + let transformation = parameter_transformation(env, analysis, ind, par); - let par_str = transformation.trampoline_from_glib(env, need_downcast); + let par_str = transformation.trampoline_from_glib(env, false); parameter_strs.push(par_str); - need_downcast = false; //Only downcast first parameter } parameter_strs diff --git a/src/codegen/trampoline.rs b/src/codegen/trampoline.rs index 50ef57826..d807457cd 100644 --- a/src/codegen/trampoline.rs +++ b/src/codegen/trampoline.rs @@ -122,7 +122,7 @@ fn func_parameters( param_str } -fn func_parameter( +pub fn func_parameter( env: &Env, par: &RustParameter, bounds: &Bounds, From b8db7166fc3a07589a857a345a438c98dad66d4c Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 8 Jun 2018 09:28:27 +0200 Subject: [PATCH 071/122] most get_type functions seem global --- src/codegen/subclass/virtual_method_body_chunks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index 504022b22..5631eb78b 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -197,7 +197,7 @@ impl Builder { name: "interface_static".to_owned(), value: Box::new(Chunk::Custom( format!( - "klass.get_interface_static({}::{}_get_type()) + "klass.get_interface_static({}::g_{}_get_type()) as *const {}Static", self.ffi_crate_name, self.object_name.to_lowercase(), From 2bde5ffec0e75d0fdd06cef16b4b484ada8d95c5 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 8 Jun 2018 14:39:25 +0200 Subject: [PATCH 072/122] splice trampoline impl from external file --- src/codegen/subclass/class_impl.rs | 31 ++++++++--- src/config/config.rs | 2 + .../action-get_state-trampoline.rs | 18 +++++++ tests/subclass/gir-gio.toml | 54 +++++++++++++++++++ 4 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 tests/subclass/gio-subclass/action-get_state-trampoline.rs create mode 100644 tests/subclass/gir-gio.toml diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 3cfe959bc..70f4855e5 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -1,5 +1,7 @@ use std::io::{Result, Write}; use std::fs; +use std::fs::File; +use std::io::prelude::*; use analysis; use analysis::bounds::Bounds; @@ -722,14 +724,27 @@ fn generate_extern_c_funcs( for method_analysis in &object_analysis.virtual_methods { - try!(virtual_methods::generate_extern_c_func( - w, - env, - object_analysis, - method_analysis, - subclass_info, - 0 - )); + + let path = env.config.config_dir.join(&env.config.library_export_name) + .join(format!("{}-{}-trampoline.rs", + object_analysis.name.to_lowercase(), + method_analysis.name.to_lowercase())); + + if let Ok(mut file) = File::open(&path) { + let mut custom_str = String::new(); + file.read_to_string(&mut custom_str).unwrap(); + + try!(write!(w, "{}", custom_str)); + } else{ + try!(virtual_methods::generate_extern_c_func( + w, + env, + object_analysis, + method_analysis, + subclass_info, + 0 + )); + } } if object_analysis.is_interface{ diff --git a/src/config/config.rs b/src/config/config.rs index 76c5dee3c..86f7acefc 100644 --- a/src/config/config.rs +++ b/src/config/config.rs @@ -35,6 +35,7 @@ pub struct Config { pub concurrency: library::Concurrency, pub single_version_file: Option, pub generate_display_trait: bool, + pub config_dir: PathBuf } impl Config { @@ -196,6 +197,7 @@ impl Config { concurrency, single_version_file, generate_display_trait, + config_dir }) } diff --git a/tests/subclass/gio-subclass/action-get_state-trampoline.rs b/tests/subclass/gio-subclass/action-get_state-trampoline.rs new file mode 100644 index 000000000..300778039 --- /dev/null +++ b/tests/subclass/gio-subclass/action-get_state-trampoline.rs @@ -0,0 +1,18 @@ +unsafe extern "C" fn action_get_state +(ptr: *mut gio_ffi::GAction) -> *mut glib_ffi::GVariant +{ + callback_guard!(); + floating_reference_guard!(ptr); + let klass = &**(ptr as *const *const ClassStruct); + let interface_static = klass.get_interface_static(gio_ffi::g_action_get_type()) + as *const ActionStatic; + let instance = &*(ptr as *const T::InstanceStructType); + let imp = instance.get_impl(); + let imp = (*(*interface_static).imp_static).get_impl(imp); + let wrap: T = from_glib_borrow(instance); + + let ret = imp.get_state(&wrap); + let ptr = ret.to_glib_none().0; + mem::forget(ret); + ptr +} diff --git a/tests/subclass/gir-gio.toml b/tests/subclass/gir-gio.toml new file mode 100644 index 000000000..1fe272fc9 --- /dev/null +++ b/tests/subclass/gir-gio.toml @@ -0,0 +1,54 @@ +[options] +girs_dir = "../../../gir-files" +library = "Gio" +library_export = "gio-subclass" +version = "2.0" +min_cfg_version = "2.32" +target_path = "./gio-subclass" +work_mode = "subclass" + +generate = [ + "Gio.Action", + "Gio.ActionMap", + "Gio.AppInfo", + "Gio.AppLaunchContext", + "Gio.ApplicationFlags", + "Gio.Drive", + "Gio.Menu", + "Gio.MenuAttributeIter", + "Gio.MenuItem", + "Gio.MenuLinkIter", + "Gio.MenuModel", + "Gio.Mount", + "Gio.Permission", + "Gio.Resource", + "Gio.ResourceError", + "Gio.ResourceLookupFlags", + "Gio.Settings", + "Gio.SettingsBindFlags", + "Gio.SimpleAction", + "Gio.SimpleActionGroup", + "Gio.SimplePermission", + "Gio.Volume", + "Gio.VolumeMonitor", +] + +manual = [ + "GLib.Bytes", + "GLib.Error", + "GLib.Variant", + "GLib.VariantType", + "GObject.Object", +] + +[[object]] +name = "Gio.ActionGroup" +status = "generate" + [[object.function]] + name = "query_action" + ignore = true + +[[object]] +name = "Gio.Application" +status = "generate" +trait = true From f7c3aa286ef31dabf7f1777e1963e02d89e8b39e Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 8 Jun 2018 14:53:14 +0200 Subject: [PATCH 073/122] insert toplevel content as well --- src/codegen/subclass/class_impl.rs | 25 ++++++-- .../subclass/gio-subclass/application-main.rs | 58 +++++++++++++++++++ 2 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 tests/subclass/gio-subclass/application-main.rs diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 70f4855e5..038c421bd 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -2,6 +2,7 @@ use std::io::{Result, Write}; use std::fs; use std::fs::File; use std::io::prelude::*; +use std::path::PathBuf; use analysis; use analysis::bounds::Bounds; @@ -88,6 +89,16 @@ impl SubclassInfo { } +fn insert_from_file(w: &mut Write, path: &PathBuf) -> bool{ + if let Ok(mut file) = File::open(&path) { + let mut custom_str = String::new(); + file.read_to_string(&mut custom_str).unwrap(); + write!(w, "{}", custom_str); + return true; + } + false +} + pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> { try!(general::start_comments(w, &env.config)); @@ -110,6 +121,13 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> let subclass_info = SubclassInfo::new(env, analysis); + + let path = env.config.config_dir.join(&env.config.library_export_name) + .join(format!("{}-main.rs", + analysis.name.to_lowercase())); + + insert_from_file(w, &path); + try!(generate_impl(w, env, analysis, &subclass_info)); if !analysis.is_interface{ @@ -730,12 +748,7 @@ fn generate_extern_c_funcs( object_analysis.name.to_lowercase(), method_analysis.name.to_lowercase())); - if let Ok(mut file) = File::open(&path) { - let mut custom_str = String::new(); - file.read_to_string(&mut custom_str).unwrap(); - - try!(write!(w, "{}", custom_str)); - } else{ + if !insert_from_file(w, &path) { try!(virtual_methods::generate_extern_c_func( w, env, diff --git a/tests/subclass/gio-subclass/application-main.rs b/tests/subclass/gio-subclass/application-main.rs new file mode 100644 index 000000000..fc0cec15b --- /dev/null +++ b/tests/subclass/gio-subclass/application-main.rs @@ -0,0 +1,58 @@ +pub struct ArgumentList { + pub(crate) ptr: *mut *mut *mut libc::c_char, + items: Vec, +} + +impl ArgumentList { + pub(crate) fn new(arguments: *mut *mut *mut libc::c_char) -> Self { + Self { + ptr: arguments, + items: unsafe { FromGlibPtrContainer::from_glib_none(ptr::read(arguments)) }, + } + } + + pub(crate) fn refresh(&mut self) { + self.items = unsafe { FromGlibPtrContainer::from_glib_none(ptr::read(self.ptr)) }; + } + + // remove the item at index `idx` and shift the raw array + pub fn remove(&mut self, idx: usize) { + unsafe { + let n_args = glib_ffi::g_strv_length(*self.ptr); + assert!((n_args as usize) == self.items.len()); + assert!((idx as u32) < n_args); + + self.items.remove(idx); + + glib_ffi::g_free(((*self.ptr).offset(idx as isize)) as *mut libc::c_void); + + for i in (idx as u32)..n_args - 1 { + ptr::write( + (*self.ptr).offset(i as isize), + *(*self.ptr).offset((i + 1) as isize), + ) + } + ptr::write((*self.ptr).offset((n_args - 1) as isize), ptr::null_mut()); + } + } +} + +impl Deref for ArgumentList { + type Target = [OsString]; + + fn deref(&self) -> &Self::Target { + self.items.as_slice() + } +} + +impl fmt::Debug for ArgumentList { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + self.items.fmt(formatter) + } +} + +impl convert::Into> for ArgumentList { + fn into(self) -> Vec { + self.items.clone() + } +} From ec8264f2e374aa92617560f03fa00d4a305b0ae5 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 8 Jun 2018 15:06:25 +0200 Subject: [PATCH 074/122] insert content for other traits --- src/codegen/subclass/class_impl.rs | 96 +++++++++++-------- .../application-local_command_line-base.rs | 21 ++++ ...application-local_command_line-box_impl.rs | 5 + .../application-local_command_line-impl.rs | 4 + 4 files changed, 88 insertions(+), 38 deletions(-) create mode 100644 tests/subclass/gio-subclass/application-local_command_line-base.rs create mode 100644 tests/subclass/gio-subclass/application-local_command_line-box_impl.rs create mode 100644 tests/subclass/gio-subclass/application-local_command_line-impl.rs diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 038c421bd..4e7ad6fb1 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -143,11 +143,11 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> try!(generate_impl_base(w, env, analysis, &subclass_info)); try!(generate_class(w, env, analysis, &subclass_info)); try!(generate_parent_impls(w, env, analysis, &subclass_info)); - try!(generate_interface_impls(w, env, analysis, &subclass_info)); try!(generate_box_impl(w, env, analysis, &subclass_info)); try!(generate_impl_objecttype(w, env, analysis, &subclass_info)); }else{ try!(generate_impl_static(w, env, analysis, &subclass_info)); + try!(generate_interface_impls(w, env, analysis, &subclass_info)); } try!(generate_extern_c_funcs(w, env, analysis, &subclass_info)); @@ -235,14 +235,21 @@ pub fn generate_impl( )); }else{ - try!(virtual_methods::generate_default_impl( - w, - env, - object_analysis, - method_analysis, - subclass_info, - 1 - )); + let path = env.config.config_dir.join(&env.config.library_export_name) + .join(format!("{}-{}-impl.rs", + object_analysis.name.to_lowercase(), + method_analysis.name.to_lowercase())); + + if !insert_from_file(w, &path) { + try!(virtual_methods::generate_default_impl( + w, + env, + object_analysis, + method_analysis, + subclass_info, + 1 + )); + } } } @@ -308,14 +315,22 @@ pub fn generate_base( )); for method_analysis in &object_analysis.virtual_methods { - try!(virtual_methods::generate_base_impl( - w, - env, - object_analysis, - method_analysis, - subclass_info, - 1 - )); + + let path = env.config.config_dir.join(&env.config.library_export_name) + .join(format!("{}-{}-base.rs", + object_analysis.name.to_lowercase(), + method_analysis.name.to_lowercase())); + + if !insert_from_file(w, &path) { + try!(virtual_methods::generate_base_impl( + w, + env, + object_analysis, + method_analysis, + subclass_info, + 1 + )); + } } //end base trait @@ -370,19 +385,16 @@ fn generate_ext( }; - - // start base trait - try!(writeln!(w)); - try!(writeln!( - w, - "pub unsafe trait {}\nwhere\n{}T::ImplType: {}{{", - ext_name, - object_analysis.subclass_base_trait_name, - tabs(1), - object_analysis.subclass_impl_trait_name - )); - - + // start base trait + try!(writeln!(w)); + try!(writeln!( + w, + "pub unsafe trait {}\nwhere\n{}T::ImplType: {}{{", + ext_name, + object_analysis.subclass_base_trait_name, + tabs(1), + object_analysis.subclass_impl_trait_name + )); try!(virtual_methods::generate_override_vfuncs( w, @@ -590,14 +602,22 @@ fn generate_box_impl( for method_analysis in &object_analysis.virtual_methods { - try!(virtual_methods::generate_box_impl( - w, - env, - object_analysis, - method_analysis, - subclass_info, - 3 - )); + + let path = env.config.config_dir.join(&env.config.library_export_name) + .join(format!("{}-{}-box_impl.rs", + object_analysis.name.to_lowercase(), + method_analysis.name.to_lowercase())); + + if !insert_from_file(w, &path) { + try!(virtual_methods::generate_box_impl( + w, + env, + object_analysis, + method_analysis, + subclass_info, + 3 + )); + } } try!(writeln!(w, "{}}}", tabs(2))); diff --git a/tests/subclass/gio-subclass/application-local_command_line-base.rs b/tests/subclass/gio-subclass/application-local_command_line-base.rs new file mode 100644 index 000000000..da223b756 --- /dev/null +++ b/tests/subclass/gio-subclass/application-local_command_line-base.rs @@ -0,0 +1,21 @@ + + fn parent_local_command_line(&self, arguments: &mut ArgumentList) -> Option { + unsafe { + let klass = self.get_class(); + let parent_klass = (*klass).get_parent_class() as *const gio_ffi::GApplicationClass; + let mut exit_status = 0; + let success = (*parent_klass) + .local_command_line + .map(|f| { + let ret = f(self.to_glib_none().0, arguments.ptr, &mut exit_status); + arguments.refresh(); + ret + }) + .unwrap_or(glib_ffi::GFALSE); + + match success { + glib_ffi::GTRUE => Some(exit_status), + _ => None, + } + } + } diff --git a/tests/subclass/gio-subclass/application-local_command_line-box_impl.rs b/tests/subclass/gio-subclass/application-local_command_line-box_impl.rs new file mode 100644 index 000000000..ce07c4f5e --- /dev/null +++ b/tests/subclass/gio-subclass/application-local_command_line-box_impl.rs @@ -0,0 +1,5 @@ + + fn local_command_line(&self, application: &T, arguments: &mut ArgumentList) -> Option{ + let imp: &$name = self.as_ref(); + imp.local_command_line(application, arguments) + } diff --git a/tests/subclass/gio-subclass/application-local_command_line-impl.rs b/tests/subclass/gio-subclass/application-local_command_line-impl.rs new file mode 100644 index 000000000..1a1b01c70 --- /dev/null +++ b/tests/subclass/gio-subclass/application-local_command_line-impl.rs @@ -0,0 +1,4 @@ + + fn local_command_line(&self, application: &T, arguments: &mut ArgumentList) -> Option { + application.parent_local_command_line(arguments) + } From 595492e9ad36883c849720fbe0428f23680f3e07 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 8 Jun 2018 20:42:21 +0200 Subject: [PATCH 075/122] fix various issues when compiling generated code --- src/codegen/general.rs | 7 +++++++ src/codegen/subclass/class_impl.rs | 1 + src/codegen/subclass/statics.rs | 10 ++++++++++ src/codegen/subclass/virtual_method_body_chunks.rs | 4 ++-- .../gio-subclass/action-get_state-trampoline.rs | 2 +- 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/codegen/general.rs b/src/codegen/general.rs index 0947eb133..d96a32cd5 100644 --- a/src/codegen/general.rs +++ b/src/codegen/general.rs @@ -9,6 +9,7 @@ use config::Config; use config::derives::Derive; use env::Env; use gir_version::VERSION; +use config::WorkMode; use version::Version; use writer::primitives::tabs; @@ -46,6 +47,12 @@ from gir-files (https://github.com/gtk-rs/gir-files @ {})", pub fn uses(w: &mut Write, env: &Env, imports: &Imports) -> Result<()> { try!(writeln!(w)); for (name, &(ref version, ref constraints)) in imports.iter() { + + // HACK: skip ffi in subclass mode. + if name == "ffi" && env.config.work_mode == WorkMode::Subclass{ + continue + } + if constraints.len() == 1 { try!(writeln!(w, "#[cfg(feature = \"{}\")]", constraints[0])); } else if !constraints.is_empty() { diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 4e7ad6fb1..232c78582 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -103,6 +103,7 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> try!(general::start_comments(w, &env.config)); try!(statics_ffi::after_extern_crates(w)); + try!(statics::use_glib(w)); try!(statics::include_custom_modules(w, env)); try!(statics::use_subclass_modules(w, env)); try!(general::uses(w, env, &analysis.imports)); diff --git a/src/codegen/subclass/statics.rs b/src/codegen/subclass/statics.rs index 3aca2fc31..7cac6305e 100644 --- a/src/codegen/subclass/statics.rs +++ b/src/codegen/subclass/statics.rs @@ -5,7 +5,17 @@ use env::Env; use config::ExternalLibrary; use nameutil; use analysis::namespaces; +use super::super::general::write_vec; +pub fn use_glib(w: &mut Write) -> Result<()> { + let v = vec![ + "", + "#[allow(unused_imports)]", + "use glib_ffi::{gboolean, gconstpointer, gpointer, GType};", + ]; + + write_vec(w, &v) +} // TODO: copied from sys pub fn generate_extern_crates(w: &mut Write, env: &Env) -> Result<()> { diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index 5631eb78b..75d79dd16 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -233,8 +233,8 @@ impl Builder { body.push(Chunk::Let { is_mut: false, name: "wrap".to_owned(), - value: Box::new(Chunk::Custom("from_glib_borrow(instance)".to_owned())), - type_: Some(Box::new(Chunk::Custom("T".to_owned()))), + value: Box::new(Chunk::Custom("from_glib_borrow(ptr)".to_owned())), + type_: None, }); Chunk::Chunks(body) diff --git a/tests/subclass/gio-subclass/action-get_state-trampoline.rs b/tests/subclass/gio-subclass/action-get_state-trampoline.rs index 300778039..1d2f1f18a 100644 --- a/tests/subclass/gio-subclass/action-get_state-trampoline.rs +++ b/tests/subclass/gio-subclass/action-get_state-trampoline.rs @@ -9,7 +9,7 @@ unsafe extern "C" fn action_get_state let instance = &*(ptr as *const T::InstanceStructType); let imp = instance.get_impl(); let imp = (*(*interface_static).imp_static).get_impl(imp); - let wrap: T = from_glib_borrow(instance); + let wrap = from_glib_borrow(ptr); let ret = imp.get_state(&wrap); let ptr = ret.to_glib_none().0; From cabf8c4610e425f1bc542c5becffaede4687d7d8 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 8 Jun 2018 21:27:32 +0200 Subject: [PATCH 076/122] Into -> Pointer --- src/codegen/subclass/virtual_methods.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 1928ef0a2..8fb6bfefe 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -635,7 +635,7 @@ fn parameter_transformation(env: &Env, analysis: &analysis::virtual_methods::Inf TransformationType::ToGlibBorrow{..} => ConversionType::Borrow, TransformationType::ToGlibUnknown{..} => ConversionType::Unknown, TransformationType::ToGlibStash{..} => ConversionType::Unknown, - TransformationType::Into{..} => ConversionType::Unknown, + TransformationType::Into{..} => ConversionType::Pointer, TransformationType::Length{..} => ConversionType::Unknown, TransformationType::IntoRaw{..} => ConversionType::Pointer, TransformationType::ToSome{..} => ConversionType::Direct From 9f867521fae298af8f841d58c33fe6009b11c7b1 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 8 Jun 2018 21:35:52 +0200 Subject: [PATCH 077/122] I cannot get gir to transform nullable ptrs to Option --- .../action-activate-trampoline.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/subclass/gio-subclass/action-activate-trampoline.rs diff --git a/tests/subclass/gio-subclass/action-activate-trampoline.rs b/tests/subclass/gio-subclass/action-activate-trampoline.rs new file mode 100644 index 000000000..48de7e7d3 --- /dev/null +++ b/tests/subclass/gio-subclass/action-activate-trampoline.rs @@ -0,0 +1,20 @@ +unsafe extern "C" fn action_activate +(ptr: *mut gio_ffi::GAction, parameter: *mut glib_ffi::GVariant) +{ + callback_guard!(); + floating_reference_guard!(ptr); + let klass = &**(ptr as *const *const ClassStruct); + let interface_static = klass.get_interface_static(gio_ffi::g_action_get_type()) + as *const ActionStatic; + let instance = &*(ptr as *const T::InstanceStructType); + let imp = instance.get_impl(); + let imp = (*(*interface_static).imp_static).get_impl(imp); + let wrap = from_glib_borrow(ptr); + + let param = if parameter.is_null(){ + None + }else{ + Some(&from_glib_none(parameter)) + }; + imp.activate(&wrap, param) +} From 8230983b14cce182d51346c89abfc3ec30a93832 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 9 Jun 2018 09:02:38 +0200 Subject: [PATCH 078/122] manually transform option into nullptr --- .../action-get_parameter_type-trampoline.rs | 20 +++++++++++++++++++ .../action-get_state_type-trampoline.rs | 20 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 tests/subclass/gio-subclass/action-get_parameter_type-trampoline.rs create mode 100644 tests/subclass/gio-subclass/action-get_state_type-trampoline.rs diff --git a/tests/subclass/gio-subclass/action-get_parameter_type-trampoline.rs b/tests/subclass/gio-subclass/action-get_parameter_type-trampoline.rs new file mode 100644 index 000000000..0173427ca --- /dev/null +++ b/tests/subclass/gio-subclass/action-get_parameter_type-trampoline.rs @@ -0,0 +1,20 @@ +unsafe extern "C" fn action_get_parameter_type +(ptr: *mut gio_ffi::GAction) -> *const glib_ffi::GVariantType +{ + use std; + + callback_guard!(); + floating_reference_guard!(ptr); + let klass = &**(ptr as *const *const ClassStruct); + let interface_static = klass.get_interface_static(gio_ffi::g_action_get_type()) + as *const ActionStatic; + let instance = &*(ptr as *const T::InstanceStructType); + let imp = instance.get_impl(); + let imp = (*(*interface_static).imp_static).get_impl(imp); + let wrap = from_glib_borrow(ptr); + + match imp.get_parameter_type(&wrap){ + Some(t) => t/*Not checked*/.to_glib_none().0, + None => std::ptr::null() + } +} diff --git a/tests/subclass/gio-subclass/action-get_state_type-trampoline.rs b/tests/subclass/gio-subclass/action-get_state_type-trampoline.rs new file mode 100644 index 000000000..3c046fe91 --- /dev/null +++ b/tests/subclass/gio-subclass/action-get_state_type-trampoline.rs @@ -0,0 +1,20 @@ +unsafe extern "C" fn action_get_state_type +(ptr: *mut gio_ffi::GAction) -> *const glib_ffi::GVariantType +{ + use std; + + callback_guard!(); + floating_reference_guard!(ptr); + let klass = &**(ptr as *const *const ClassStruct); + let interface_static = klass.get_interface_static(gio_ffi::g_action_get_type()) + as *const ActionStatic; + let instance = &*(ptr as *const T::InstanceStructType); + let imp = instance.get_impl(); + let imp = (*(*interface_static).imp_static).get_impl(imp); + let wrap = from_glib_borrow(ptr); + + match imp.get_state_type(&wrap){ + Some(t) => t/*Not checked*/.to_glib_none().0, + None => std::ptr::null() + } +} From 96796c2e4839e55953f8f68616d84a40d604aed6 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 9 Jun 2018 20:12:55 +0200 Subject: [PATCH 079/122] add missing import statements for application --- tests/subclass/gio-subclass/application-main.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/subclass/gio-subclass/application-main.rs b/tests/subclass/gio-subclass/application-main.rs index fc0cec15b..e63d62efb 100644 --- a/tests/subclass/gio-subclass/application-main.rs +++ b/tests/subclass/gio-subclass/application-main.rs @@ -1,10 +1,15 @@ +use std::fmt; +use std::ffi::OsString; +use std::convert; +use std::ops::Deref; + pub struct ArgumentList { - pub(crate) ptr: *mut *mut *mut libc::c_char, + pub(crate) ptr: *mut *mut *mut c_char, items: Vec, } impl ArgumentList { - pub(crate) fn new(arguments: *mut *mut *mut libc::c_char) -> Self { + pub(crate) fn new(arguments: *mut *mut *mut c_char) -> Self { Self { ptr: arguments, items: unsafe { FromGlibPtrContainer::from_glib_none(ptr::read(arguments)) }, @@ -24,7 +29,7 @@ impl ArgumentList { self.items.remove(idx); - glib_ffi::g_free(((*self.ptr).offset(idx as isize)) as *mut libc::c_void); + glib_ffi::g_free(((*self.ptr).offset(idx as isize)) as *mut c_void); for i in (idx as u32)..n_args - 1 { ptr::write( From 8191d6d77f66bc985c6093a0c9fd59f5bc74a3b7 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 10 Jun 2018 08:00:33 +0200 Subject: [PATCH 080/122] fix compilation of action interface --- src/codegen/subclass/virtual_method_body_chunks.rs | 2 +- tests/subclass/gio-subclass/action-activate-trampoline.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index 75d79dd16..b776e2e90 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -289,7 +289,7 @@ impl Builder { is_mut: false, value: Box::new(Chunk::Custom( format!( - "&mut *(iface as *mut {}::{})", + "&mut *(iface as *mut {}::{}Interface)", self.ffi_crate_name, self.object_c_type ).to_owned(), )), diff --git a/tests/subclass/gio-subclass/action-activate-trampoline.rs b/tests/subclass/gio-subclass/action-activate-trampoline.rs index 48de7e7d3..03fce0f48 100644 --- a/tests/subclass/gio-subclass/action-activate-trampoline.rs +++ b/tests/subclass/gio-subclass/action-activate-trampoline.rs @@ -14,7 +14,7 @@ unsafe extern "C" fn action_activate let param = if parameter.is_null(){ None }else{ - Some(&from_glib_none(parameter)) + Some(from_glib_none(parameter)) }; - imp.activate(&wrap, param) + imp.activate(&wrap, param.as_ref()) } From b633689ec84766fed64d73556b705dcedc9d6728 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 10 Jun 2018 08:00:46 +0200 Subject: [PATCH 081/122] add own ffi type to glib wrapper --- src/codegen/subclass/class_impl.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 232c78582..0449c69d3 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -431,12 +431,24 @@ fn generate_glib_wrapper( if subclass_info.parents.len() > 0 { try!(write!(w, ":[")); + + let t = env.library.type_(object_analysis.type_id); + let k = &env.namespaces[object_analysis.type_id.ns_id].crate_name; + try!(write!( + w, + "\n{tabs} {krate}::{ty} => {krate}_ffi::{cty},", + tabs = tabs(2), + krate = k, + ty = t.get_name(), + cty = t.get_glib_name().unwrap() + )); + for parent in &subclass_info.parents { let t = env.library.type_(parent.type_id); let k = &env.namespaces[parent.type_id.ns_id].crate_name; try!(write!( w, - "\n{tabs} {krate}::{ty} => {krate}_ffi::{cty}", + "\n{tabs} {krate}::{ty} => {krate}_ffi::{cty},", tabs = tabs(2), krate = k, ty = t.get_name(), From a307a27a5fc55a082e7b530939c61ebecb98a569 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 10 Jun 2018 08:01:00 +0200 Subject: [PATCH 082/122] fix config for vfunc defs --- src/config/gobjects.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/gobjects.rs b/src/config/gobjects.rs index 54b303af4..f0f3c50a7 100644 --- a/src/config/gobjects.rs +++ b/src/config/gobjects.rs @@ -212,7 +212,7 @@ fn parse_object( let constants = Constants::parse(toml_object.lookup("constant"), &name); let functions = Functions::parse(toml_object.lookup("function"), &name); - let virtual_methods = Functions::parse(toml_object.lookup("virtual_methods"), &name); + let virtual_methods = Functions::parse(toml_object.lookup("virtual_method"), &name); let signals = { let mut v = Vec::new(); if let Some(configs) = toml_object.lookup("signal").and_then(|val| val.as_array()) { From a9e414c8fcdfc4c13d6e83b9d06c4420f74db3b5 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 10 Jun 2018 08:01:17 +0200 Subject: [PATCH 083/122] ignore some application vfuncs --- tests/subclass/gir-gio.toml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/subclass/gir-gio.toml b/tests/subclass/gir-gio.toml index 1fe272fc9..53f3750cb 100644 --- a/tests/subclass/gir-gio.toml +++ b/tests/subclass/gir-gio.toml @@ -52,3 +52,10 @@ status = "generate" name = "Gio.Application" status = "generate" trait = true + [[object.virtual_method]] + name = "handle_local_options" + ignore = true + + [[object.virtual_method]] + name = "add_platform_data" + ignore = true From 6babfc28807e1dbcad20616a8cea2e6bee717c8b Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 10 Jun 2018 12:17:26 +0200 Subject: [PATCH 084/122] implement conversion of nullable types --- src/analysis/virtual_methods.rs | 7 +++--- src/codegen/subclass/virtual_methods.rs | 11 +++++---- src/codegen/trampoline_to_glib.rs | 24 +++++++++++++++++++ .../action-get_parameter_type-trampoline.rs | 20 ---------------- .../action-get_state_type-trampoline.rs | 20 ---------------- tests/subclass/gir-gio.toml | 8 +++++++ 6 files changed, 41 insertions(+), 49 deletions(-) delete mode 100644 tests/subclass/gio-subclass/action-get_parameter_type-trampoline.rs delete mode 100644 tests/subclass/gio-subclass/action-get_state_type-trampoline.rs diff --git a/src/analysis/virtual_methods.rs b/src/analysis/virtual_methods.rs index 345af7889..76e152e18 100644 --- a/src/analysis/virtual_methods.rs +++ b/src/analysis/virtual_methods.rs @@ -233,10 +233,9 @@ fn analyze_virtual_method( } if async && !commented { - if env.config.library_name != "Gio" { - imports.add("gio_ffi", version); - imports.add_with_constraint("gio", version, Some("futures")); - } + imports.add("gio_ffi", version); + imports.add_with_constraint("gio", version, Some("futures")); + imports.add("glib_ffi", None); imports.add("gobject_ffi", None); imports.add_with_constraint("futures_core", version, Some("futures")); diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 8fb6bfefe..c2483a5ad 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -455,11 +455,12 @@ pub fn generate_extern_c_func( let func_ret = trampoline_call_return(env, method_analysis); func_params.insert(0, "&wrap".to_string()); - try!(writeln!(w, "{}imp.{}({}){}", + try!(writeln!(w, "{}{}imp.{}({}){}", tabs(indent+1), + func_ret.0, &method_analysis.name, func_params.join(", "), - func_ret)); + func_ret.1)); try!(writeln!( w, @@ -672,9 +673,9 @@ fn trampoline_call_parameters(env: &Env, analysis: &analysis::virtual_methods::I parameter_strs } -fn trampoline_call_return(env: &Env, analysis: &analysis::virtual_methods::Info) -> String { +fn trampoline_call_return(env: &Env, analysis: &analysis::virtual_methods::Info) -> (String, String) { match analysis.ret.parameter { - Some(ref param) => param.trampoline_to_glib(env), - None => String::new() + Some(ref param) => param.trampoline_to_glib_as_function(env), + None => (String::new(), String::new()) } } diff --git a/src/codegen/trampoline_to_glib.rs b/src/codegen/trampoline_to_glib.rs index 8251952f0..99be92045 100644 --- a/src/codegen/trampoline_to_glib.rs +++ b/src/codegen/trampoline_to_glib.rs @@ -4,10 +4,13 @@ use env; pub trait TrampolineToGlib { fn trampoline_to_glib(&self, env: &env::Env) -> String; + fn trampoline_to_glib_as_function(&self, env: &env::Env) -> (String, String); } impl TrampolineToGlib for library::Parameter { fn trampoline_to_glib(&self, env: &env::Env) -> String { + + use analysis::conversion_type::ConversionType::*; match ConversionType::of(env, self.typ) { Direct => String::new(), @@ -17,6 +20,27 @@ impl TrampolineToGlib for library::Parameter { Unknown => "/*Unknown conversion*/".to_owned(), } } + + fn trampoline_to_glib_as_function(&self, env: &env::Env) -> (String, String){ + + use analysis::conversion_type::ConversionType::*; + match ConversionType::of(env, self.typ) { + Direct => (String::new(), String::new()), + Scalar => (String::new(), ".to_glib()".to_owned()), + Pointer => { + if *self.nullable{ + let left = "match ".to_owned(); + let right = format!("{{ Some(t) => t{}, None => std::ptr::null()}}", to_glib_xxx(self.transfer)).to_owned(); + + (left, right) + }else{ + (String::new(), to_glib_xxx(self.transfer).to_owned()) + } + } + Borrow => (String::new(), "/*Not applicable conversion Borrow*/".to_owned()), + Unknown => (String::new(), "/*Unknown conversion*/".to_owned()), + } + } } fn to_glib_xxx(transfer: library::Transfer) -> &'static str { diff --git a/tests/subclass/gio-subclass/action-get_parameter_type-trampoline.rs b/tests/subclass/gio-subclass/action-get_parameter_type-trampoline.rs deleted file mode 100644 index 0173427ca..000000000 --- a/tests/subclass/gio-subclass/action-get_parameter_type-trampoline.rs +++ /dev/null @@ -1,20 +0,0 @@ -unsafe extern "C" fn action_get_parameter_type -(ptr: *mut gio_ffi::GAction) -> *const glib_ffi::GVariantType -{ - use std; - - callback_guard!(); - floating_reference_guard!(ptr); - let klass = &**(ptr as *const *const ClassStruct); - let interface_static = klass.get_interface_static(gio_ffi::g_action_get_type()) - as *const ActionStatic; - let instance = &*(ptr as *const T::InstanceStructType); - let imp = instance.get_impl(); - let imp = (*(*interface_static).imp_static).get_impl(imp); - let wrap = from_glib_borrow(ptr); - - match imp.get_parameter_type(&wrap){ - Some(t) => t/*Not checked*/.to_glib_none().0, - None => std::ptr::null() - } -} diff --git a/tests/subclass/gio-subclass/action-get_state_type-trampoline.rs b/tests/subclass/gio-subclass/action-get_state_type-trampoline.rs deleted file mode 100644 index 3c046fe91..000000000 --- a/tests/subclass/gio-subclass/action-get_state_type-trampoline.rs +++ /dev/null @@ -1,20 +0,0 @@ -unsafe extern "C" fn action_get_state_type -(ptr: *mut gio_ffi::GAction) -> *const glib_ffi::GVariantType -{ - use std; - - callback_guard!(); - floating_reference_guard!(ptr); - let klass = &**(ptr as *const *const ClassStruct); - let interface_static = klass.get_interface_static(gio_ffi::g_action_get_type()) - as *const ActionStatic; - let instance = &*(ptr as *const T::InstanceStructType); - let imp = instance.get_impl(); - let imp = (*(*interface_static).imp_static).get_impl(imp); - let wrap = from_glib_borrow(ptr); - - match imp.get_state_type(&wrap){ - Some(t) => t/*Not checked*/.to_glib_none().0, - None => std::ptr::null() - } -} diff --git a/tests/subclass/gir-gio.toml b/tests/subclass/gir-gio.toml index 53f3750cb..8c4b622d6 100644 --- a/tests/subclass/gir-gio.toml +++ b/tests/subclass/gir-gio.toml @@ -59,3 +59,11 @@ trait = true [[object.virtual_method]] name = "add_platform_data" ignore = true + + [[object.virtual_method]] + name = "dbus_register" + ignore = true + + [[object.virtual_method]] + name = "dbus_unregister" + ignore = true From 7d3db07f56585358af563bb5d13cf8f35f899d06 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 10 Jun 2018 16:31:36 +0200 Subject: [PATCH 085/122] rename ptr to gptr --- src/codegen/subclass/virtual_method_body_chunks.rs | 14 +++++++------- src/codegen/subclass/virtual_methods.rs | 2 +- src/codegen/trampoline_to_glib.rs | 5 +---- .../gio-subclass/action-activate-trampoline.rs | 10 +++++----- .../gio-subclass/action-get_state-trampoline.rs | 14 +++++++------- 5 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index b776e2e90..e2eb92557 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -144,13 +144,13 @@ impl Builder { let mut body = Vec::new(); body.push(self.callback_guard()); - body.push(self.floating_reference_guard("ptr")); + body.push(self.floating_reference_guard("gptr")); body.push(Chunk::Let { is_mut: false, name: self.object_name.to_lowercase(), value: Box::new(Chunk::Custom( - "&*(ptr as *mut T::InstanceStructType)".to_owned(), + "&*(gptr as *mut T::InstanceStructType)".to_owned(), )), type_: None, }); @@ -159,7 +159,7 @@ impl Builder { is_mut: false, name: "wrap".to_owned(), value: Box::new(Chunk::Custom( - "from_glib_borrow(ptr as *mut T::InstanceStructType)".to_owned(), + "from_glib_borrow(gptr as *mut T::InstanceStructType)".to_owned(), )), type_: Some(Box::new(Chunk::Custom("T".to_owned()))), }); @@ -180,13 +180,13 @@ impl Builder { let mut body = Vec::new(); body.push(self.callback_guard()); - body.push(self.floating_reference_guard("ptr")); + body.push(self.floating_reference_guard("gptr")); body.push(Chunk::Let { is_mut: false, name: "klass".to_owned(), value: Box::new(Chunk::Custom( - "&**(ptr as *const *const ClassStruct)" + "&**(gptr as *const *const ClassStruct)" .to_owned(), )), type_: None, @@ -211,7 +211,7 @@ impl Builder { is_mut: false, name: "instance".to_owned(), value: Box::new(Chunk::Custom( - "&*(ptr as *const T::InstanceStructType)".to_owned(), + "&*(gptr as *const T::InstanceStructType)".to_owned(), )), type_: None, }); @@ -233,7 +233,7 @@ impl Builder { body.push(Chunk::Let { is_mut: false, name: "wrap".to_owned(), - value: Box::new(Chunk::Custom("from_glib_borrow(ptr)".to_owned())), + value: Box::new(Chunk::Custom("from_glib_borrow(gptr)".to_owned())), type_: None, }); diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index c2483a5ad..66ab83753 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -535,7 +535,7 @@ pub fn function_signature(env: &Env, method: &analysis::virtual_methods::Info, b let mut parameter_strs: Vec = Vec::new(); for (pos, par) in method.parameters.c_parameters.iter().enumerate() { - let param_name = if pos == 0 { Some("ptr".to_owned()) } else { None }; + let param_name = if pos == 0 { Some("gptr".to_owned()) } else { None }; let (c, par_str) = function_parameter(env, par, bare, param_name.as_ref()); parameter_strs.push(par_str); diff --git a/src/codegen/trampoline_to_glib.rs b/src/codegen/trampoline_to_glib.rs index 99be92045..1c1f81217 100644 --- a/src/codegen/trampoline_to_glib.rs +++ b/src/codegen/trampoline_to_glib.rs @@ -9,8 +9,6 @@ pub trait TrampolineToGlib { impl TrampolineToGlib for library::Parameter { fn trampoline_to_glib(&self, env: &env::Env) -> String { - - use analysis::conversion_type::ConversionType::*; match ConversionType::of(env, self.typ) { Direct => String::new(), @@ -22,7 +20,6 @@ impl TrampolineToGlib for library::Parameter { } fn trampoline_to_glib_as_function(&self, env: &env::Env) -> (String, String){ - use analysis::conversion_type::ConversionType::*; match ConversionType::of(env, self.typ) { Direct => (String::new(), String::new()), @@ -30,7 +27,7 @@ impl TrampolineToGlib for library::Parameter { Pointer => { if *self.nullable{ let left = "match ".to_owned(); - let right = format!("{{ Some(t) => t{}, None => std::ptr::null()}}", to_glib_xxx(self.transfer)).to_owned(); + let right = format!("{{ Some(t) => t{}, None => ptr::null()}}", to_glib_xxx(self.transfer)).to_owned(); (left, right) }else{ diff --git a/tests/subclass/gio-subclass/action-activate-trampoline.rs b/tests/subclass/gio-subclass/action-activate-trampoline.rs index 03fce0f48..1ccdc6e11 100644 --- a/tests/subclass/gio-subclass/action-activate-trampoline.rs +++ b/tests/subclass/gio-subclass/action-activate-trampoline.rs @@ -1,15 +1,15 @@ unsafe extern "C" fn action_activate -(ptr: *mut gio_ffi::GAction, parameter: *mut glib_ffi::GVariant) +(gptr: *mut gio_ffi::GAction, parameter: *mut glib_ffi::GVariant) { callback_guard!(); - floating_reference_guard!(ptr); - let klass = &**(ptr as *const *const ClassStruct); + floating_reference_guard!(gptr); + let klass = &**(gptr as *const *const ClassStruct); let interface_static = klass.get_interface_static(gio_ffi::g_action_get_type()) as *const ActionStatic; - let instance = &*(ptr as *const T::InstanceStructType); + let instance = &*(gptr as *const T::InstanceStructType); let imp = instance.get_impl(); let imp = (*(*interface_static).imp_static).get_impl(imp); - let wrap = from_glib_borrow(ptr); + let wrap = from_glib_borrow(gptr); let param = if parameter.is_null(){ None diff --git a/tests/subclass/gio-subclass/action-get_state-trampoline.rs b/tests/subclass/gio-subclass/action-get_state-trampoline.rs index 1d2f1f18a..3a81a1c67 100644 --- a/tests/subclass/gio-subclass/action-get_state-trampoline.rs +++ b/tests/subclass/gio-subclass/action-get_state-trampoline.rs @@ -1,18 +1,18 @@ unsafe extern "C" fn action_get_state -(ptr: *mut gio_ffi::GAction) -> *mut glib_ffi::GVariant +(gptr: *mut gio_ffi::GAction) -> *mut glib_ffi::GVariant { callback_guard!(); - floating_reference_guard!(ptr); - let klass = &**(ptr as *const *const ClassStruct); + floating_reference_guard!(gptr); + let klass = &**(gptr as *const *const ClassStruct); let interface_static = klass.get_interface_static(gio_ffi::g_action_get_type()) as *const ActionStatic; - let instance = &*(ptr as *const T::InstanceStructType); + let instance = &*(gptr as *const T::InstanceStructType); let imp = instance.get_impl(); let imp = (*(*interface_static).imp_static).get_impl(imp); - let wrap = from_glib_borrow(ptr); + let wrap = from_glib_borrow(gptr); let ret = imp.get_state(&wrap); - let ptr = ret.to_glib_none().0; + let gptr = ret.to_glib_none().0; mem::forget(ret); - ptr + gptr } From 73e2e69de0a9f7ed51fb9d70be928cdf13771108 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 10 Jun 2018 16:52:08 +0200 Subject: [PATCH 086/122] fix ptr mutability --- src/codegen/trampoline_to_glib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/codegen/trampoline_to_glib.rs b/src/codegen/trampoline_to_glib.rs index 1c1f81217..0cfd2c438 100644 --- a/src/codegen/trampoline_to_glib.rs +++ b/src/codegen/trampoline_to_glib.rs @@ -26,8 +26,9 @@ impl TrampolineToGlib for library::Parameter { Scalar => (String::new(), ".to_glib()".to_owned()), Pointer => { if *self.nullable{ + let mut_str = if self.transfer == library::Transfer::Full{ "_mut"} else {""}; let left = "match ".to_owned(); - let right = format!("{{ Some(t) => t{}, None => ptr::null()}}", to_glib_xxx(self.transfer)).to_owned(); + let right = format!("{{ Some(t) => t{}, None => ptr::null{}()}}", to_glib_xxx(self.transfer), mut_str).to_owned(); (left, right) }else{ From a95bf236b9a3d8520959e1c1ef4a44d8a8f7a172 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 10 Jun 2018 16:52:24 +0200 Subject: [PATCH 087/122] generate interface register function --- src/codegen/subclass/class_impl.rs | 10 ++++- src/codegen/subclass/virtual_methods.rs | 53 +++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 0449c69d3..be2e5055b 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -803,8 +803,14 @@ fn generate_extern_c_funcs( 0 )); - // TODO: generate register_*>( - // see: https://github.com/sdroege/gst-plugin-rs/blob/25af5afb2bb9dfea79a13fd306d4b7fe36d26496/gst-plugin/src/uri_handler.rs#L123 + try!(virtual_methods::generate_interface_register( + w, + env, + object_analysis, + subclass_info, + 0 + )); + } diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 66ab83753..00a091eb5 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -611,6 +611,59 @@ unsafe extern \"C\" fn {}_init( try!(writeln!(w, "{}{}", tabs(indent+1), s)); } + try!(writeln!(w,"}}")); + + Ok(()) +} + + +pub fn generate_interface_register( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + subclass_info: &SubclassInfo, + indent: usize, +) -> Result<()> { + + try!(writeln!( + w, + " +unsafe extern \"C\" fn register_{}>( + _: &TypeInitToken, + type_: glib::Type, + imp: &I, +) {{", + object_analysis.name.to_lowercase(), + object_analysis.subclass_impl_trait_name + )); + + + try!(writeln!( + w, + " + unsafe {{ + let imp = imp as &{iface_impl}Static as *const {iface_impl}Static; + let interface_static = Box::new({iface}Static {{ + imp_static: imp, + }}); + let iface_info = gobject_ffi::GInterfaceInfo {{ + interface_init: Some({iface_l}_init::), + interface_finalize: None, + interface_data: Box::into_raw(interface_static) as glib_ffi::gpointer, + }}; + gobject_ffi::g_type_add_interface_static( + type_.to_glib(), + gio_ffi::g_{iface_l}_get_type(), + &iface_info, + ); + }} + ", + iface=object_analysis.name, + iface_impl=object_analysis.subclass_impl_trait_name, + iface_l=object_analysis.name.to_lowercase() + )); + + try!(writeln!(w,"}}")); Ok(()) From 0efb089d17fb6c005ce2797dc85ed0e46a07a29b Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 10 Jun 2018 21:39:16 +0200 Subject: [PATCH 088/122] fix eager copy/paste error --- src/codegen/subclass/virtual_methods.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 00a091eb5..20087b8c8 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -628,7 +628,7 @@ pub fn generate_interface_register( try!(writeln!( w, " -unsafe extern \"C\" fn register_{}>( +pub fn register_{}>( _: &TypeInitToken, type_: glib::Type, imp: &I, From 7d8b12c3ba88463523b0aedc4cc15bd604a0f31a Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 11 Jun 2018 13:30:38 +0200 Subject: [PATCH 089/122] generate import statements for subclass modules --- src/analysis/object.rs | 11 +++ src/codegen/subclass/class_impl.rs | 138 ++++++++++++++++++++++------- 2 files changed, 115 insertions(+), 34 deletions(-) diff --git a/src/analysis/object.rs b/src/analysis/object.rs index 6d662775f..2474350b9 100644 --- a/src/analysis/object.rs +++ b/src/analysis/object.rs @@ -48,6 +48,17 @@ impl Info { pub fn has_action_signals(&self) -> bool { self.signals.iter().any(|s| s.action_emit_name.is_some()) } + + pub fn module_name(&self, env: &Env) -> Option{ + let obj = &env.config.objects[&self.full_name]; + if !obj.status.need_generate() { + return None; + } + + Some(obj.module_name.clone().unwrap_or_else(|| { + module_name(split_namespace_name(&self.full_name).1) + })) + } } impl Deref for Info { diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index be2e5055b..f974ac72d 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -87,6 +87,61 @@ impl SubclassInfo { None } + fn get_all_parents<'a>(&self, env: &'a Env) -> Vec<&'a analysis::object::Info> + { + let mut pars = Vec::new(); + for parent in &self.parents { + if !env.analysis + .objects + .contains_key(&parent.type_id.full_name(&env.library)) + { + continue; + } + + let o = &env.analysis.objects[&parent.type_id.full_name(&env.library)]; + pars.push(o); + } + pars + } + + fn get_parents<'a>(&self, env: &'a Env) -> Vec<&'a analysis::object::Info> + { + let mut pars = Vec::new(); + for parent in &self.parents { + if !env.analysis + .objects + .contains_key(&parent.type_id.full_name(&env.library)) + { + continue; + } + + let o = &env.analysis.objects[&parent.type_id.full_name(&env.library)]; + if !o.is_interface{ + pars.push(o); + } + } + pars + } + + fn get_interfaces<'a>(&self, env: &'a Env) -> Vec<&'a analysis::object::Info> + { + let mut ifaces = Vec::new(); + for parent in &self.parents { + if !env.analysis + .objects + .contains_key(&parent.type_id.full_name(&env.library)) + { + continue; + } + + let o = &env.analysis.objects[&parent.type_id.full_name(&env.library)]; + if o.is_interface{ + ifaces.push(o); + } + } + ifaces + } + } fn insert_from_file(w: &mut Write, path: &PathBuf) -> bool{ @@ -108,20 +163,12 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> try!(statics::use_subclass_modules(w, env)); try!(general::uses(w, env, &analysis.imports)); + let subclass_info = SubclassInfo::new(env, analysis); - // match &*env.config.library_name { - // "GLib" => try!(statics::only_for_glib(w)), - // "GObject" => try!(statics::only_for_gobject(w)), - // "Gtk" => try!(statics::only_for_gtk(w)), - // _ => (), - // } - try!(writeln!(w)); - - - // TODO: insert gobject-subclass uses + try!(generate_subclass_uses(w, env, analysis, &subclass_info)); - let subclass_info = SubclassInfo::new(env, analysis); + try!(writeln!(w)); let path = env.config.config_dir.join(&env.config.library_export_name) .join(format!("{}-main.rs", @@ -183,6 +230,33 @@ pub fn generate_exports( // )); } +pub fn generate_subclass_uses(w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + subclass_info: &SubclassInfo, +) -> Result<()> { + + for parent in &subclass_info.get_all_parents(env){ + + let mut ns = "".to_string(); + if parent.type_id.ns_id != object_analysis.type_id.ns_id{ + let ns_name = &env.library.namespace(parent.type_id.ns_id).name; + ns = format!("{}subclass::", ns_name).to_string(); + } + + try!(writeln!( + w, + "use {}{};", + ns, + parent.module_name(env).unwrap_or("".to_string()) + )); + + } + + Ok(()) +} + + pub fn generate_impl( w: &mut Write, env: &Env, @@ -203,13 +277,17 @@ pub fn generate_impl( )); }else{ - let parents = subclass_info.parent_names(env, "_subclass"); + let parent_impls: Vec = subclass_info.get_parents(env) + .iter() + .map(|ref p| { format!(" {}::{}Impl +", p.module_name(env).unwrap_or("".to_string()), p.name) }) + .collect(); - let parent_impls: Vec = parents + let iface_impls: Vec = subclass_info.get_interfaces(env) .iter() - .map(|ref p| format!(" {}Impl +", p)) + .map(|ref p| { format!(" {}::{}Impl +", p.module_name(env).unwrap_or("".to_string()), p.name) }) .collect(); - let parent_objs = parent_impls.join(""); + + let parent_objs = parent_impls.join("") + &iface_impls.join(""); try!(writeln!( w, @@ -218,8 +296,6 @@ pub fn generate_impl( object_analysis.subclass_base_trait_name, parent_objs )); - - info!("supertypes, {:?}", parents); } @@ -525,15 +601,15 @@ fn generate_parent_impls( ) -> Result<()> { try!(writeln!(w)); - writeln!(w, "// FIXME: Boilerplate"); - if subclass_info.parents.len() > 0 { - for parent in &subclass_info.parents { - let t = env.library.type_(parent.type_id); + let parents = subclass_info.get_parents(env); + if parents.len() > 0 { + writeln!(w, "// FIXME: Boilerplate"); + for parent in parents { try!(writeln!( w, "unsafe impl {par}ClassExt<{obj}> for {obj}Class {{}}", obj = object_analysis.name, - par = t.get_name() + par = parent.name )); } } @@ -582,20 +658,14 @@ fn generate_box_impl( try!(writeln!(w, "{}($name:ident) => {{", tabs(1))); - if subclass_info.parents.len() > 0 { - for parent in &subclass_info.parents { - if !env.analysis - .objects - .contains_key(&parent.type_id.full_name(&env.library)) - { - continue; - } - let o = &env.analysis.objects[&parent.type_id.full_name(&env.library)]; + let parents = subclass_info.get_parents(env); + if parents.len() > 0 { + for parent in parents { try!(writeln!( w, "{}box_{}_impl!($name);", tabs(2), - o.name.to_lowercase() + parent.name.to_lowercase() )); } } else { @@ -694,7 +764,7 @@ fn generate_impl_objecttype( )); - for parent in &subclass_info.parents { + for parent in &subclass_info.get_parents(env) { try!(writeln!(w, "{}{}ClassExt::override_vfuncs(klass, token);", tabs(2), parent.name)); @@ -810,7 +880,7 @@ fn generate_extern_c_funcs( subclass_info, 0 )); - + } From 5c1ff95ae5a5db3621e22877dd2529f18fc84999 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 11 Jun 2018 13:31:05 +0200 Subject: [PATCH 090/122] use proper get_type function --- src/codegen/subclass/virtual_method_body_chunks.rs | 10 ++++++++-- src/codegen/subclass/virtual_methods.rs | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index e2eb92557..cd1a59af8 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -25,6 +25,7 @@ pub struct Builder { object_c_type: String, ffi_crate_name: String, glib_name: String, + get_type: String, method_name: String, parameters: Vec, transformations: Vec, @@ -64,6 +65,11 @@ impl Builder { self } + pub fn get_type(&mut self, get_type_fn: &str) -> &mut Builder { + self.get_type = get_type_fn.into(); + self + } + pub fn method_name(&mut self, name: &str) -> &mut Builder { self.method_name = name.into(); self @@ -197,10 +203,10 @@ impl Builder { name: "interface_static".to_owned(), value: Box::new(Chunk::Custom( format!( - "klass.get_interface_static({}::g_{}_get_type()) + "klass.get_interface_static({}::{}()) as *const {}Static", self.ffi_crate_name, - self.object_name.to_lowercase(), + self.get_type, self.object_name ).to_owned(), )), diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 20087b8c8..5016a22f8 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -484,6 +484,7 @@ pub fn body_chunk_builder(env: &Env, .object_class_c_type(object_analysis.c_class_type.as_ref().unwrap()) .ffi_crate_name(&env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name) .glib_name(&method_analysis.glib_name) + .get_type(&object_analysis.get_type) .method_name(&method_analysis.name) .assertion(method_analysis.assertion) .ret(&method_analysis.ret) From c1b3a91057c42e44f1b4592a198f5beac754249b Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 12 Jun 2018 15:54:10 +0200 Subject: [PATCH 091/122] various fixes for object generation --- src/codegen/subclass/class_impl.rs | 168 +++++++++++++++--------- src/codegen/subclass/virtual_methods.rs | 11 +- 2 files changed, 116 insertions(+), 63 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index f974ac72d..75acb2f37 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -80,6 +80,12 @@ impl SubclassInfo { } let o = &env.analysis.objects[&parent.type_id.full_name(&env.library)]; + let obj = &env.config.objects[&o.full_name]; + + if obj.status.ignored() { + continue; + } + if !o.is_interface{ return Some(o); } @@ -99,6 +105,11 @@ impl SubclassInfo { } let o = &env.analysis.objects[&parent.type_id.full_name(&env.library)]; + let obj = &env.config.objects[&o.full_name]; + debug!("object status {:?}: {:?}", o.full_name, obj.status); + if obj.status.ignored() { + continue; + } pars.push(o); } pars @@ -116,6 +127,12 @@ impl SubclassInfo { } let o = &env.analysis.objects[&parent.type_id.full_name(&env.library)]; + let obj = &env.config.objects[&o.full_name]; + debug!("object status {:?}: {:?}", o.full_name, obj.status); + + if obj.status.ignored() { + continue; + } if !o.is_interface{ pars.push(o); } @@ -133,8 +150,14 @@ impl SubclassInfo { { continue; } - let o = &env.analysis.objects[&parent.type_id.full_name(&env.library)]; + let obj = &env.config.objects[&o.full_name]; + debug!("object status {:?}: {:?}", o.full_name, obj.status); + + if obj.status.ignored() { + continue; + } + if o.is_interface{ ifaces.push(o); } @@ -160,11 +183,10 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> try!(statics_ffi::after_extern_crates(w)); try!(statics::use_glib(w)); try!(statics::include_custom_modules(w, env)); - try!(statics::use_subclass_modules(w, env)); try!(general::uses(w, env, &analysis.imports)); let subclass_info = SubclassInfo::new(env, analysis); - + try!(statics::use_subclass_modules(w, env)); try!(generate_subclass_uses(w, env, analysis, &subclass_info)); @@ -277,17 +299,12 @@ pub fn generate_impl( )); }else{ - let parent_impls: Vec = subclass_info.get_parents(env) + let parent_impls: Vec = subclass_info.get_all_parents(env) .iter() .map(|ref p| { format!(" {}::{}Impl +", p.module_name(env).unwrap_or("".to_string()), p.name) }) .collect(); - let iface_impls: Vec = subclass_info.get_interfaces(env) - .iter() - .map(|ref p| { format!(" {}::{}Impl +", p.module_name(env).unwrap_or("".to_string()), p.name) }) - .collect(); - - let parent_objs = parent_impls.join("") + &iface_impls.join(""); + let parent_objs = parent_impls.join(""); try!(writeln!( w, @@ -350,12 +367,16 @@ pub fn generate_impl_ext( try!(writeln!(w, "pub trait {} {{}}", implext_name)); // start ext trait impl - let parents = subclass_info.parent_names(env, ""); + let mut impls: Vec<&analysis::object::Info> = vec![object_analysis]; + impls.append(&mut subclass_info.get_parents(env)); + + let parent_impls: Vec = impls.iter() + .map(|ref p| { + let ns_name = &env.namespaces[p.type_id.ns_id].crate_name; + format!("+ glib::IsA<{}::{}>", ns_name, p.name) + }) + .collect(); - let parent_impls: Vec = parents - .iter() - .map(|ref p| format!("+ glib::IsA<{}>", p)) - .collect(); let parent_objs = parent_impls.join(" "); try!(writeln!( @@ -375,12 +396,17 @@ pub fn generate_base( object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo, ) -> Result<()> { - let parents = subclass_info.parent_names(env, ""); - let parent_impls: Vec = parents - .iter() - .map(|ref p| format!("+ glib::IsA<{}>", p)) - .collect(); + let mut impls: Vec<&analysis::object::Info> = vec![object_analysis]; + impls.append(&mut subclass_info.get_parents(env)); + + let parent_impls: Vec = impls.iter() + .map(|ref p| { + let ns_name = &env.namespaces[object_analysis.type_id.ns_id].crate_name; + format!("+ glib::IsA<{}::{}>", ns_name, p.name) + }) + .collect(); + let parent_objs = parent_impls.join(" "); // start base trait @@ -558,12 +584,17 @@ fn generate_impl_base( object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo, ) -> Result<()> { - let parents = subclass_info.parent_names(env, ""); - let parent_impls: Vec = parents - .iter() - .map(|ref p| format!("+ glib::IsA<{}>", p)) - .collect(); + let mut impls: Vec<&analysis::object::Info> = vec![object_analysis]; + impls.append(&mut subclass_info.get_parents(env)); + + let parent_impls: Vec = impls.iter() + .map(|ref p| { + let ns_name = &env.namespaces[p.type_id.ns_id].crate_name; + format!("+ glib::IsA<{}::{}>", ns_name, p.name) + }) + .collect(); + let parent_objs = parent_impls.join(" "); try!(writeln!(w)); @@ -602,18 +633,32 @@ fn generate_parent_impls( try!(writeln!(w)); let parents = subclass_info.get_parents(env); - if parents.len() > 0 { - writeln!(w, "// FIXME: Boilerplate"); - for parent in parents { - try!(writeln!( - w, - "unsafe impl {par}ClassExt<{obj}> for {obj}Class {{}}", - obj = object_analysis.name, - par = parent.name - )); - } + writeln!(w, "// FIXME: Boilerplate"); + + try!(writeln!( + w, + "unsafe impl {par}ClassExt<{obj}> for {obj}Class {{}}", + obj = object_analysis.name, + par = "Object".to_owned() + )); + + try!(writeln!( + w, + "unsafe impl {par}ClassExt<{obj}> for {obj}Class {{}}", + obj = object_analysis.name, + par = object_analysis.name + )); + + for parent in parents { + try!(writeln!( + w, + "unsafe impl {par}ClassExt<{obj}> for {obj}Class {{}}", + obj = object_analysis.name, + par = parent.name + )); } + Ok(()) } @@ -641,6 +686,13 @@ fn generate_interface_impls( Ok(()) } +fn box_impl_name(env: &Env, + analysis: &analysis::object::Info) -> String{ + format!("box_{}_{}_impl", + env.namespaces[analysis.type_id.ns_id].name.to_lowercase(), + analysis.name.to_lowercase()) +} + fn generate_box_impl( w: &mut Write, env: &Env, @@ -652,8 +704,8 @@ fn generate_box_impl( try!(writeln!(w, "#[macro_export]")); try!(writeln!( w, - "macro_rules! box_{}_impl(", - object_analysis.name.to_lowercase() + "macro_rules! {}(", + box_impl_name(env, object_analysis) )); try!(writeln!(w, "{}($name:ident) => {{", tabs(1))); @@ -663,9 +715,9 @@ fn generate_box_impl( for parent in parents { try!(writeln!( w, - "{}box_{}_impl!($name);", + "{}{}!($name);", tabs(2), - parent.name.to_lowercase() + box_impl_name(env, &parent) )); } } else { @@ -708,9 +760,18 @@ fn generate_box_impl( try!(writeln!(w, "{}}}", tabs(1))); try!(writeln!(w, ");")); + try!(writeln!(w)); + + try!(writeln!(w, "{}!({});", box_impl_name(env, object_analysis), object_analysis.subclass_impl_trait_name)); + Ok(()) } + +fn override_vfuncs_statement(name: &String) -> String{ + format!("{}ClassExt::override_vfuncs(klass, token);", name) +} + fn generate_impl_objecttype( w: &mut Write, env: &Env, @@ -730,20 +791,14 @@ fn generate_impl_objecttype( object_analysis.full_name )); - let parent = subclass_info.parent(env); - - if parent.is_some(){ - let p = parent.as_ref().unwrap(); - - let (ns, n) = nameutil::split_namespace_name(&p.full_name); + let (ns, n) = nameutil::split_namespace_name(&object_analysis.full_name); + try!(writeln!(w, "{}type ParentType = {}::{};", + tabs(1), + ns.unwrap_or("").to_lowercase(), + n + )); - try!(writeln!(w, "{}type ParentType = {}::{};", - tabs(1), - ns.unwrap_or("").to_lowercase(), - n - )); - } try!(writeln!(w, "{}type ImplType = Box<{}>;", tabs(1), @@ -759,15 +814,10 @@ fn generate_impl_objecttype( object_analysis.name )); - try!(writeln!(w, "{}ObjectClassExt::override_vfuncs(klass, token);", - tabs(2) - )); - - + try!(writeln!(w, "{}{}", tabs(2), override_vfuncs_statement(&"Object".to_string()))); + try!(writeln!(w, "{}{}", tabs(2), override_vfuncs_statement(&object_analysis.name))); for parent in &subclass_info.get_parents(env) { - try!(writeln!(w, "{}{}ClassExt::override_vfuncs(klass, token);", - tabs(2), - parent.name)); + try!(writeln!(w, "{}{}", tabs(2), override_vfuncs_statement(&parent.name))); } try!(writeln!(w, "{}}}", tabs(1))); diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 5016a22f8..897645b2b 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -130,15 +130,17 @@ pub fn default_impl_body_chunk(env: &Env, fn virtual_method_args(method_analysis: &analysis::virtual_methods::Info, include_parent: bool) -> String { let mut arg_str = String::with_capacity(100); + let mut cnt = 0; for (pos, par) in method_analysis.parameters.rust_parameters.iter().enumerate() { if !include_parent && pos == 0{ // skip the first one, continue; } - if pos > 1 { + if cnt > 0 { arg_str.push_str(", "); } arg_str.push_str(&par.name); + cnt += 1; } arg_str } @@ -377,7 +379,7 @@ pub fn generate_box_impl( declr, )); - let arg_str = virtual_method_args(method_analysis, false); + let arg_str = virtual_method_args(method_analysis, true); try!(writeln!( @@ -420,9 +422,10 @@ pub fn generate_extern_c_func( try!(writeln!( w, - "unsafe extern \"C\" fn {}_{}", + "unsafe extern \"C\" fn {}_{}", object_analysis.name.to_lowercase(), - method_analysis.name + method_analysis.name, + object_analysis.subclass_base_trait_name )); let (_, sig) = function_signature(env, method_analysis, false); From 649aea5532c4871685bd964c409e01e0d222a0b0 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 13 Jun 2018 20:21:50 +0200 Subject: [PATCH 092/122] fix implementation of gio application --- src/codegen/subclass/virtual_methods.rs | 8 ++- .../application-command_line-base.rs | 11 ++++ ...plication-local_command_line-trampoline.rs | 24 ++++++++ .../application-open-trampoline.rs | 18 ++++++ tests/subclass/gir-gio.toml | 58 +++++++++---------- 5 files changed, 88 insertions(+), 31 deletions(-) create mode 100644 tests/subclass/gio-subclass/application-command_line-base.rs create mode 100644 tests/subclass/gio-subclass/application-local_command_line-trampoline.rs create mode 100644 tests/subclass/gio-subclass/application-open-trampoline.rs diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 897645b2b..09544b335 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -419,13 +419,17 @@ pub fn generate_extern_c_func( try!(writeln!(w)); // TODO: use Chunk::ExternCFunc - + let base_trait_name = if object_analysis.is_interface { + "ObjectType".to_string() + } else { + object_analysis.subclass_base_trait_name.clone() + }; try!(writeln!( w, "unsafe extern \"C\" fn {}_{}", object_analysis.name.to_lowercase(), method_analysis.name, - object_analysis.subclass_base_trait_name + base_trait_name )); let (_, sig) = function_signature(env, method_analysis, false); diff --git a/tests/subclass/gio-subclass/application-command_line-base.rs b/tests/subclass/gio-subclass/application-command_line-base.rs new file mode 100644 index 000000000..43183f169 --- /dev/null +++ b/tests/subclass/gio-subclass/application-command_line-base.rs @@ -0,0 +1,11 @@ + + fn parent_command_line(&self, cmd_line: &gio::ApplicationCommandLine) -> i32 { + unsafe { + let klass = self.get_class(); + let parent_klass = (*klass).get_parent_class() as *const gio_ffi::GApplicationClass; + (*parent_klass) + .command_line + .map(|f| f(self.to_glib_none().0, cmd_line.to_glib_none().0)) + .unwrap_or(0) + } + } diff --git a/tests/subclass/gio-subclass/application-local_command_line-trampoline.rs b/tests/subclass/gio-subclass/application-local_command_line-trampoline.rs new file mode 100644 index 000000000..c2a745a18 --- /dev/null +++ b/tests/subclass/gio-subclass/application-local_command_line-trampoline.rs @@ -0,0 +1,24 @@ +unsafe extern "C" fn application_local_command_line( + ptr: *mut gio_ffi::GApplication, + arguments: *mut *mut *mut c_char, + exit_status: *mut c_int, +) -> glib_ffi::gboolean +where + T::ImplType: ApplicationImpl, +{ + callback_guard!(); + floating_reference_guard!(ptr); + let application = &*(ptr as *mut T::InstanceStructType); + let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType); + let imp = application.get_impl(); + + let mut args = ArgumentList::new(arguments); + + match imp.local_command_line(&wrap, &mut args) { + Some(ret) => { + ptr::write(exit_status, ret); + glib_ffi::GTRUE + } + None => glib_ffi::GFALSE, + } +} diff --git a/tests/subclass/gio-subclass/application-open-trampoline.rs b/tests/subclass/gio-subclass/application-open-trampoline.rs new file mode 100644 index 000000000..126d72a6e --- /dev/null +++ b/tests/subclass/gio-subclass/application-open-trampoline.rs @@ -0,0 +1,18 @@ +unsafe extern "C" fn application_open( + ptr: *mut gio_ffi::GApplication, + files: *mut *mut gio_ffi::GFile, + num_files: c_int, + hint: *const c_char, +) where + T::ImplType: ApplicationImpl, +{ + callback_guard!(); + floating_reference_guard!(ptr); + let application = &*(ptr as *mut T::InstanceStructType); + let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType); + let imp = application.get_impl(); + + let files_r: Vec = FromGlibContainer::from_glib_none_num(files, num_files as usize); + let hint_r: String = from_glib_none(hint); + imp.open(&wrap, &files_r.as_slice(), &hint_r.as_str()) +} diff --git a/tests/subclass/gir-gio.toml b/tests/subclass/gir-gio.toml index 8c4b622d6..43a283890 100644 --- a/tests/subclass/gir-gio.toml +++ b/tests/subclass/gir-gio.toml @@ -9,28 +9,28 @@ work_mode = "subclass" generate = [ "Gio.Action", - "Gio.ActionMap", - "Gio.AppInfo", - "Gio.AppLaunchContext", - "Gio.ApplicationFlags", - "Gio.Drive", - "Gio.Menu", - "Gio.MenuAttributeIter", - "Gio.MenuItem", - "Gio.MenuLinkIter", - "Gio.MenuModel", - "Gio.Mount", - "Gio.Permission", - "Gio.Resource", - "Gio.ResourceError", - "Gio.ResourceLookupFlags", - "Gio.Settings", - "Gio.SettingsBindFlags", - "Gio.SimpleAction", - "Gio.SimpleActionGroup", - "Gio.SimplePermission", - "Gio.Volume", - "Gio.VolumeMonitor", + # "Gio.ActionMap", + # "Gio.AppInfo", + # "Gio.AppLaunchContext", + # "Gio.ApplicationFlags", + # "Gio.Drive", + # "Gio.Menu", + # "Gio.MenuAttributeIter", + # "Gio.MenuItem", + # "Gio.MenuLinkIter", + # "Gio.MenuModel", + # "Gio.Mount", + # "Gio.Permission", + # "Gio.Resource", + # "Gio.ResourceError", + # "Gio.ResourceLookupFlags", + # "Gio.Settings", + # "Gio.SettingsBindFlags", + # "Gio.SimpleAction", + # "Gio.SimpleActionGroup", + # "Gio.SimplePermission", + # "Gio.Volume", + # "Gio.VolumeMonitor", ] manual = [ @@ -41,12 +41,12 @@ manual = [ "GObject.Object", ] -[[object]] -name = "Gio.ActionGroup" -status = "generate" - [[object.function]] - name = "query_action" - ignore = true +# [[object]] +# name = "Gio.ActionGroup" +# status = "generate" +# [[object.function]] +# name = "query_action" +# ignore = true [[object]] name = "Gio.Application" @@ -63,7 +63,7 @@ trait = true [[object.virtual_method]] name = "dbus_register" ignore = true - + [[object.virtual_method]] name = "dbus_unregister" ignore = true From e2b25f7bc276e1d423babdb3518dc6a464aa6f51 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 14 Jun 2018 12:46:08 +0200 Subject: [PATCH 093/122] fix invalid object name --- src/codegen/subclass/class_impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 75acb2f37..fa520ea01 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -788,7 +788,7 @@ fn generate_impl_objecttype( try!(writeln!(w, "{}const NAME: &'static str = \"Rs{}\";", tabs(1), - object_analysis.full_name + object_analysis.full_name.replace(".", "") )); From b31b0c5c8ce49bf64a9ac78bc2f02e5961ff4128 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 15 Jun 2018 12:01:54 +0200 Subject: [PATCH 094/122] move custom snippets to target path --- src/codegen/subclass/class_impl.rs | 38 +++++------ src/codegen/subclass/mod.rs | 12 ++-- .../application-command_line-base.rs | 11 ---- .../application-local_command_line-base.rs | 21 ------- ...application-local_command_line-box_impl.rs | 5 -- .../application-local_command_line-impl.rs | 4 -- ...plication-local_command_line-trampoline.rs | 24 ------- .../subclass/gio-subclass/application-main.rs | 63 ------------------- .../application-open-trampoline.rs | 18 ------ 9 files changed, 25 insertions(+), 171 deletions(-) delete mode 100644 tests/subclass/gio-subclass/application-command_line-base.rs delete mode 100644 tests/subclass/gio-subclass/application-local_command_line-base.rs delete mode 100644 tests/subclass/gio-subclass/application-local_command_line-box_impl.rs delete mode 100644 tests/subclass/gio-subclass/application-local_command_line-impl.rs delete mode 100644 tests/subclass/gio-subclass/application-local_command_line-trampoline.rs delete mode 100644 tests/subclass/gio-subclass/application-main.rs delete mode 100644 tests/subclass/gio-subclass/application-open-trampoline.rs diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index fa520ea01..ac4c2b107 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -192,9 +192,9 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> try!(writeln!(w)); - let path = env.config.config_dir.join(&env.config.library_export_name) - .join(format!("{}-main.rs", - analysis.name.to_lowercase())); + let path = env.config.target_path.join("src").join("custom") + .join(format!("{}-main.rs", + analysis.name.to_lowercase())); insert_from_file(w, &path); @@ -329,10 +329,10 @@ pub fn generate_impl( )); }else{ - let path = env.config.config_dir.join(&env.config.library_export_name) - .join(format!("{}-{}-impl.rs", - object_analysis.name.to_lowercase(), - method_analysis.name.to_lowercase())); + let path = env.config.target_path.join("src").join("custom") + .join(format!("{}-{}-impl.rs", + object_analysis.name.to_lowercase(), + method_analysis.name.to_lowercase())); if !insert_from_file(w, &path) { try!(virtual_methods::generate_default_impl( @@ -419,10 +419,10 @@ pub fn generate_base( for method_analysis in &object_analysis.virtual_methods { - let path = env.config.config_dir.join(&env.config.library_export_name) - .join(format!("{}-{}-base.rs", - object_analysis.name.to_lowercase(), - method_analysis.name.to_lowercase())); + let path = env.config.target_path.join("src").join("custom") + .join(format!("{}-{}-base.rs", + object_analysis.name.to_lowercase(), + method_analysis.name.to_lowercase())); if !insert_from_file(w, &path) { try!(virtual_methods::generate_base_impl( @@ -738,10 +738,10 @@ fn generate_box_impl( for method_analysis in &object_analysis.virtual_methods { - let path = env.config.config_dir.join(&env.config.library_export_name) - .join(format!("{}-{}-box_impl.rs", - object_analysis.name.to_lowercase(), - method_analysis.name.to_lowercase())); + let path = env.config.target_path.join("src").join("custom") + .join(format!("{}-{}-box_impl.rs", + object_analysis.name.to_lowercase(), + method_analysis.name.to_lowercase())); if !insert_from_file(w, &path) { try!(virtual_methods::generate_box_impl( @@ -896,10 +896,10 @@ fn generate_extern_c_funcs( for method_analysis in &object_analysis.virtual_methods { - let path = env.config.config_dir.join(&env.config.library_export_name) - .join(format!("{}-{}-trampoline.rs", - object_analysis.name.to_lowercase(), - method_analysis.name.to_lowercase())); + let path = env.config.target_path.join("src").join("custom") + .join(format!("{}-{}-trampoline.rs", + object_analysis.name.to_lowercase(), + method_analysis.name.to_lowercase())); if !insert_from_file(w, &path) { try!(virtual_methods::generate_extern_c_func( diff --git a/src/codegen/subclass/mod.rs b/src/codegen/subclass/mod.rs index 0a4a61bab..e51dabb78 100644 --- a/src/codegen/subclass/mod.rs +++ b/src/codegen/subclass/mod.rs @@ -24,7 +24,7 @@ pub fn generate(env: &Env) { class_impls::generate(env, &root_path, &mut lib_rs); - generate_lib_rs(env, &root_path, &lib_rs); + generate_mod_rs(env, &root_path, &lib_rs); // lib_::generate(env); // build::generate(env); @@ -33,15 +33,15 @@ pub fn generate(env: &Env) { } -pub fn generate_lib_rs(env: &Env, root_path: &Path, lib_rs: &[String]) { +pub fn generate_mod_rs(env: &Env, root_path: &Path, lib_rs: &[String]) { - let path = root_path.join("lib.rs"); + let path = root_path.join("mod.rs"); save_to_file(path, env.config.make_backup, |w| { try!(general::start_comments(w, &env.config)); try!(writeln!(w)); - try!(statics_ffi::begin(w)); - try!(statics::generate_extern_crates(w, env)); - try!(writeln!(w)); + // try!(statics_ffi::begin(w)); + // try!(statics::generate_extern_crates(w, env)); + // try!(writeln!(w)); general::write_vec(w, lib_rs) }); } diff --git a/tests/subclass/gio-subclass/application-command_line-base.rs b/tests/subclass/gio-subclass/application-command_line-base.rs deleted file mode 100644 index 43183f169..000000000 --- a/tests/subclass/gio-subclass/application-command_line-base.rs +++ /dev/null @@ -1,11 +0,0 @@ - - fn parent_command_line(&self, cmd_line: &gio::ApplicationCommandLine) -> i32 { - unsafe { - let klass = self.get_class(); - let parent_klass = (*klass).get_parent_class() as *const gio_ffi::GApplicationClass; - (*parent_klass) - .command_line - .map(|f| f(self.to_glib_none().0, cmd_line.to_glib_none().0)) - .unwrap_or(0) - } - } diff --git a/tests/subclass/gio-subclass/application-local_command_line-base.rs b/tests/subclass/gio-subclass/application-local_command_line-base.rs deleted file mode 100644 index da223b756..000000000 --- a/tests/subclass/gio-subclass/application-local_command_line-base.rs +++ /dev/null @@ -1,21 +0,0 @@ - - fn parent_local_command_line(&self, arguments: &mut ArgumentList) -> Option { - unsafe { - let klass = self.get_class(); - let parent_klass = (*klass).get_parent_class() as *const gio_ffi::GApplicationClass; - let mut exit_status = 0; - let success = (*parent_klass) - .local_command_line - .map(|f| { - let ret = f(self.to_glib_none().0, arguments.ptr, &mut exit_status); - arguments.refresh(); - ret - }) - .unwrap_or(glib_ffi::GFALSE); - - match success { - glib_ffi::GTRUE => Some(exit_status), - _ => None, - } - } - } diff --git a/tests/subclass/gio-subclass/application-local_command_line-box_impl.rs b/tests/subclass/gio-subclass/application-local_command_line-box_impl.rs deleted file mode 100644 index ce07c4f5e..000000000 --- a/tests/subclass/gio-subclass/application-local_command_line-box_impl.rs +++ /dev/null @@ -1,5 +0,0 @@ - - fn local_command_line(&self, application: &T, arguments: &mut ArgumentList) -> Option{ - let imp: &$name = self.as_ref(); - imp.local_command_line(application, arguments) - } diff --git a/tests/subclass/gio-subclass/application-local_command_line-impl.rs b/tests/subclass/gio-subclass/application-local_command_line-impl.rs deleted file mode 100644 index 1a1b01c70..000000000 --- a/tests/subclass/gio-subclass/application-local_command_line-impl.rs +++ /dev/null @@ -1,4 +0,0 @@ - - fn local_command_line(&self, application: &T, arguments: &mut ArgumentList) -> Option { - application.parent_local_command_line(arguments) - } diff --git a/tests/subclass/gio-subclass/application-local_command_line-trampoline.rs b/tests/subclass/gio-subclass/application-local_command_line-trampoline.rs deleted file mode 100644 index c2a745a18..000000000 --- a/tests/subclass/gio-subclass/application-local_command_line-trampoline.rs +++ /dev/null @@ -1,24 +0,0 @@ -unsafe extern "C" fn application_local_command_line( - ptr: *mut gio_ffi::GApplication, - arguments: *mut *mut *mut c_char, - exit_status: *mut c_int, -) -> glib_ffi::gboolean -where - T::ImplType: ApplicationImpl, -{ - callback_guard!(); - floating_reference_guard!(ptr); - let application = &*(ptr as *mut T::InstanceStructType); - let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType); - let imp = application.get_impl(); - - let mut args = ArgumentList::new(arguments); - - match imp.local_command_line(&wrap, &mut args) { - Some(ret) => { - ptr::write(exit_status, ret); - glib_ffi::GTRUE - } - None => glib_ffi::GFALSE, - } -} diff --git a/tests/subclass/gio-subclass/application-main.rs b/tests/subclass/gio-subclass/application-main.rs deleted file mode 100644 index e63d62efb..000000000 --- a/tests/subclass/gio-subclass/application-main.rs +++ /dev/null @@ -1,63 +0,0 @@ -use std::fmt; -use std::ffi::OsString; -use std::convert; -use std::ops::Deref; - -pub struct ArgumentList { - pub(crate) ptr: *mut *mut *mut c_char, - items: Vec, -} - -impl ArgumentList { - pub(crate) fn new(arguments: *mut *mut *mut c_char) -> Self { - Self { - ptr: arguments, - items: unsafe { FromGlibPtrContainer::from_glib_none(ptr::read(arguments)) }, - } - } - - pub(crate) fn refresh(&mut self) { - self.items = unsafe { FromGlibPtrContainer::from_glib_none(ptr::read(self.ptr)) }; - } - - // remove the item at index `idx` and shift the raw array - pub fn remove(&mut self, idx: usize) { - unsafe { - let n_args = glib_ffi::g_strv_length(*self.ptr); - assert!((n_args as usize) == self.items.len()); - assert!((idx as u32) < n_args); - - self.items.remove(idx); - - glib_ffi::g_free(((*self.ptr).offset(idx as isize)) as *mut c_void); - - for i in (idx as u32)..n_args - 1 { - ptr::write( - (*self.ptr).offset(i as isize), - *(*self.ptr).offset((i + 1) as isize), - ) - } - ptr::write((*self.ptr).offset((n_args - 1) as isize), ptr::null_mut()); - } - } -} - -impl Deref for ArgumentList { - type Target = [OsString]; - - fn deref(&self) -> &Self::Target { - self.items.as_slice() - } -} - -impl fmt::Debug for ArgumentList { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - self.items.fmt(formatter) - } -} - -impl convert::Into> for ArgumentList { - fn into(self) -> Vec { - self.items.clone() - } -} diff --git a/tests/subclass/gio-subclass/application-open-trampoline.rs b/tests/subclass/gio-subclass/application-open-trampoline.rs deleted file mode 100644 index 126d72a6e..000000000 --- a/tests/subclass/gio-subclass/application-open-trampoline.rs +++ /dev/null @@ -1,18 +0,0 @@ -unsafe extern "C" fn application_open( - ptr: *mut gio_ffi::GApplication, - files: *mut *mut gio_ffi::GFile, - num_files: c_int, - hint: *const c_char, -) where - T::ImplType: ApplicationImpl, -{ - callback_guard!(); - floating_reference_guard!(ptr); - let application = &*(ptr as *mut T::InstanceStructType); - let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType); - let imp = application.get_impl(); - - let files_r: Vec = FromGlibContainer::from_glib_none_num(files, num_files as usize); - let hint_r: String = from_glib_none(hint); - imp.open(&wrap, &files_r.as_slice(), &hint_r.as_str()) -} From 8da4b0fd3a2cd95d8bd4d42bdeaa385aab5e8411 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 22 Jun 2018 23:10:42 +0200 Subject: [PATCH 095/122] use correct get_type function --- src/codegen/subclass/virtual_methods.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 09544b335..3ccd27167 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -661,14 +661,16 @@ pub fn register_{}>( }}; gobject_ffi::g_type_add_interface_static( type_.to_glib(), - gio_ffi::g_{iface_l}_get_type(), + {ffi_crate}::{get_type}(), &iface_info, ); }} ", iface=object_analysis.name, iface_impl=object_analysis.subclass_impl_trait_name, - iface_l=object_analysis.name.to_lowercase() + iface_l=object_analysis.name.to_lowercase(), + ffi_crate=&env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name, + get_type=object_analysis.get_type )); From a9a56047d9ea2631b6cbf5c8389a88bff6b6f797 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 22 Jun 2018 23:13:18 +0200 Subject: [PATCH 096/122] don't add template param for interfaces --- src/codegen/subclass/class_impl.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index ac4c2b107..d711c8f44 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -301,7 +301,9 @@ pub fn generate_impl( let parent_impls: Vec = subclass_info.get_all_parents(env) .iter() - .map(|ref p| { format!(" {}::{}Impl +", p.module_name(env).unwrap_or("".to_string()), p.name) }) + .map(|ref p| { + let templ = if p.is_interface { "" } else {""}; + format!(" {}::{}Impl{} +", p.module_name(env).unwrap_or("".to_string()), p.name, templ) }) .collect(); let parent_objs = parent_impls.join(""); From e893ad32e81692c37489d4ea9e6d505e9f1d0909 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 22 Jun 2018 23:16:57 +0200 Subject: [PATCH 097/122] don't add trait bounds for interfaces --- src/codegen/subclass/class_impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index d711c8f44..5f6c17f80 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -299,7 +299,7 @@ pub fn generate_impl( )); }else{ - let parent_impls: Vec = subclass_info.get_all_parents(env) + let parent_impls: Vec = subclass_info.get_parents(env) .iter() .map(|ref p| { let templ = if p.is_interface { "" } else {""}; From 387dc6e83cd919e18410bfa353dfb98ea348c9ae Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 23 Jun 2018 08:55:08 +0200 Subject: [PATCH 098/122] make custom implementation filenames on par with module name --- src/codegen/subclass/class_impl.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 5f6c17f80..276d4d414 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -194,7 +194,7 @@ pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> let path = env.config.target_path.join("src").join("custom") .join(format!("{}-main.rs", - analysis.name.to_lowercase())); + analysis.module_name(env).unwrap_or(analysis.name.to_lowercase()))); insert_from_file(w, &path); @@ -333,7 +333,7 @@ pub fn generate_impl( let path = env.config.target_path.join("src").join("custom") .join(format!("{}-{}-impl.rs", - object_analysis.name.to_lowercase(), + object_analysis.module_name(env).unwrap_or(object_analysis.name.to_lowercase()), method_analysis.name.to_lowercase())); if !insert_from_file(w, &path) { @@ -423,7 +423,7 @@ pub fn generate_base( let path = env.config.target_path.join("src").join("custom") .join(format!("{}-{}-base.rs", - object_analysis.name.to_lowercase(), + object_analysis.module_name(env).unwrap_or(object_analysis.name.to_lowercase()), method_analysis.name.to_lowercase())); if !insert_from_file(w, &path) { @@ -742,7 +742,7 @@ fn generate_box_impl( let path = env.config.target_path.join("src").join("custom") .join(format!("{}-{}-box_impl.rs", - object_analysis.name.to_lowercase(), + object_analysis.module_name(env).unwrap_or(object_analysis.name.to_lowercase()), method_analysis.name.to_lowercase())); if !insert_from_file(w, &path) { @@ -900,7 +900,7 @@ fn generate_extern_c_funcs( let path = env.config.target_path.join("src").join("custom") .join(format!("{}-{}-trampoline.rs", - object_analysis.name.to_lowercase(), + object_analysis.module_name(env).unwrap_or(object_analysis.name.to_lowercase()), method_analysis.name.to_lowercase())); if !insert_from_file(w, &path) { From ffe400765e460788589a6f06456e49ac5f8ba243 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 23 Jun 2018 17:22:21 +0200 Subject: [PATCH 099/122] fix import path for subclass parents --- src/codegen/subclass/class_impl.rs | 37 ++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 276d4d414..6dc69f1e4 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -252,6 +252,23 @@ pub fn generate_exports( // )); } +fn subclass_parent_module_path(object: &analysis::object::Info, parent: &analysis::object::Info, env: &Env, include_crate: bool) -> String{ + + let mut ns = "".to_string(); + if include_crate{ + if parent.type_id.ns_id != object.type_id.ns_id{ + let ns_name = &env.library.namespace(parent.type_id.ns_id).name; + ns = format!("{}_subclass::", ns_name.to_lowercase()).to_string(); + } + } + + let obj = &env.config.objects[&parent.full_name]; + let module_name = obj.module_name.clone().unwrap_or_else(|| { + nameutil::module_name(nameutil::split_namespace_name(&parent.full_name).1) + }); + format!("{}{}", ns, module_name) +} + pub fn generate_subclass_uses(w: &mut Write, env: &Env, object_analysis: &analysis::object::Info, @@ -260,19 +277,13 @@ pub fn generate_subclass_uses(w: &mut Write, for parent in &subclass_info.get_all_parents(env){ - let mut ns = "".to_string(); - if parent.type_id.ns_id != object_analysis.type_id.ns_id{ - let ns_name = &env.library.namespace(parent.type_id.ns_id).name; - ns = format!("{}subclass::", ns_name).to_string(); - } + let parent_module_path = subclass_parent_module_path(parent, object_analysis, env, true); try!(writeln!( w, - "use {}{};", - ns, - parent.module_name(env).unwrap_or("".to_string()) + "use {};", + parent_module_path )); - } Ok(()) @@ -303,7 +314,7 @@ pub fn generate_impl( .iter() .map(|ref p| { let templ = if p.is_interface { "" } else {""}; - format!(" {}::{}Impl{} +", p.module_name(env).unwrap_or("".to_string()), p.name, templ) }) + format!(" {}::{}Impl{} +", subclass_parent_module_path(p, object_analysis, env, false), p.name, templ) }) .collect(); let parent_objs = parent_impls.join(""); @@ -654,8 +665,9 @@ fn generate_parent_impls( for parent in parents { try!(writeln!( w, - "unsafe impl {par}ClassExt<{obj}> for {obj}Class {{}}", + "unsafe impl {par_mod}::{par}ClassExt<{obj}> for {obj}Class {{}}", obj = object_analysis.name, + par_mod = subclass_parent_module_path(object_analysis, parent, env, false), par = parent.name )); } @@ -819,7 +831,8 @@ fn generate_impl_objecttype( try!(writeln!(w, "{}{}", tabs(2), override_vfuncs_statement(&"Object".to_string()))); try!(writeln!(w, "{}{}", tabs(2), override_vfuncs_statement(&object_analysis.name))); for parent in &subclass_info.get_parents(env) { - try!(writeln!(w, "{}{}", tabs(2), override_vfuncs_statement(&parent.name))); + let par_mod = subclass_parent_module_path(object_analysis, parent, env, false); + try!(writeln!(w, "{}{}::{}", tabs(2), par_mod, override_vfuncs_statement(&parent.name))); } try!(writeln!(w, "{}}}", tabs(1))); From 90582b70bde98c950ff50727b04ea843b46f6fbe Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 23 Jun 2018 21:42:27 +0200 Subject: [PATCH 100/122] alias imports from other subclass crates --- src/codegen/subclass/class_impl.rs | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 6dc69f1e4..43a1aede3 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -252,21 +252,29 @@ pub fn generate_exports( // )); } -fn subclass_parent_module_path(object: &analysis::object::Info, parent: &analysis::object::Info, env: &Env, include_crate: bool) -> String{ +fn subclass_parent_module_path(parent: &analysis::object::Info, object: &analysis::object::Info, env: &Env, for_use: bool) -> String{ let mut ns = "".to_string(); - if include_crate{ - if parent.type_id.ns_id != object.type_id.ns_id{ - let ns_name = &env.library.namespace(parent.type_id.ns_id).name; - ns = format!("{}_subclass::", ns_name.to_lowercase()).to_string(); - } - } - + let mut alias = "".to_string(); let obj = &env.config.objects[&parent.full_name]; let module_name = obj.module_name.clone().unwrap_or_else(|| { nameutil::module_name(nameutil::split_namespace_name(&parent.full_name).1) }); - format!("{}{}", ns, module_name) + + if parent.type_id.ns_id != object.type_id.ns_id{ + let ns_name = &env.library.namespace(parent.type_id.ns_id).name; + alias = format!("{}_{}", ns_name.to_lowercase(), module_name).to_string(); + + if for_use{ + ns = format!("{}_subclass::", ns_name.to_lowercase()).to_string(); + } + } + + if for_use{ + format!("{}{} as {}", ns, module_name, alias) + }else{ + format!("{}", alias) + } } pub fn generate_subclass_uses(w: &mut Write, @@ -667,7 +675,7 @@ fn generate_parent_impls( w, "unsafe impl {par_mod}::{par}ClassExt<{obj}> for {obj}Class {{}}", obj = object_analysis.name, - par_mod = subclass_parent_module_path(object_analysis, parent, env, false), + par_mod = subclass_parent_module_path(parent, object_analysis, env, false), par = parent.name )); } @@ -831,7 +839,7 @@ fn generate_impl_objecttype( try!(writeln!(w, "{}{}", tabs(2), override_vfuncs_statement(&"Object".to_string()))); try!(writeln!(w, "{}{}", tabs(2), override_vfuncs_statement(&object_analysis.name))); for parent in &subclass_info.get_parents(env) { - let par_mod = subclass_parent_module_path(object_analysis, parent, env, false); + let par_mod = subclass_parent_module_path(parent, object_analysis, env, false); try!(writeln!(w, "{}{}::{}", tabs(2), par_mod, override_vfuncs_statement(&parent.name))); } From 9f17014e5d6b4f358423097c2b6775d15c33aa6d Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 24 Jun 2018 10:06:55 +0200 Subject: [PATCH 101/122] skip InitiallyUnowned in glib_wrapper --- src/codegen/subclass/class_impl.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 43a1aede3..39ee70702 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -423,7 +423,7 @@ pub fn generate_base( let parent_impls: Vec = impls.iter() .map(|ref p| { - let ns_name = &env.namespaces[object_analysis.type_id.ns_id].crate_name; + let ns_name = &env.namespaces[p.type_id.ns_id].crate_name; format!("+ glib::IsA<{}::{}>", ns_name, p.name) }) .collect(); @@ -569,13 +569,19 @@ fn generate_glib_wrapper( for parent in &subclass_info.parents { let t = env.library.type_(parent.type_id); let k = &env.namespaces[parent.type_id.ns_id].crate_name; + + let tglib = t.get_glib_name(); + if tglib == Some("InitiallyUnowned"){ + continue; + } + try!(write!( w, "\n{tabs} {krate}::{ty} => {krate}_ffi::{cty},", tabs = tabs(2), krate = k, ty = t.get_name(), - cty = t.get_glib_name().unwrap() + cty = tglib.unwrap_or("") )); } From 22e33eb3450deacfd0c64d8d636ab3e210126190 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 24 Jun 2018 18:58:59 +0200 Subject: [PATCH 102/122] callback guard is now deprecated --- src/codegen/subclass/virtual_method_body_chunks.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index cd1a59af8..0d5106593 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -185,7 +185,6 @@ impl Builder { pub fn generate_interface_extern_c_func(&self, env: &Env) -> Chunk { let mut body = Vec::new(); - body.push(self.callback_guard()); body.push(self.floating_reference_guard("gptr")); body.push(Chunk::Let { From ef389c4ea9ead0b7bce1b872b9f678089427e6fc Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 24 Jun 2018 21:53:09 +0200 Subject: [PATCH 103/122] remove further occurances of callback_guard --- src/codegen/subclass/virtual_method_body_chunks.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index 0d5106593..ea0f865fc 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -149,7 +149,6 @@ impl Builder { pub fn generate_object_extern_c_func(&self, env: &Env) -> Chunk { let mut body = Vec::new(); - body.push(self.callback_guard()); body.push(self.floating_reference_guard("gptr")); body.push(Chunk::Let { @@ -245,10 +244,6 @@ impl Builder { Chunk::Chunks(body) } - fn callback_guard(&self) -> Chunk { - Chunk::Custom("callback_guard!();".to_owned()) - } - fn floating_reference_guard(&self, p: &str) -> Chunk { Chunk::Custom(format!("floating_reference_guard!({});", p).to_owned()) } @@ -288,7 +283,6 @@ impl Builder { let iface_name = format!("{}_iface", self.object_name.to_lowercase()).to_owned(); - body.push(self.callback_guard()); body.push(Chunk::Let { name: iface_name.clone(), is_mut: false, From 2618c707e78f1662c15bbb2fe7401d7f29bec1cf Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 25 Jun 2018 07:52:08 +0200 Subject: [PATCH 104/122] fix ignoring InitiallyUnowned --- src/codegen/subclass/class_impl.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 39ee70702..e95952482 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -570,8 +570,7 @@ fn generate_glib_wrapper( let t = env.library.type_(parent.type_id); let k = &env.namespaces[parent.type_id.ns_id].crate_name; - let tglib = t.get_glib_name(); - if tglib == Some("InitiallyUnowned"){ + if t.get_name() == "InitiallyUnowned"{ continue; } @@ -581,7 +580,7 @@ fn generate_glib_wrapper( tabs = tabs(2), krate = k, ty = t.get_name(), - cty = tglib.unwrap_or("") + cty = t.get_glib_name().unwrap_or("") )); } From e9c7687eb0f043f4e5492c98fecd48d159204ecb Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 27 Jun 2018 07:40:39 +0200 Subject: [PATCH 105/122] support optional types in trampoline parameters and improve lifetime of return values --- src/codegen/subclass/mod.rs | 1 + src/codegen/subclass/trampoline_from_glib.rs | 76 ++++++++++++++++++++ src/codegen/subclass/virtual_methods.rs | 6 +- src/codegen/trampoline_to_glib.rs | 27 ++++++- 4 files changed, 104 insertions(+), 6 deletions(-) create mode 100644 src/codegen/subclass/trampoline_from_glib.rs diff --git a/src/codegen/subclass/mod.rs b/src/codegen/subclass/mod.rs index e51dabb78..86a589814 100644 --- a/src/codegen/subclass/mod.rs +++ b/src/codegen/subclass/mod.rs @@ -10,6 +10,7 @@ mod class_impls; mod class_impl; mod virtual_methods; mod virtual_method_body_chunks; +mod trampoline_from_glib; use codegen::sys::statics as statics_ffi; use codegen::generate_single_version_file; diff --git a/src/codegen/subclass/trampoline_from_glib.rs b/src/codegen/subclass/trampoline_from_glib.rs new file mode 100644 index 000000000..88fd51a4e --- /dev/null +++ b/src/codegen/subclass/trampoline_from_glib.rs @@ -0,0 +1,76 @@ +use analysis::rust_type::rust_type; +use analysis::trampoline_parameters::Transformation; +use analysis::function_parameters::RustParameter; + +use env::Env; +use library; +use traits::*; + +pub trait TrampolineFromGlib { + fn trampoline_from_glib(&self, env: &Env, par: &RustParameter, need_downcast: bool) -> String; +} + +impl TrampolineFromGlib for Transformation { + fn trampoline_from_glib(&self, env: &Env, par: &RustParameter, need_downcast: bool) -> String { + use analysis::conversion_type::ConversionType::*; + let need_type_name = need_downcast || is_need_type_name(env, self.typ); + match self.conversion_type { + Direct => self.name.clone(), + Scalar => format!("from_glib({})", self.name), + Borrow | Pointer => { + let is_borrow = self.conversion_type == Borrow; + let (mut left, mut right) = from_glib_xxx(self.transfer, is_borrow); + + let type_prefix = if need_type_name { + format!("&{}::", rust_type(env, self.typ).into_string()) + }else{ + "".to_string() + }; + + if need_downcast { + right = format!("{}.downcast_unchecked()", right); + } + + if !par.allow_none{ + left = format!("&{}{}", type_prefix, left); + format!("{}{}{}", left, self.name, right) + + }else{ + left = format!("{}{}", type_prefix, left); + format!("(if {name}.is_null() {{ None }} else {{ Some({left}{name}{right}) }}).as_ref()", + name=self.name, + left=left, + right=right) + } + + + } + Unknown => format!("/*Unknown conversion*/{}", self.name), + } + } +} + +fn from_glib_xxx(transfer: library::Transfer, is_borrow: bool) -> (String, String) { + use library::Transfer::*; + match transfer { + None if is_borrow => ("from_glib_borrow(".into(), ")".into()), + None => ("from_glib_none(".into(), ")".into()), + Full => ("from_glib_full(".into(), ")".into()), + Container => ("from_glib_container(".into(), ")".into()), + } +} + +fn is_need_type_name(env: &Env, type_id: library::TypeId) -> bool { + if type_id.ns_id == library::INTERNAL_NAMESPACE { + use library::Type::*; + use library::Fundamental::*; + match *env.type_(type_id) { + Fundamental(fund) if fund == Utf8 => true, + Fundamental(fund) if fund == Filename => true, + Fundamental(fund) if fund == OsString => true, + _ => false, + } + } else { + false + } +} diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 3ccd27167..b08479ec2 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -24,7 +24,7 @@ use codegen::subclass::virtual_method_body_chunks::Builder; use codegen::sys::ffi_type::ffi_type; use codegen::function_body_chunk::{Parameter, ReturnValue}; use codegen::return_value::{ToReturnValue, out_parameter_as_return}; -use codegen::trampoline_from_glib::TrampolineFromGlib; +use codegen::subclass::trampoline_from_glib::TrampolineFromGlib; use codegen::trampoline_to_glib::TrampolineToGlib; pub fn generate_default_impl( @@ -729,7 +729,7 @@ fn trampoline_call_parameters(env: &Env, analysis: &analysis::virtual_methods::I let transformation = parameter_transformation(env, analysis, ind, par); - let par_str = transformation.trampoline_from_glib(env, false); + let par_str = transformation.trampoline_from_glib(env, par, false); parameter_strs.push(par_str); } @@ -738,7 +738,7 @@ fn trampoline_call_parameters(env: &Env, analysis: &analysis::virtual_methods::I fn trampoline_call_return(env: &Env, analysis: &analysis::virtual_methods::Info) -> (String, String) { match analysis.ret.parameter { - Some(ref param) => param.trampoline_to_glib_as_function(env), + Some(ref param) => param.trampoline_to_glib_as_function(env, Some(analysis)), None => (String::new(), String::new()) } } diff --git a/src/codegen/trampoline_to_glib.rs b/src/codegen/trampoline_to_glib.rs index 0cfd2c438..f4790def2 100644 --- a/src/codegen/trampoline_to_glib.rs +++ b/src/codegen/trampoline_to_glib.rs @@ -1,10 +1,11 @@ use analysis::conversion_type::ConversionType; +use analysis::virtual_methods; use library; use env; pub trait TrampolineToGlib { fn trampoline_to_glib(&self, env: &env::Env) -> String; - fn trampoline_to_glib_as_function(&self, env: &env::Env) -> (String, String); + fn trampoline_to_glib_as_function(&self, env: &env::Env, method: Option<&virtual_methods::Info>) -> (String, String); } impl TrampolineToGlib for library::Parameter { @@ -19,16 +20,36 @@ impl TrampolineToGlib for library::Parameter { } } - fn trampoline_to_glib_as_function(&self, env: &env::Env) -> (String, String){ + fn trampoline_to_glib_as_function(&self, env: &env::Env, method: Option<&virtual_methods::Info>) -> (String, String){ use analysis::conversion_type::ConversionType::*; match ConversionType::of(env, self.typ) { Direct => (String::new(), String::new()), Scalar => (String::new(), ".to_glib()".to_owned()), Pointer => { if *self.nullable{ + println!("trampoline {:?}", self); let mut_str = if self.transfer == library::Transfer::Full{ "_mut"} else {""}; let left = "match ".to_owned(); - let right = format!("{{ Some(t) => t{}, None => ptr::null{}()}}", to_glib_xxx(self.transfer), mut_str).to_owned(); + let right = (if self.transfer == library::Transfer::None { + format!(r#" + {{ + Some(t) => {{ + let ret = t{to_glib}; + gobject_ffi::g_object_set_qdata_full(gptr as *mut gobject_ffi::GObject, + glib_ffi::g_quark_from_string("rs_{method_name}".to_glib_none().0), + ret as *mut c_void, + None //TODO: how do we free the data + ); + ret + }}, + None => ptr::null{mut_str}() + }}"#, + method_name=method.map(|ref m| &m.name).unwrap_or(&"".to_string()), + to_glib=to_glib_xxx(self.transfer), + mut_str=mut_str) + } else{ + format!("{{ Some(t) => t{}, None => ptr::null{}()}}", to_glib_xxx(self.transfer), mut_str) + }).to_owned(); (left, right) }else{ From 630f04420a2155fdfc2d6bb44bba5280a468e5ce Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 1 Jul 2018 09:05:04 +0200 Subject: [PATCH 106/122] add basic support for default return values in base impl --- src/chunk/chunk.rs | 3 + src/chunk/parameter_ffi_call_out.rs | 3 + .../subclass/virtual_method_body_chunks.rs | 95 +++++++++++++++++-- src/writer/to_code.rs | 4 + 4 files changed, 96 insertions(+), 9 deletions(-) diff --git a/src/chunk/chunk.rs b/src/chunk/chunk.rs index a1525b019..f76c62687 100644 --- a/src/chunk/chunk.rs +++ b/src/chunk/chunk.rs @@ -75,6 +75,9 @@ pub enum Chunk { Closure{ arguments: Vec, body: Box, + }, + Deref{ + param: Box, } } diff --git a/src/chunk/parameter_ffi_call_out.rs b/src/chunk/parameter_ffi_call_out.rs index 1d543d166..ed50c17a1 100644 --- a/src/chunk/parameter_ffi_call_out.rs +++ b/src/chunk/parameter_ffi_call_out.rs @@ -8,6 +8,7 @@ pub struct Parameter { pub transfer: library::Transfer, pub caller_allocates: bool, pub is_error: bool, + pub nullable: library::Nullable } impl Parameter { @@ -18,6 +19,7 @@ impl Parameter { transfer: orig.transfer, caller_allocates: orig.caller_allocates, is_error: orig.is_error, + nullable: orig.nullable, } } } @@ -30,6 +32,7 @@ impl<'a> From<&'a library::Parameter> for Parameter { transfer: orig.transfer, caller_allocates: orig.caller_allocates, is_error: orig.is_error, + nullable: orig.nullable } } } diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index ea0f865fc..f2524152e 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -6,7 +6,8 @@ use analysis::functions::{find_index_to_ignore, AsyncTrampoline}; use analysis::namespaces; use analysis::out_parameters::Mode; use analysis::return_value; -use analysis::rust_type::rust_type; +use analysis::rust_type::{parameter_rust_type, rust_type}; +use analysis::ref_mode::RefMode; use analysis::safety_assertion_mode::SafetyAssertionMode; use chunk::parameter_ffi_call_out; use chunk::{Chunk, Param, TupleMode}; @@ -15,6 +16,7 @@ use env::Env; use library::{self, ParameterDirection}; use nameutil; use writer::ToCode; +use traits::IntoString; use codegen::function_body_chunk::{c_type_mem_mode, OutMemMode, Parameter, ReturnValue}; @@ -125,15 +127,23 @@ impl Builder { body.push(Chunk::Custom("(*parent_klass)".to_owned())); body.push(Chunk::Custom(format!(".{}", self.method_name).to_owned())); let mut args = Vec::new(); - args.push(self.base_impl_body_chunk()); + args.push(self.base_impl_body_chunk(env)); body.push(Chunk::Call { func_name: ".map".to_owned(), arguments: args, as_return: true, }); - //TODO: return variables? - body.push(Chunk::Custom(".unwrap_or(())".to_owned())); + let mut defaults = Vec::new(); + self.write_defaults(env, &mut defaults); + + body.push(Chunk::Call { + func_name: ".unwrap_or".to_owned(), + arguments: vec![Chunk::Tuple( + defaults, + TupleMode::WithUnit)], + as_return: true, + }); let unsafe_ = Chunk::Unsafe(body); @@ -248,7 +258,7 @@ impl Builder { Chunk::Custom(format!("floating_reference_guard!({});", p).to_owned()) } - fn base_impl_body_chunk(&self) -> Chunk { + fn base_impl_body_chunk(&self, env: &Env) -> Chunk { let mut body = Vec::new(); if self.outs_as_return { @@ -260,7 +270,7 @@ impl Builder { let call = self.generate_ffi_call(Some("f".to_owned())); let call = self.generate_ffi_call_conversion(call); - let ret = self.generate_out_return(); + let ret = self.generate_out_return(env); let (call, ret) = self.apply_outs_mode(call, ret); body.push(call); @@ -410,6 +420,55 @@ impl Builder { } } } + + fn write_defaults(&self, env: &Env, v: &mut Vec) { + if self.outs_as_return{ + let outs = self.get_outs(); + for par in outs { + if let Out { + ref parameter, + ref mem_mode, + } = *par + { + if *parameter.nullable{ + v.push(Chunk::Custom("None".to_owned())); + }else{ + use library::Type::*; + let type_ = env.library.type_(parameter.typ); + match *type_ { + Fundamental(_) => { + v.push(Chunk::Custom(format!("{}::default()", rust_type( + env, + parameter.typ + ).unwrap()))); + }, + _ => { + v.push(self.get_uninitialized(mem_mode)); + } + } + } + } + } + }else{ + if self.ret.ret.parameter.is_none(){ + return; + } + let ret = self.ret.ret.parameter.as_ref().unwrap(); + if *ret.nullable{ + v.push(Chunk::Custom("None".to_owned())) + }else{ + let rust_type = parameter_rust_type( + env, + ret.typ, + ret.direction, + ret.nullable, + RefMode::None, + ); + v.push(Chunk::Custom(format!("{}::default()", rust_type.into_string()).to_owned())) + } + } + } + fn get_uninitialized(&self, mem_mode: &OutMemMode) -> Chunk { use self::OutMemMode::*; match *mem_mode { @@ -487,7 +546,7 @@ impl Builder { .next() } - fn generate_out_return(&self) -> Option { + fn generate_out_return(&self, env: &Env) -> Option { if !self.outs_as_return { return None; } @@ -514,7 +573,7 @@ impl Builder { continue; } - chs.push(self.out_parameter_to_return(parameter, mem_mode)); + chs.push(self.out_parameter_to_return(env, parameter, mem_mode)); } } let chunk = Chunk::Tuple(chs, TupleMode::Auto); @@ -522,13 +581,31 @@ impl Builder { } fn out_parameter_to_return( &self, + env: &Env, parameter: ¶meter_ffi_call_out::Parameter, - mem_mode: &OutMemMode, + mem_mode: &OutMemMode ) -> Chunk { let value = Chunk::Custom(parameter.name.clone()); if let OutMemMode::UninitializedNamed(_) = *mem_mode { value } else { + let value = if let OutMemMode::Uninitialized = *mem_mode { + use library::Type::*; + let type_ = env.library.type_(parameter.typ); + match *type_ { + Fundamental(_) => { + Chunk::Deref{ + param: Box::new(value) + } + }, + _ => { + value + } + } + }else { + value + }; + Chunk::FromGlibConversion { mode: parameter.into(), array_length_name: self.find_array_length_name(¶meter.name), diff --git a/src/writer/to_code.rs b/src/writer/to_code.rs index a5657b150..2e516bc30 100644 --- a/src/writer/to_code.rs +++ b/src/writer/to_code.rs @@ -174,6 +174,10 @@ impl ToCode for Chunk { let code = format_block_one_line("{", "}", &body.to_code(env), " ", " "); vec![format!("{}{}", s, code)] } + Deref { ref param } => { + let mut code = format_block_smart("*", "", ¶m.to_code(env), "", ""); + code + } } } } From 2d6825987f3bb148f704dcb3cff7f3671b05542e Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 1 Jul 2018 12:43:22 +0200 Subject: [PATCH 107/122] implement destroy function for return parameter --- src/codegen/subclass/class_impl.rs | 2 +- src/codegen/subclass/virtual_methods.rs | 27 +++++++++++++++---------- src/codegen/trampoline_to_glib.rs | 23 +++++++++++++++------ 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index e95952482..557ed44ed 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -717,7 +717,7 @@ fn box_impl_name(env: &Env, analysis: &analysis::object::Info) -> String{ format!("box_{}_{}_impl", env.namespaces[analysis.type_id.ns_id].name.to_lowercase(), - analysis.name.to_lowercase()) + analysis.module_name(env).unwrap_or(analysis.name.to_lowercase())) } fn generate_box_impl( diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index b08479ec2..f50bc75fb 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -334,7 +334,7 @@ pub fn generate_override_vfuncs( for method_analysis in &object_analysis.virtual_methods { body_chunks.push(Chunk::Custom( format!("klass.{mname} = Some({cname}_{mname}::);", mname=method_analysis.name, - cname=object_analysis.name.to_lowercase()).to_owned() + cname=object_analysis.module_name(env).unwrap_or(object_analysis.name.to_lowercase())).to_owned() )); } @@ -427,7 +427,7 @@ pub fn generate_extern_c_func( try!(writeln!( w, "unsafe extern \"C\" fn {}_{}", - object_analysis.name.to_lowercase(), + object_analysis.module_name(env).unwrap_or(object_analysis.name.to_lowercase()), method_analysis.name, base_trait_name )); @@ -459,7 +459,7 @@ pub fn generate_extern_c_func( } let mut func_params = trampoline_call_parameters(env, method_analysis); - let func_ret = trampoline_call_return(env, method_analysis); + let func_ret = trampoline_call_return(env, object_analysis, method_analysis); func_params.insert(0, "&wrap".to_string()); try!(writeln!(w, "{}{}imp.{}({}){}", @@ -604,7 +604,7 @@ unsafe extern \"C\" fn {}_init( iface: glib_ffi::gpointer, iface_data: glib_ffi::gpointer ) {{", - object_analysis.name.to_lowercase() + object_analysis.module_name(env).unwrap_or(object_analysis.name.to_lowercase()) )); let mut builder = Builder::new(); @@ -641,7 +641,7 @@ pub fn register_{}>( type_: glib::Type, imp: &I, ) {{", - object_analysis.name.to_lowercase(), + object_analysis.module_name(env).unwrap_or(object_analysis.name.to_lowercase()), object_analysis.subclass_impl_trait_name )); @@ -668,7 +668,7 @@ pub fn register_{}>( ", iface=object_analysis.name, iface_impl=object_analysis.subclass_impl_trait_name, - iface_l=object_analysis.name.to_lowercase(), + iface_l=object_analysis.module_name(env).unwrap_or(object_analysis.name.to_lowercase()), ffi_crate=&env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name, get_type=object_analysis.get_type )); @@ -699,7 +699,7 @@ fn parameter_transformation(env: &Env, analysis: &analysis::virtual_methods::Inf TransformationType::ToGlibBorrow{..} => ConversionType::Borrow, TransformationType::ToGlibUnknown{..} => ConversionType::Unknown, TransformationType::ToGlibStash{..} => ConversionType::Unknown, - TransformationType::Into{..} => ConversionType::Pointer, + TransformationType::Into{..} => ConversionType::Borrow, TransformationType::Length{..} => ConversionType::Unknown, TransformationType::IntoRaw{..} => ConversionType::Pointer, TransformationType::ToSome{..} => ConversionType::Direct @@ -736,9 +736,14 @@ fn trampoline_call_parameters(env: &Env, analysis: &analysis::virtual_methods::I parameter_strs } -fn trampoline_call_return(env: &Env, analysis: &analysis::virtual_methods::Info) -> (String, String) { - match analysis.ret.parameter { - Some(ref param) => param.trampoline_to_glib_as_function(env, Some(analysis)), - None => (String::new(), String::new()) +fn trampoline_call_return(env: &Env, object: &analysis::object::Info, method: &analysis::virtual_methods::Info) -> (String, String) { + + let outs_as_return = !method.outs.is_empty(); + if(!outs_as_return){ + //TODO: convert params to output + } + match method.ret.parameter { + Some(ref param) => param.trampoline_to_glib_as_function(env, Some(object), Some(method)), + None => (String::new(), ";".to_string()) } } diff --git a/src/codegen/trampoline_to_glib.rs b/src/codegen/trampoline_to_glib.rs index f4790def2..00cef7427 100644 --- a/src/codegen/trampoline_to_glib.rs +++ b/src/codegen/trampoline_to_glib.rs @@ -1,11 +1,13 @@ use analysis::conversion_type::ConversionType; use analysis::virtual_methods; +use analysis::object; +use traits::IntoString; use library; use env; pub trait TrampolineToGlib { fn trampoline_to_glib(&self, env: &env::Env) -> String; - fn trampoline_to_glib_as_function(&self, env: &env::Env, method: Option<&virtual_methods::Info>) -> (String, String); + fn trampoline_to_glib_as_function(&self, env: &env::Env, object: Option<&object::Info>, method: Option<&virtual_methods::Info>) -> (String, String); } impl TrampolineToGlib for library::Parameter { @@ -20,8 +22,10 @@ impl TrampolineToGlib for library::Parameter { } } - fn trampoline_to_glib_as_function(&self, env: &env::Env, method: Option<&virtual_methods::Info>) -> (String, String){ + fn trampoline_to_glib_as_function(&self, env: &env::Env, object: Option<&object::Info>, method: Option<&virtual_methods::Info>) -> (String, String){ use analysis::conversion_type::ConversionType::*; + use codegen::sys::ffi_type::ffi_type; + use analysis::rust_type::rust_type; match ConversionType::of(env, self.typ) { Direct => (String::new(), String::new()), Scalar => (String::new(), ".to_glib()".to_owned()), @@ -35,20 +39,27 @@ impl TrampolineToGlib for library::Parameter { {{ Some(t) => {{ let ret = t{to_glib}; + unsafe extern "C" fn destroy_{ret_param}(p: glib_ffi::gpointer){{ + {rust_type}::from_glib_full(p as {c_type}); + }}; gobject_ffi::g_object_set_qdata_full(gptr as *mut gobject_ffi::GObject, - glib_ffi::g_quark_from_string("rs_{method_name}".to_glib_none().0), + glib_ffi::g_quark_from_string("rs_{object_name}_{method_name}".to_glib_none().0), ret as *mut c_void, - None //TODO: how do we free the data + Some(destroy_{ret_param}) ); ret }}, None => ptr::null{mut_str}() }}"#, + object_name=object.map(|ref o| o.module_name(env).unwrap_or(o.name.to_lowercase())).unwrap_or("".to_string()), method_name=method.map(|ref m| &m.name).unwrap_or(&"".to_string()), to_glib=to_glib_xxx(self.transfer), - mut_str=mut_str) + mut_str=mut_str, + ret_param="ret", + rust_type=rust_type(env, self.typ).into_string(), + c_type= ffi_type(env, self.typ, &self.c_type).into_string()) } else{ - format!("{{ Some(t) => t{}, None => ptr::null{}()}}", to_glib_xxx(self.transfer), mut_str) + format!("{{ Some(t) => t{}, None => ptr::null{}()}}", to_glib_xxx(self.transfer), mut_str) }).to_owned(); (left, right) From 27f18dfea9e17c4214b413960bff007b27570115 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 1 Jul 2018 12:49:13 +0200 Subject: [PATCH 108/122] transfer full ownership of return types --- src/codegen/trampoline_to_glib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/codegen/trampoline_to_glib.rs b/src/codegen/trampoline_to_glib.rs index 00cef7427..63e801173 100644 --- a/src/codegen/trampoline_to_glib.rs +++ b/src/codegen/trampoline_to_glib.rs @@ -53,7 +53,11 @@ impl TrampolineToGlib for library::Parameter { }}"#, object_name=object.map(|ref o| o.module_name(env).unwrap_or(o.name.to_lowercase())).unwrap_or("".to_string()), method_name=method.map(|ref m| &m.name).unwrap_or(&"".to_string()), - to_glib=to_glib_xxx(self.transfer), + to_glib=to_glib_xxx( if self.transfer == library::Transfer::None { + library::Transfer::Full + }else{ + self.transfer + }), mut_str=mut_str, ret_param="ret", rust_type=rust_type(env, self.typ).into_string(), From 3b75fcc78547f3c75435fece84d9658bd5f54c66 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 2 Jul 2018 07:48:21 +0200 Subject: [PATCH 109/122] fix mutability of trampoline return types --- src/codegen/subclass/trampoline_from_glib.rs | 13 +++++++++---- src/codegen/trampoline_to_glib.rs | 6 ++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/codegen/subclass/trampoline_from_glib.rs b/src/codegen/subclass/trampoline_from_glib.rs index 88fd51a4e..5f91dc77c 100644 --- a/src/codegen/subclass/trampoline_from_glib.rs +++ b/src/codegen/subclass/trampoline_from_glib.rs @@ -1,6 +1,7 @@ use analysis::rust_type::rust_type; use analysis::trampoline_parameters::Transformation; use analysis::function_parameters::RustParameter; +use analysis::ref_mode::RefMode; use env::Env; use library; @@ -21,8 +22,10 @@ impl TrampolineFromGlib for Transformation { let is_borrow = self.conversion_type == Borrow; let (mut left, mut right) = from_glib_xxx(self.transfer, is_borrow); + let mut_str = if self.ref_mode == RefMode::ByRefMut{ "mut " } else {""}; + let type_prefix = if need_type_name { - format!("&{}::", rust_type(env, self.typ).into_string()) + format!("{}{}::", mut_str, rust_type(env, self.typ).into_string()) }else{ "".to_string() }; @@ -32,15 +35,17 @@ impl TrampolineFromGlib for Transformation { } if !par.allow_none{ - left = format!("&{}{}", type_prefix, left); + left = format!("&{}{}{}", mut_str, type_prefix, left); format!("{}{}{}", left, self.name, right) }else{ left = format!("{}{}", type_prefix, left); - format!("(if {name}.is_null() {{ None }} else {{ Some({left}{name}{right}) }}).as_ref()", + let ref_mode = if self.ref_mode == RefMode::ByRefMut{ "as_mut()" } else {"as_ref()"}; + format!("(if {name}.is_null() {{ None }} else {{ Some({left}{name}{right}) }}).{ref_mode}", name=self.name, left=left, - right=right) + right=right, + ref_mode=ref_mode) } diff --git a/src/codegen/trampoline_to_glib.rs b/src/codegen/trampoline_to_glib.rs index 63e801173..cfdfe8a0d 100644 --- a/src/codegen/trampoline_to_glib.rs +++ b/src/codegen/trampoline_to_glib.rs @@ -26,13 +26,15 @@ impl TrampolineToGlib for library::Parameter { use analysis::conversion_type::ConversionType::*; use codegen::sys::ffi_type::ffi_type; use analysis::rust_type::rust_type; + + // TODO: handle out parameters match ConversionType::of(env, self.typ) { Direct => (String::new(), String::new()), Scalar => (String::new(), ".to_glib()".to_owned()), Pointer => { if *self.nullable{ - println!("trampoline {:?}", self); - let mut_str = if self.transfer == library::Transfer::Full{ "_mut"} else {""}; + // FIXME: isn't there any other way to know if we need to return a mutable ptr? + let mut_str = if self.c_type.starts_with("const ") {""} else {"_mut"}; let left = "match ".to_owned(); let right = (if self.transfer == library::Transfer::None { format!(r#" From bc71b370362cd2b206449d49f0d49119cdf4f6d3 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 2 Jul 2018 08:14:31 +0200 Subject: [PATCH 110/122] remove 'into' conversions in base impl --- src/codegen/subclass/virtual_method_body_chunks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index f2524152e..367b5f04a 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -149,7 +149,7 @@ impl Builder { let mut chunks = Vec::new(); - self.add_into_conversion(&mut chunks); + // self.add_into_conversion(&mut chunks); // self.add_assertion(&mut chunks); chunks.push(unsafe_); From 4f6ee90571d5acee8f874527ce009909cd649117 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 3 Jul 2018 12:32:03 +0200 Subject: [PATCH 111/122] remove insertion of fixme --- src/codegen/subclass/class_impl.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 557ed44ed..2b9a5326b 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -659,7 +659,6 @@ fn generate_parent_impls( try!(writeln!(w)); let parents = subclass_info.get_parents(env); - writeln!(w, "// FIXME: Boilerplate"); try!(writeln!( w, From 7980ecee2183e21e9a42d44eeb8a8e1c6a4982b5 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 3 Jul 2018 12:58:02 +0200 Subject: [PATCH 112/122] remove another FIXME --- src/codegen/subclass/class_impl.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index 2b9a5326b..d3ddeff1e 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -696,7 +696,6 @@ fn generate_interface_impls( ) -> Result<()> { try!(writeln!(w)); - writeln!(w, "// FIXME: Boilerplate"); if subclass_info.parents.len() > 0 { for parent in &subclass_info.parents { let t = env.library.type_(parent.type_id); From c7faed3590e616e15e95dd0761defb221fb0271c Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 4 Jul 2018 09:23:06 +0200 Subject: [PATCH 113/122] write output parameters back to pointers --- src/codegen/subclass/mod.rs | 1 + src/codegen/subclass/trampoline_to_glib.rs | 88 ++++++++++++++++++++++ src/codegen/subclass/virtual_methods.rs | 61 ++++++++++++--- src/codegen/trampoline_to_glib.rs | 59 --------------- 4 files changed, 141 insertions(+), 68 deletions(-) create mode 100644 src/codegen/subclass/trampoline_to_glib.rs diff --git a/src/codegen/subclass/mod.rs b/src/codegen/subclass/mod.rs index 86a589814..ad336dca5 100644 --- a/src/codegen/subclass/mod.rs +++ b/src/codegen/subclass/mod.rs @@ -11,6 +11,7 @@ mod class_impl; mod virtual_methods; mod virtual_method_body_chunks; mod trampoline_from_glib; +mod trampoline_to_glib; use codegen::sys::statics as statics_ffi; use codegen::generate_single_version_file; diff --git a/src/codegen/subclass/trampoline_to_glib.rs b/src/codegen/subclass/trampoline_to_glib.rs new file mode 100644 index 000000000..f150d1850 --- /dev/null +++ b/src/codegen/subclass/trampoline_to_glib.rs @@ -0,0 +1,88 @@ +use analysis::conversion_type::ConversionType; +use analysis::object; +use analysis::virtual_methods; +use codegen::trampoline_to_glib::TrampolineToGlib; +use env; +use library; +use traits::IntoString; + +pub fn trampoline_to_glib( + parameter: &library::Parameter, + env: &env::Env, + object: &object::Info, + method: &virtual_methods::Info, +) -> String { + use analysis::conversion_type::ConversionType::*; + use analysis::rust_type::rust_type; + use codegen::sys::ffi_type::ffi_type; + + let param_name = if parameter.name.len() > 0 { parameter.name.clone() } else {"ret".to_string()}; + + // TODO: handle out parameters + match ConversionType::of(env, parameter.typ) { + Direct => format!("rs_{}{}", param_name, parameter.trampoline_to_glib(env)), + Scalar => format!("rs_{}{}", param_name, parameter.trampoline_to_glib(env)), + Pointer => { + if *parameter.nullable { + + // FIXME: isn't there any other way to know if we need to return a mutable ptr? + let mut_str = if parameter.c_type.starts_with("const ") { + "" + } else { + "_mut" + }; + let right = (if parameter.transfer == library::Transfer::None { + format!(r#" + match rs_{param_name} {{ + Some(t_{param_name}) => {{ + let ret = t_{param_name}{to_glib}; + unsafe extern "C" fn destroy_{param_name}(p: glib_ffi::gpointer){{ + {rust_type}::from_glib_full(p as {c_type}); + }}; + gobject_ffi::g_object_set_qdata_full(gptr as *mut gobject_ffi::GObject, + glib_ffi::g_quark_from_string("rs_{object_name}_{method_name}_{param_name}".to_glib_none().0), + ret as *mut c_void, + Some(destroy_{param_name}) + ); + ret + }}, + None => ptr::null{mut_str}() + }}"#, + object_name=object.module_name(env).unwrap_or(object.name.to_lowercase()), + method_name=method.name, + to_glib=to_glib_xxx( if parameter.transfer == library::Transfer::None { + library::Transfer::Full + }else{ + parameter.transfer + }), + mut_str=mut_str, + param_name=param_name, + rust_type=rust_type(env, parameter.typ).into_string(), + c_type= ffi_type(env, parameter.typ, ¶meter.c_type).into_string()) + } else { + format!( + "match rs_{param_name} {{ Some(t_{param_name}) => t_{param_name}{to_glib}, None => ptr::null{mut_str}()}}", + param_name=param_name, + to_glib=parameter.trampoline_to_glib(env), + mut_str=mut_str + ) + }).to_owned(); + + right + } else { + format!("rs_{}{}", param_name, parameter.trampoline_to_glib(env)) + } + } + Borrow => format!("rs_{}{}", param_name, parameter.trampoline_to_glib(env)), + Unknown => format!("rs_{}{}", param_name, parameter.trampoline_to_glib(env)), + } +} + +fn to_glib_xxx(transfer: library::Transfer) -> &'static str { + use library::Transfer::*; + match transfer { + None => "/*Not checked*/.to_glib_none().0", + Full => ".to_glib_full()", + Container => "/*Not checked*/.to_glib_container().0", + } +} diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index f50bc75fb..cf70682ab 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -25,7 +25,6 @@ use codegen::sys::ffi_type::ffi_type; use codegen::function_body_chunk::{Parameter, ReturnValue}; use codegen::return_value::{ToReturnValue, out_parameter_as_return}; use codegen::subclass::trampoline_from_glib::TrampolineFromGlib; -use codegen::trampoline_to_glib::TrampolineToGlib; pub fn generate_default_impl( w: &mut Write, @@ -462,12 +461,17 @@ pub fn generate_extern_c_func( let func_ret = trampoline_call_return(env, object_analysis, method_analysis); func_params.insert(0, "&wrap".to_string()); - try!(writeln!(w, "{}{}imp.{}({}){}", + try!(writeln!(w, "{}{}imp.{}({});", tabs(indent+1), func_ret.0, &method_analysis.name, - func_params.join(", "), - func_ret.1)); + func_params.join(", "))); + + for line in func_ret.1{ + try!(writeln!(w, "{}{}", + tabs(indent+1), + line)); + } try!(writeln!( w, @@ -736,14 +740,53 @@ fn trampoline_call_parameters(env: &Env, analysis: &analysis::virtual_methods::I parameter_strs } -fn trampoline_call_return(env: &Env, object: &analysis::object::Info, method: &analysis::virtual_methods::Info) -> (String, String) { +fn trampoline_call_return(env: &Env, object: &analysis::object::Info, method: &analysis::virtual_methods::Info) -> (String, Vec) { + use codegen::subclass::trampoline_to_glib::trampoline_to_glib; + + let mut left = String::new(); + let mut right: Vec = vec![]; + + let retvar_name = "rs_ret".to_string(); + let mut retvar = retvar_name.clone(); let outs_as_return = !method.outs.is_empty(); - if(!outs_as_return){ - //TODO: convert params to output + if outs_as_return { + + let mut param_names: Vec = if method.ret.parameter.is_some() { vec![retvar_name.clone()] } else {vec![]}; + param_names.append(&mut (&method.outs.params).into_iter().map(|ref p| format!("rs_{}", p.name).to_string()).collect()); + + retvar = format!("({})", param_names.join(", ")).to_string(); + + + for param in &method.outs.params{ + right.push(format!("std::ptr::write({}, {});", param.name, trampoline_to_glib(param, env, object, method)).to_string()); + } } match method.ret.parameter { - Some(ref param) => param.trampoline_to_glib_as_function(env, Some(object), Some(method)), - None => (String::new(), ";".to_string()) + Some(ref param) => { + right.push(trampoline_to_glib(param, env, object, method)); + }, + None => {} + } + + if method.ret.parameter.is_some() || outs_as_return{ + left = format!("let {} = ", retvar).to_string(); } + + (left, right) } + + +// fn trampoline_call_output_params(env: &Env, object: &analysis::object::Info, method: &analysis::virtual_methods::Info) -> (String, String) { +// +// // TODO: support both return value and output parameters +// for param in method.outs.params{ +// param.trampoline_to_glib_as_function(env, Some(object), Some(method)); +// } +// +// // let (rs_minimum_width, rs_natural_width) = imp.get_preferred_width_for_height(&wrap, &from_glib_none(widget), height); +// // std::ptr::write(minimum_width, rs_minimum_width); +// // std::ptr::write(natural_width, rs_natural_width); +// +// +// } diff --git a/src/codegen/trampoline_to_glib.rs b/src/codegen/trampoline_to_glib.rs index cfdfe8a0d..065786a67 100644 --- a/src/codegen/trampoline_to_glib.rs +++ b/src/codegen/trampoline_to_glib.rs @@ -1,13 +1,10 @@ use analysis::conversion_type::ConversionType; -use analysis::virtual_methods; -use analysis::object; use traits::IntoString; use library; use env; pub trait TrampolineToGlib { fn trampoline_to_glib(&self, env: &env::Env) -> String; - fn trampoline_to_glib_as_function(&self, env: &env::Env, object: Option<&object::Info>, method: Option<&virtual_methods::Info>) -> (String, String); } impl TrampolineToGlib for library::Parameter { @@ -21,62 +18,6 @@ impl TrampolineToGlib for library::Parameter { Unknown => "/*Unknown conversion*/".to_owned(), } } - - fn trampoline_to_glib_as_function(&self, env: &env::Env, object: Option<&object::Info>, method: Option<&virtual_methods::Info>) -> (String, String){ - use analysis::conversion_type::ConversionType::*; - use codegen::sys::ffi_type::ffi_type; - use analysis::rust_type::rust_type; - - // TODO: handle out parameters - match ConversionType::of(env, self.typ) { - Direct => (String::new(), String::new()), - Scalar => (String::new(), ".to_glib()".to_owned()), - Pointer => { - if *self.nullable{ - // FIXME: isn't there any other way to know if we need to return a mutable ptr? - let mut_str = if self.c_type.starts_with("const ") {""} else {"_mut"}; - let left = "match ".to_owned(); - let right = (if self.transfer == library::Transfer::None { - format!(r#" - {{ - Some(t) => {{ - let ret = t{to_glib}; - unsafe extern "C" fn destroy_{ret_param}(p: glib_ffi::gpointer){{ - {rust_type}::from_glib_full(p as {c_type}); - }}; - gobject_ffi::g_object_set_qdata_full(gptr as *mut gobject_ffi::GObject, - glib_ffi::g_quark_from_string("rs_{object_name}_{method_name}".to_glib_none().0), - ret as *mut c_void, - Some(destroy_{ret_param}) - ); - ret - }}, - None => ptr::null{mut_str}() - }}"#, - object_name=object.map(|ref o| o.module_name(env).unwrap_or(o.name.to_lowercase())).unwrap_or("".to_string()), - method_name=method.map(|ref m| &m.name).unwrap_or(&"".to_string()), - to_glib=to_glib_xxx( if self.transfer == library::Transfer::None { - library::Transfer::Full - }else{ - self.transfer - }), - mut_str=mut_str, - ret_param="ret", - rust_type=rust_type(env, self.typ).into_string(), - c_type= ffi_type(env, self.typ, &self.c_type).into_string()) - } else{ - format!("{{ Some(t) => t{}, None => ptr::null{}()}}", to_glib_xxx(self.transfer), mut_str) - }).to_owned(); - - (left, right) - }else{ - (String::new(), to_glib_xxx(self.transfer).to_owned()) - } - } - Borrow => (String::new(), "/*Not applicable conversion Borrow*/".to_owned()), - Unknown => (String::new(), "/*Unknown conversion*/".to_owned()), - } - } } fn to_glib_xxx(transfer: library::Transfer) -> &'static str { From b7c2a7fb93590142bf50663210f6d898849c620f Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 4 Jul 2018 10:26:40 +0200 Subject: [PATCH 114/122] omit brackets when there's only one output variable --- src/codegen/subclass/virtual_methods.rs | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index cf70682ab..7d675b1f5 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -755,8 +755,12 @@ fn trampoline_call_return(env: &Env, object: &analysis::object::Info, method: &a let mut param_names: Vec = if method.ret.parameter.is_some() { vec![retvar_name.clone()] } else {vec![]}; param_names.append(&mut (&method.outs.params).into_iter().map(|ref p| format!("rs_{}", p.name).to_string()).collect()); - retvar = format!("({})", param_names.join(", ")).to_string(); - + let param_name_list = param_names.join(", "); + if param_names.len() > 1{ + retvar = format!("({})", param_name_list).to_string(); + }else{ + retvar = param_name_list; + } for param in &method.outs.params{ right.push(format!("std::ptr::write({}, {});", param.name, trampoline_to_glib(param, env, object, method)).to_string()); @@ -775,18 +779,3 @@ fn trampoline_call_return(env: &Env, object: &analysis::object::Info, method: &a (left, right) } - - -// fn trampoline_call_output_params(env: &Env, object: &analysis::object::Info, method: &analysis::virtual_methods::Info) -> (String, String) { -// -// // TODO: support both return value and output parameters -// for param in method.outs.params{ -// param.trampoline_to_glib_as_function(env, Some(object), Some(method)); -// } -// -// // let (rs_minimum_width, rs_natural_width) = imp.get_preferred_width_for_height(&wrap, &from_glib_none(widget), height); -// // std::ptr::write(minimum_width, rs_minimum_width); -// // std::ptr::write(natural_width, rs_natural_width); -// -// -// } From e7f334463b20d50d1c00d7a76ed114506df3bac3 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 4 Jul 2018 20:20:07 +0200 Subject: [PATCH 115/122] also store non-nullable pointers --- src/codegen/subclass/trampoline_to_glib.rs | 62 +++++++++++++--------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/src/codegen/subclass/trampoline_to_glib.rs b/src/codegen/subclass/trampoline_to_glib.rs index f150d1850..cdce4f55a 100644 --- a/src/codegen/subclass/trampoline_to_glib.rs +++ b/src/codegen/subclass/trampoline_to_glib.rs @@ -13,12 +13,9 @@ pub fn trampoline_to_glib( method: &virtual_methods::Info, ) -> String { use analysis::conversion_type::ConversionType::*; - use analysis::rust_type::rust_type; - use codegen::sys::ffi_type::ffi_type; let param_name = if parameter.name.len() > 0 { parameter.name.clone() } else {"ret".to_string()}; - // TODO: handle out parameters match ConversionType::of(env, parameter.typ) { Direct => format!("rs_{}{}", param_name, parameter.trampoline_to_glib(env)), Scalar => format!("rs_{}{}", param_name, parameter.trampoline_to_glib(env)), @@ -34,31 +31,12 @@ pub fn trampoline_to_glib( let right = (if parameter.transfer == library::Transfer::None { format!(r#" match rs_{param_name} {{ - Some(t_{param_name}) => {{ - let ret = t_{param_name}{to_glib}; - unsafe extern "C" fn destroy_{param_name}(p: glib_ffi::gpointer){{ - {rust_type}::from_glib_full(p as {c_type}); - }}; - gobject_ffi::g_object_set_qdata_full(gptr as *mut gobject_ffi::GObject, - glib_ffi::g_quark_from_string("rs_{object_name}_{method_name}_{param_name}".to_glib_none().0), - ret as *mut c_void, - Some(destroy_{param_name}) - ); - ret - }}, + Some(t_{param_name}) => {to_glib_destroy}, None => ptr::null{mut_str}() }}"#, - object_name=object.module_name(env).unwrap_or(object.name.to_lowercase()), - method_name=method.name, - to_glib=to_glib_xxx( if parameter.transfer == library::Transfer::None { - library::Transfer::Full - }else{ - parameter.transfer - }), + to_glib_destroy=to_glib_with_destroy(parameter, env, object, method, ¶m_name), mut_str=mut_str, - param_name=param_name, - rust_type=rust_type(env, parameter.typ).into_string(), - c_type= ffi_type(env, parameter.typ, ¶meter.c_type).into_string()) + param_name=param_name) } else { format!( "match rs_{param_name} {{ Some(t_{param_name}) => t_{param_name}{to_glib}, None => ptr::null{mut_str}()}}", @@ -70,7 +48,7 @@ pub fn trampoline_to_glib( right } else { - format!("rs_{}{}", param_name, parameter.trampoline_to_glib(env)) + to_glib_with_destroy(parameter, env, object, method, ¶m_name).to_owned() } } Borrow => format!("rs_{}{}", param_name, parameter.trampoline_to_glib(env)), @@ -78,6 +56,38 @@ pub fn trampoline_to_glib( } } +fn to_glib_with_destroy(parameter: &library::Parameter, + env: &env::Env, + object: &object::Info, + method: &virtual_methods::Info, + param_name: &String) -> String { + use analysis::rust_type::rust_type; + use codegen::sys::ffi_type::ffi_type; + + format!(r#"{{ + let ret = t_{param_name}{to_glib}; + unsafe extern "C" fn destroy_{param_name}(p: glib_ffi::gpointer){{ + {rust_type}::from_glib_full(p as {c_type}); + }}; + gobject_ffi::g_object_set_qdata_full(gptr as *mut gobject_ffi::GObject, + glib_ffi::g_quark_from_string("rs_{object_name}_{method_name}_{param_name}".to_glib_none().0), + ret as *mut c_void, + Some(destroy_{param_name}) + ); + ret + }}"#, + object_name=object.module_name(env).unwrap_or(object.name.to_lowercase()), + method_name=method.name, + to_glib=to_glib_xxx( if parameter.transfer == library::Transfer::None { + library::Transfer::Full + }else{ + parameter.transfer + }), + param_name=param_name, + rust_type=rust_type(env, parameter.typ).into_string(), + c_type= ffi_type(env, parameter.typ, ¶meter.c_type).into_string()) +} + fn to_glib_xxx(transfer: library::Transfer) -> &'static str { use library::Transfer::*; match transfer { From 18f411e5b9a0c3379290c3936bf9cba9d364688f Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 4 Jul 2018 21:44:50 +0200 Subject: [PATCH 116/122] fix some variable name vs module name confusion --- src/codegen/subclass/class_impl.rs | 6 +++++- src/codegen/subclass/virtual_method_body_chunks.rs | 10 ++++++++-- src/codegen/subclass/virtual_methods.rs | 6 ++++-- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index d3ddeff1e..43840a8ee 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -271,7 +271,11 @@ fn subclass_parent_module_path(parent: &analysis::object::Info, object: &analysi } if for_use{ - format!("{}{} as {}", ns, module_name, alias) + if alias.len() > 0 { + format!("{}{} as {}", ns, module_name, alias) + }else{ + format!("{}{}", ns, module_name) + } }else{ format!("{}", alias) } diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index 367b5f04a..ba4cefc40 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -23,6 +23,7 @@ use codegen::function_body_chunk::{c_type_mem_mode, OutMemMode, Parameter, Retur #[derive(Default)] pub struct Builder { object_name: String, + module_name: String, object_class_c_type: String, object_c_type: String, ffi_crate_name: String, @@ -47,6 +48,11 @@ impl Builder { self } + pub fn module_name(&mut self, name: &str) -> &mut Builder { + self.module_name = name.into(); + self + } + pub fn glib_name(&mut self, name: &str) -> &mut Builder { self.glib_name = name.into(); self @@ -291,7 +297,7 @@ impl Builder { ) -> Chunk { let mut body = Vec::new(); - let iface_name = format!("{}_iface", self.object_name.to_lowercase()).to_owned(); + let iface_name = format!("{}_iface", self.module_name).to_owned(); body.push(Chunk::Let { name: iface_name.clone(), @@ -349,7 +355,7 @@ impl Builder { "{iface}.{mname} = Some({obj}_{mname}::);", mname = method_analysis.name, iface = iface_name, - obj = self.object_name.to_lowercase() + obj = self.module_name ).to_owned(), )); } diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 7d675b1f5..0c34542e4 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -492,6 +492,7 @@ pub fn body_chunk_builder(env: &Env, let outs_as_return = !method_analysis.outs.is_empty(); builder.object_name(&object_analysis.name) + .module_name(&object_analysis.module_name(env).unwrap_or(object_analysis.name.to_lowercase())) .object_class_c_type(object_analysis.c_class_type.as_ref().unwrap()) .ffi_crate_name(&env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name) .glib_name(&method_analysis.glib_name) @@ -614,6 +615,7 @@ unsafe extern \"C\" fn {}_init( let mut builder = Builder::new(); builder.object_name(&object_analysis.name) + .module_name(&object_analysis.module_name(env).unwrap_or(object_analysis.name.to_lowercase())) .object_c_type(&object_analysis.c_type) .ffi_crate_name(&env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name); @@ -645,7 +647,7 @@ pub fn register_{}>( type_: glib::Type, imp: &I, ) {{", - object_analysis.module_name(env).unwrap_or(object_analysis.name.to_lowercase()), + object_analysis.name, object_analysis.subclass_impl_trait_name )); @@ -763,7 +765,7 @@ fn trampoline_call_return(env: &Env, object: &analysis::object::Info, method: &a } for param in &method.outs.params{ - right.push(format!("std::ptr::write({}, {});", param.name, trampoline_to_glib(param, env, object, method)).to_string()); + right.push(format!("ptr::write({}, {});", param.name, trampoline_to_glib(param, env, object, method)).to_string()); } } match method.ret.parameter { From d7f5bbd5b412536129fc8c31c032364d7019a7be Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 5 Jul 2018 00:00:26 +0200 Subject: [PATCH 117/122] fix c type of inout params --- src/codegen/subclass/trampoline_to_glib.rs | 7 ++++++- src/codegen/subclass/virtual_methods.rs | 8 ++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/codegen/subclass/trampoline_to_glib.rs b/src/codegen/subclass/trampoline_to_glib.rs index cdce4f55a..48595bd48 100644 --- a/src/codegen/subclass/trampoline_to_glib.rs +++ b/src/codegen/subclass/trampoline_to_glib.rs @@ -64,6 +64,11 @@ fn to_glib_with_destroy(parameter: &library::Parameter, use analysis::rust_type::rust_type; use codegen::sys::ffi_type::ffi_type; + let type_ = &env.library.type_(parameter.typ); + // TODO: way too ugly + let c_type = type_.get_glib_name().map(|c| format!("{}*", c)).unwrap_or(parameter.c_type.clone()); + + format!(r#"{{ let ret = t_{param_name}{to_glib}; unsafe extern "C" fn destroy_{param_name}(p: glib_ffi::gpointer){{ @@ -85,7 +90,7 @@ fn to_glib_with_destroy(parameter: &library::Parameter, }), param_name=param_name, rust_type=rust_type(env, parameter.typ).into_string(), - c_type= ffi_type(env, parameter.typ, ¶meter.c_type).into_string()) + c_type=ffi_type(env, parameter.typ, &c_type).into_string()) } fn to_glib_xxx(transfer: library::Transfer) -> &'static str { diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 0c34542e4..0098b7e45 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -647,7 +647,7 @@ pub fn register_{}>( type_: glib::Type, imp: &I, ) {{", - object_analysis.name, + object_analysis.module_name(env).unwrap_or(object_analysis.name.to_lowercase()), object_analysis.subclass_impl_trait_name )); @@ -765,7 +765,11 @@ fn trampoline_call_return(env: &Env, object: &analysis::object::Info, method: &a } for param in &method.outs.params{ - right.push(format!("ptr::write({}, {});", param.name, trampoline_to_glib(param, env, object, method)).to_string()); + right.append(&mut vec![ + format!("if !{}.is_null() {{", param.name).to_string(), + format!("{}ptr::write({}, {});", tabs(1), param.name, trampoline_to_glib(param, env, object, method)).to_string(), + "}".to_string() + ]); } } match method.ret.parameter { From 44b1509e318dd472724c28bab1850a29aa3191e6 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 5 Jul 2018 00:56:08 +0200 Subject: [PATCH 118/122] fix optionality of output params vs arrays --- src/codegen/subclass/trampoline_to_glib.rs | 23 +++++++++++---- src/codegen/subclass/virtual_methods.rs | 34 ++++++++++++++++------ 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/codegen/subclass/trampoline_to_glib.rs b/src/codegen/subclass/trampoline_to_glib.rs index 48595bd48..1ee386200 100644 --- a/src/codegen/subclass/trampoline_to_glib.rs +++ b/src/codegen/subclass/trampoline_to_glib.rs @@ -20,7 +20,18 @@ pub fn trampoline_to_glib( Direct => format!("rs_{}{}", param_name, parameter.trampoline_to_glib(env)), Scalar => format!("rs_{}{}", param_name, parameter.trampoline_to_glib(env)), Pointer => { - if *parameter.nullable { + let type_ = env.library.type_(parameter.typ); + let is_array_type = match type_ { + library::Type::Array(..) | + library::Type::CArray(..) | + library::Type::PtrArray(..) | + library::Type::List(..) | + library::Type::SList(..) | + library::Type::FixedArray(..) | + library::Type::HashTable(..) => true, + _ => false + }; + if *parameter.nullable && !is_array_type{ // FIXME: isn't there any other way to know if we need to return a mutable ptr? let mut_str = if parameter.c_type.starts_with("const ") { @@ -34,7 +45,7 @@ pub fn trampoline_to_glib( Some(t_{param_name}) => {to_glib_destroy}, None => ptr::null{mut_str}() }}"#, - to_glib_destroy=to_glib_with_destroy(parameter, env, object, method, ¶m_name), + to_glib_destroy=to_glib_with_destroy(parameter, env, object, method, ¶m_name, &"t_".to_string()), mut_str=mut_str, param_name=param_name) } else { @@ -48,7 +59,7 @@ pub fn trampoline_to_glib( right } else { - to_glib_with_destroy(parameter, env, object, method, ¶m_name).to_owned() + to_glib_with_destroy(parameter, env, object, method, ¶m_name, &"rs_".to_string()).to_owned() } } Borrow => format!("rs_{}{}", param_name, parameter.trampoline_to_glib(env)), @@ -60,7 +71,8 @@ fn to_glib_with_destroy(parameter: &library::Parameter, env: &env::Env, object: &object::Info, method: &virtual_methods::Info, - param_name: &String) -> String { + param_name: &String, + param_prefix: &String) -> String { use analysis::rust_type::rust_type; use codegen::sys::ffi_type::ffi_type; @@ -70,7 +82,7 @@ fn to_glib_with_destroy(parameter: &library::Parameter, format!(r#"{{ - let ret = t_{param_name}{to_glib}; + let ret = {param_prefix}{param_name}{to_glib}; unsafe extern "C" fn destroy_{param_name}(p: glib_ffi::gpointer){{ {rust_type}::from_glib_full(p as {c_type}); }}; @@ -89,6 +101,7 @@ fn to_glib_with_destroy(parameter: &library::Parameter, parameter.transfer }), param_name=param_name, + param_prefix=param_prefix, rust_type=rust_type(env, parameter.typ).into_string(), c_type=ffi_type(env, parameter.typ, &c_type).into_string()) } diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index 0098b7e45..a661ab12e 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -744,6 +744,7 @@ fn trampoline_call_parameters(env: &Env, analysis: &analysis::virtual_methods::I fn trampoline_call_return(env: &Env, object: &analysis::object::Info, method: &analysis::virtual_methods::Info) -> (String, Vec) { use codegen::subclass::trampoline_to_glib::trampoline_to_glib; + use analysis::out_parameters::Mode; let mut left = String::new(); let mut right: Vec = vec![]; @@ -752,9 +753,11 @@ fn trampoline_call_return(env: &Env, object: &analysis::object::Info, method: &a let mut retvar = retvar_name.clone(); let outs_as_return = !method.outs.is_empty(); - if outs_as_return { - let mut param_names: Vec = if method.ret.parameter.is_some() { vec![retvar_name.clone()] } else {vec![]}; + let outs_as_return_optional = method.outs.mode == Mode::Optional; + + if outs_as_return { + let mut param_names: Vec = vec![]; param_names.append(&mut (&method.outs.params).into_iter().map(|ref p| format!("rs_{}", p.name).to_string()).collect()); let param_name_list = param_names.join(", "); @@ -772,15 +775,28 @@ fn trampoline_call_return(env: &Env, object: &analysis::object::Info, method: &a ]); } } - match method.ret.parameter { - Some(ref param) => { - right.push(trampoline_to_glib(param, env, object, method)); - }, - None => {} - } if method.ret.parameter.is_some() || outs_as_return{ - left = format!("let {} = ", retvar).to_string(); + if !outs_as_return_optional{ + left = format!("let {} = ", retvar).to_string(); + }else{ + left = "let ret = ".to_string(); + } + } + + if !outs_as_return_optional{ + match method.ret.parameter { + Some(ref param) => { + right.push(trampoline_to_glib(param, env, object, method)); + }, + None => {} + } + }else{ + right.insert(0, "match ret {".to_string()); + right.insert(1, format!("Some({}) => {{", retvar).to_string()); + right.push("true.to_glib() },".to_string()); + right.push("None => false.to_glib()".to_string()); + right.push("}".to_string()); } (left, right) From 71856a806010f586b4cbff0b13ea740780f424d0 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 5 Jul 2018 06:54:59 +0200 Subject: [PATCH 119/122] fix destroy function for container types --- src/codegen/subclass/trampoline_to_glib.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/codegen/subclass/trampoline_to_glib.rs b/src/codegen/subclass/trampoline_to_glib.rs index 1ee386200..466f29763 100644 --- a/src/codegen/subclass/trampoline_to_glib.rs +++ b/src/codegen/subclass/trampoline_to_glib.rs @@ -80,11 +80,23 @@ fn to_glib_with_destroy(parameter: &library::Parameter, // TODO: way too ugly let c_type = type_.get_glib_name().map(|c| format!("{}*", c)).unwrap_or(parameter.c_type.clone()); + let is_container_type = match type_ { + library::Type::Array(..) | + library::Type::CArray(..) | + library::Type::PtrArray(..) | + library::Type::List(..) | + library::Type::SList(..) | + library::Type::FixedArray(..) => true, + _ => false + }; + + + let rust_type = rust_type(env, parameter.typ).into_string(); format!(r#"{{ let ret = {param_prefix}{param_name}{to_glib}; unsafe extern "C" fn destroy_{param_name}(p: glib_ffi::gpointer){{ - {rust_type}::from_glib_full(p as {c_type}); + let _:{rust_type} = {glib_translate}::from_glib_full(p as {c_type}); }}; gobject_ffi::g_object_set_qdata_full(gptr as *mut gobject_ffi::GObject, glib_ffi::g_quark_from_string("rs_{object_name}_{method_name}_{param_name}".to_glib_none().0), @@ -102,7 +114,8 @@ fn to_glib_with_destroy(parameter: &library::Parameter, }), param_name=param_name, param_prefix=param_prefix, - rust_type=rust_type(env, parameter.typ).into_string(), + glib_translate= if is_container_type {"FromGlibPtrContainer".to_string()} else {rust_type.clone()}, + rust_type=rust_type, c_type=ffi_type(env, parameter.typ, &c_type).into_string()) } From 53e6bc7d9cd5292e1bb0c94ebbddf122fa205bc6 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 6 Jul 2018 06:56:40 +0200 Subject: [PATCH 120/122] always import ffi library in subclass mode --- src/analysis/object.rs | 21 +++++++++++++++++++-- src/codegen/general.rs | 6 ------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/analysis/object.rs b/src/analysis/object.rs index 2474350b9..28e441ab2 100644 --- a/src/analysis/object.rs +++ b/src/analysis/object.rs @@ -10,6 +10,7 @@ use super::imports::Imports; use super::info_base::InfoBase; use super::signatures::Signatures; use traits::*; +use config::WorkMode; #[derive(Debug, Default)] pub struct Info { @@ -105,10 +106,20 @@ pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option let mut imports = Imports::with_defined(&env.library, &name); imports.add("glib::translate::*", None); - imports.add("ffi", None); + //imports.add("ffi", None); if obj.generate_display_trait { imports.add("std::fmt", None); } + imports.add("glib_ffi", None); + imports.add("gobject_ffi", None); + imports.add("std::mem", None); + imports.add("std::ptr", None); + + if env.config.work_mode != WorkMode::Subclass { + imports.add("ffi", None); + }else{ + imports.add(&format!("{}_ffi", env.config.library_name.to_lowercase()), None); + } let supertypes = supertypes::analyze(env, class_tid, &mut imports); @@ -316,12 +327,18 @@ pub fn interface(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option Result<()> { try!(writeln!(w)); for (name, &(ref version, ref constraints)) in imports.iter() { - // HACK: skip ffi in subclass mode. - if name == "ffi" && env.config.work_mode == WorkMode::Subclass{ - continue - } - if constraints.len() == 1 { try!(writeln!(w, "#[cfg(feature = \"{}\")]", constraints[0])); } else if !constraints.is_empty() { From d8c1dad0db9f82ad70fa72feb2daf762505b7f00 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 6 Jul 2018 08:30:43 +0200 Subject: [PATCH 121/122] fix styling --- src/codegen/subclass/trampoline_to_glib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/subclass/trampoline_to_glib.rs b/src/codegen/subclass/trampoline_to_glib.rs index 466f29763..9f167cd8f 100644 --- a/src/codegen/subclass/trampoline_to_glib.rs +++ b/src/codegen/subclass/trampoline_to_glib.rs @@ -96,7 +96,7 @@ fn to_glib_with_destroy(parameter: &library::Parameter, format!(r#"{{ let ret = {param_prefix}{param_name}{to_glib}; unsafe extern "C" fn destroy_{param_name}(p: glib_ffi::gpointer){{ - let _:{rust_type} = {glib_translate}::from_glib_full(p as {c_type}); + let _: {rust_type} = {glib_translate}::from_glib_full(p as {c_type}); }}; gobject_ffi::g_object_set_qdata_full(gptr as *mut gobject_ffi::GObject, glib_ffi::g_quark_from_string("rs_{object_name}_{method_name}_{param_name}".to_glib_none().0), From b9fad8ddd5d1dfa454d2c6ed013c45cefecfc1b7 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 28 Dec 2018 07:48:16 +0100 Subject: [PATCH 122/122] fix build after rebase --- src/analysis/virtual_methods.rs | 6 +++--- src/codegen/subclass/virtual_methods.rs | 2 +- src/lib.rs | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/analysis/virtual_methods.rs b/src/analysis/virtual_methods.rs index 76e152e18..0417754f0 100644 --- a/src/analysis/virtual_methods.rs +++ b/src/analysis/virtual_methods.rs @@ -165,7 +165,7 @@ fn analyze_virtual_method( "Wrong instance parameter in {}", method.c_identifier.as_ref().unwrap() ); - if let Ok(s) = used_rust_type(env, par.typ) { + if let Ok(s) = used_rust_type(env, par.typ, !par.direction.is_out()) { used_types.push(s); } let (to_glib_extra, callback_info) = bounds.add_for_parameter(env, method, par, async); @@ -243,12 +243,12 @@ fn analyze_virtual_method( if let Some(ref trampoline) = trampoline { for par in &trampoline.output_params { - if let Ok(s) = used_rust_type(env, par.typ) { + if let Ok(s) = used_rust_type(env, par.typ, !par.direction.is_out()) { used_types.push(s); } } if let Some(ref par) = trampoline.ffi_ret { - if let Ok(s) = used_rust_type(env, par.typ) { + if let Ok(s) = used_rust_type(env, par.typ, !par.direction.is_out()) { used_types.push(s); } } diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index a661ab12e..b7c8ea685 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -156,7 +156,7 @@ pub fn declaration(env: &Env, method_analysis: &analysis::virtual_methods::Info, " -> Result<(), glib::error::BoolError>".into() } } else { - method_analysis.ret.to_return_value(env) + method_analysis.ret.to_return_value(env, false) }; let mut param_str = String::with_capacity(100); diff --git a/src/lib.rs b/src/lib.rs index fc32bea77..c8fd13e6b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +#![feature(tool_lints)] #![allow(clippy::let_and_return)] #![allow(clippy::too_many_arguments)] #![allow(clippy::write_literal)]