From 7316d020472cddb5cf790935b20ff2610579765a Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Thu, 3 Aug 2017 13:59:34 +0200 Subject: [PATCH 1/7] For generated c++ headers generate small member wrapper functions Add a option to generate member function wrappers for each function taking a pointer to a struct type as first argument --- src/bindgen/config.rs | 4 +++ src/bindgen/ir/alias.rs | 1 + src/bindgen/ir/function.rs | 41 +++++++++++++++++++++------- src/bindgen/ir/structure.rs | 54 ++++++++++++++++++++++++++++++++++++- src/bindgen/library.rs | 51 +++++++++++++++++++++++++++++++++++ 5 files changed, 140 insertions(+), 11 deletions(-) diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index 0e1539e30..676df6a62 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -159,6 +159,9 @@ pub struct StructConfig { pub derive_gt: bool, /// Whether to generate a greater than or equal to operator on structs with one field pub derive_gte: bool, + /// Whether to generate member functions to wrap functions taking a pointer to this struct as + /// first argument + pub generate_member_functions: bool, } impl Default for StructConfig { @@ -172,6 +175,7 @@ impl Default for StructConfig { derive_lte: false, derive_gt: false, derive_gte: false, + generate_member_functions: true, } } } diff --git a/src/bindgen/ir/alias.rs b/src/bindgen/ir/alias.rs index 2d165cd4f..532d1f9c3 100644 --- a/src/bindgen/ir/alias.rs +++ b/src/bindgen/ir/alias.rs @@ -114,6 +114,7 @@ impl Specialization { .collect(), generic_params: self.generic_params.clone(), documentation: aliased.documentation.clone(), + functions: Vec::new(), }))) } PathValue::Enum(ref aliased) => { diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index 6297300f3..3a65f2175 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -46,6 +46,19 @@ impl Function { }) } + pub fn add_member_function(&self, out: &mut MemberFunctions) { + if let Some(&(_, ref ty)) = self.args.get(0) { + match *ty { + Type::ConstPtr(ref t) | Type::Ptr(ref t) => { + out.entry((**t).clone()) + .or_insert_with(Vec::new) + .push(self.clone()) + } + _ => {} + } + } + } + pub fn add_deps(&self, library: &Library, out: &mut DependencyList) { self.ret.add_deps(library, out); for &(_, ref ty) in &self.args { @@ -86,11 +99,9 @@ impl Function { ty.mangle_paths(monomorphs); } } -} -impl Source for Function { - fn write(&self, config: &Config, out: &mut SourceWriter) { - fn write_1(func: &Function, config: &Config, out: &mut SourceWriter) { + pub fn write_formated(&self, config: &Config, out: &mut SourceWriter, add_semicolon: bool) { + fn write_1(func: &Function, config: &Config, out: &mut SourceWriter, add_semicolon: bool) { let prefix = config.function.prefix(&func.annotations); let postfix = config.function.postfix(&func.annotations); @@ -104,10 +115,12 @@ impl Source for Function { out.write(" "); out.write(postfix); } - out.write(";"); + if add_semicolon { + out.write(";"); + } } - fn write_2(func: &Function, config: &Config, out: &mut SourceWriter) { + fn write_2(func: &Function, config: &Config, out: &mut SourceWriter, add_semicolon: bool) { let prefix = config.function.prefix(&func.annotations); let postfix = config.function.postfix(&func.annotations); @@ -121,20 +134,28 @@ impl Source for Function { out.new_line(); out.write(postfix); } - out.write(";"); + if add_semicolon { + out.write(";"); + } }; - let option_1 = out.measure(|out| write_1(self, config, out)); + let option_1 = out.measure(|out| write_1(self, config, out, add_semicolon)); if (config.function.args == Layout::Auto && option_1 <= config.line_length) || config.function.args == Layout::Horizontal { - write_1(self, config, out); + write_1(self, config, out, add_semicolon); } else { - write_2(self, config, out); + write_2(self, config, out, add_semicolon); } } } +impl Source for Function { + fn write(&self, config: &Config, out: &mut SourceWriter) { + self.write_formated(config, out, true) + } +} + pub trait SynFnArgHelpers { fn as_ident_and_type(&self) -> Result, String>; } diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 492f8c58a..2a720320a 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -8,7 +8,7 @@ use std::io::Write; use syn; use bindgen::annotation::*; -use bindgen::config::{Config, Language}; +use bindgen::config::{Config, Language, Layout}; use bindgen::ir::*; use bindgen::library::*; use bindgen::mangle::*; @@ -23,6 +23,7 @@ pub struct Struct { pub fields: Vec<(String, Type, Documentation)>, pub generic_params: Vec, pub documentation: Documentation, + pub functions: Vec, } impl Struct { @@ -63,6 +64,7 @@ impl Struct { fields: fields, generic_params: generic_params, documentation: Documentation::load(doc), + functions: Vec::new(), }) } @@ -94,6 +96,7 @@ impl Struct { .collect(), generic_params: vec![], documentation: self.documentation.clone(), + functions: vec![], }; for &(_, ref ty, _) in &monomorph.fields { @@ -176,6 +179,28 @@ impl Source for Struct { String::from("other") }; + out.new_line(); + for f in &self.functions { + if f.extern_decl { + continue; + } + out.new_line(); + f.write_formated(config, out, false); + out.open_brace(); + out.new_line(); + let option_1 = out.measure(|out| format_function_call_1(f, out)); + + if (config.function.args == Layout::Auto && option_1 <= config.line_length) || + config.function.args == Layout::Horizontal { + format_function_call_1(f, out); + } else { + format_function_call_2(f, out); + } + + out.close_brace(false); + out.new_line(); + } + let mut emit_op = |op, conjuc| { if !wrote_start_newline { wrote_start_newline = true; @@ -230,6 +255,33 @@ impl Source for Struct { } } +fn format_function_call_1(f: &Function, out: &mut SourceWriter) { + out.write("return ::"); + out.write(&f.name); + out.write("(this"); + for &(ref name, _) in &f.args { + out.write(", "); + out.write(name); + } + out.write(");"); +} + +fn format_function_call_2(f: &Function, out: &mut SourceWriter) { + out.write("return ::"); + out.write(&f.name); + out.write("("); + let align_lenght = out.line_length_for_align(); + out.push_set_spaces(align_lenght); + out.write("this"); + for &(ref name, _) in &f.args { + out.write(","); + out.new_line(); + out.write(name); + } + out.pop_tab(); + out.write(");"); +} + pub trait SynFieldHelpers { fn as_ident_and_type(&self) -> Result, String>; } diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 62c3eb75c..d174c214d 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -124,6 +124,7 @@ impl Monomorph { pub type MonomorphList = BTreeMap, Monomorph>; pub type Monomorphs = BTreeMap; +pub type MemberFunctions = BTreeMap>; /// A dependency list is used for gathering what order to output the types. pub struct DependencyList { @@ -637,8 +638,10 @@ impl Library { // Gather only the items that we need for this // `extern "c"` interface let mut deps = DependencyList::new(); + let mut oop = MemberFunctions::new(); for (_, function) in &self.functions { function.add_deps(&self, &mut deps); + function.add_member_function(&mut oop); } // Gather a list of all the instantiations of generic structs @@ -712,6 +715,42 @@ impl Library { }; result.items.sort_by(ordering); + // Collect all possible member fucntions + if self.config.language == Language::Cxx && self.config.structure.generate_member_functions { + let items = ::std::mem::replace(&mut result.items, Vec::new()); + for item in items { + match item { + PathValue::Struct(mut s) => { + let ty = Type::Path(s.name.clone(), Vec::new()); + if let Some(functions) = oop.remove(&ty) { + let opaque = OpaqueItem { + name:s.name.clone(), + generic_params: s.generic_params.clone(), + annotations: s.annotations.clone(), + documentation: s.documentation.clone(), + }; + result.items.push(PathValue::OpaqueItem(opaque)); + s.functions = functions.into_iter() + .map(|f| { + Function { + name: f.name, + annotations: f.annotations, + ret: f.ret, + args: f.args[1..].to_owned(), + extern_decl: f.extern_decl, + documentation: f.documentation.clone(), + } + }).collect(); + result.full_objects.push(s); + } else { + result.items.push(PathValue::Struct(s)); + } + } + other => result.items.push(other), + } + } + } + result.functions = self.functions.iter() .map(|(_, function)| function.clone()) .collect::>(); @@ -762,6 +801,7 @@ pub struct GeneratedBindings { monomorphs: Monomorphs, items: Vec, functions: Vec, + full_objects: Vec, } impl GeneratedBindings { @@ -771,6 +811,7 @@ impl GeneratedBindings { monomorphs: Monomorphs::new(), items: Vec::new(), functions: Vec::new(), + full_objects: Vec::new(), } } @@ -880,6 +921,16 @@ impl GeneratedBindings { out.new_line(); } + if self.config.language == Language::Cxx { + out.new_line(); + out.new_line(); + for full_object in &self.full_objects { + full_object.write(&self.config, &mut out); + out.new_line(); + out.new_line(); + } + } + if self.config.language == Language::Cxx { let mut wrote_namespace: bool = false; if let Some(ref namespaces) = self.config.namespaces { From a577a6e4449134a5eef4204638ccf90f7ed2b132 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Thu, 3 Aug 2017 14:10:46 +0200 Subject: [PATCH 2/7] Remove some unneeded checks for generating documentation --- src/bindgen/ir/alias.rs | 4 +--- src/bindgen/ir/structure.rs | 9 +-------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/bindgen/ir/alias.rs b/src/bindgen/ir/alias.rs index 532d1f9c3..a6f37b240 100644 --- a/src/bindgen/ir/alias.rs +++ b/src/bindgen/ir/alias.rs @@ -231,9 +231,7 @@ impl Typedef { impl Source for Typedef { fn write(&self, config: &Config, out: &mut SourceWriter) { - if config.documentation { - self.documentation.write(config, out); - } + self.documentation.write(config, out); out.write("typedef "); (self.name.clone(), self.aliased.clone()).write(config, out); out.write(";"); diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 2a720320a..d6df9d798 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -161,14 +161,7 @@ impl Source for Struct { } out.open_brace(); - if config.documentation { - out.write_vertical_source_list(&self.fields, ListType::Cap(";")); - } else { - out.write_vertical_source_list(&self.fields.iter() - .map(|&(ref name, ref ty, _)| (name.clone(), ty.clone())) - .collect(), - ListType::Cap(";")); - } + out.write_vertical_source_list(&self.fields, ListType::Cap(";")); if config.language == Language::Cxx { let mut wrote_start_newline = false; From c6ad53c8f55ece7c3d4eed4398993eccfc9b5129 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Mon, 7 Aug 2017 14:34:41 +0200 Subject: [PATCH 3/7] Support destructors --- src/bindgen/ir/alias.rs | 1 + src/bindgen/ir/function.rs | 19 +++++- src/bindgen/ir/structure.rs | 127 +++++++++++++++++++++++++++++------- src/bindgen/library.rs | 26 +++----- 4 files changed, 130 insertions(+), 43 deletions(-) diff --git a/src/bindgen/ir/alias.rs b/src/bindgen/ir/alias.rs index a6f37b240..1d1cd9b4b 100644 --- a/src/bindgen/ir/alias.rs +++ b/src/bindgen/ir/alias.rs @@ -115,6 +115,7 @@ impl Specialization { generic_params: self.generic_params.clone(), documentation: aliased.documentation.clone(), functions: Vec::new(), + destructor: None, }))) } PathValue::Enum(ref aliased) => { diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index 3a65f2175..15c05d3ff 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -14,6 +14,7 @@ use bindgen::library::*; use bindgen::rename::*; use bindgen::utilities::*; use bindgen::writer::*; +use bindgen::mangle; #[derive(Debug, Clone)] pub struct Function { @@ -50,7 +51,16 @@ impl Function { if let Some(&(_, ref ty)) = self.args.get(0) { match *ty { Type::ConstPtr(ref t) | Type::Ptr(ref t) => { - out.entry((**t).clone()) + let t = match **t { + Type::Path(ref t, ref g) if g.is_empty() => { + Type::Path(t.to_owned(), Vec::new()) + } + Type::Path(ref p, ref g) => { + Type::Path(mangle::mangle_path(p, g), Vec::new()) + } + _ => return + }; + out.entry(t) .or_insert_with(Vec::new) .push(self.clone()) } @@ -100,6 +110,13 @@ impl Function { } } + pub fn as_member(self) -> Self{ + Function { + args: self.args[1..].to_owned(), + ..self + } + } + pub fn write_formated(&self, config: &Config, out: &mut SourceWriter, add_semicolon: bool) { fn write_1(func: &Function, config: &Config, out: &mut SourceWriter, add_semicolon: bool) { let prefix = config.function.prefix(&func.annotations); diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index d6df9d798..8aa5346db 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -24,6 +24,7 @@ pub struct Struct { pub generic_params: Vec, pub documentation: Documentation, pub functions: Vec, + pub destructor: Option, } impl Struct { @@ -65,6 +66,7 @@ impl Struct { generic_params: generic_params, documentation: Documentation::load(doc), functions: Vec::new(), + destructor: None, }) } @@ -97,6 +99,7 @@ impl Struct { generic_params: vec![], documentation: self.documentation.clone(), functions: vec![], + destructor: None, }; for &(_, ref ty, _) in &monomorph.fields { @@ -140,15 +143,100 @@ impl Struct { x.2.clone())) .collect(); } + + for f in &mut self.functions { + f.rename_args(config); + } + if let Some(ref mut destructor) = self.destructor { + destructor.rename_args(config); + } } pub fn mangle_paths(&mut self, monomorphs: &Monomorphs) { for &mut (_, ref mut ty, _) in &mut self.fields { ty.mangle_paths(monomorphs); } + for f in &mut self.functions { + f.mangle_paths(monomorphs); + } + if let Some(ref mut destructor) = self.destructor { + destructor.mangle_paths(monomorphs); + } + } + + pub fn add_member_function(&mut self, function: Function) { + + if function.annotations.bool("destructor").unwrap_or(false) + && self.destructor.is_none() && function.args.is_empty() + { + self.destructor = Some(function); + } else if !function.annotations.bool("destructor").unwrap_or(false) { + self.functions.push(function); + } else { + warn!("Found double destructor annotation for struct {}", self.name); + } + } + + pub fn as_opaque(&self) -> OpaqueItem { + OpaqueItem { + name: self.name.clone(), + generic_params: self.generic_params.clone(), + annotations: self.annotations.clone(), + documentation: self.documentation.clone(), + } + } + + pub fn write_destructor(&self, config: &Config, out: &mut SourceWriter) { + if let Some(ref destructor) = self.destructor { + if !destructor.extern_decl { + out.new_line(); + out.new_line(); + + out.write(&format!("~{}()", self.name)); + out.open_brace(); + let option_1 = out.measure(|out| format_function_call_1(destructor, out, false)); + + if (config.function.args == Layout::Auto && option_1 <= config.line_length) || + config.function.args == Layout::Horizontal { + format_function_call_1(destructor, out, false); + } else { + format_function_call_2(destructor, out, false); + } + + out.close_brace(false); + } + } + } + + pub fn write_functions(&self, config: &Config, out: &mut SourceWriter) { + if !self.functions.is_empty() { + out.new_line(); + out.new_line(); + } + for f in &self.functions { + if f.extern_decl { + continue; + } + out.new_line(); + f.write_formated(config, out, false); + out.open_brace(); + let option_1 = out.measure(|out| format_function_call_1(f, out, true)); + + if (config.function.args == Layout::Auto && option_1 <= config.line_length) || + config.function.args == Layout::Horizontal { + format_function_call_1(f, out, true); + } else { + format_function_call_2(f, out, true); + } + + out.close_brace(false); + out.new_line(); + } } } + + impl Source for Struct { fn write(&self, config: &Config, out: &mut SourceWriter) { assert!(self.generic_params.is_empty()); @@ -172,27 +260,8 @@ impl Source for Struct { String::from("other") }; - out.new_line(); - for f in &self.functions { - if f.extern_decl { - continue; - } - out.new_line(); - f.write_formated(config, out, false); - out.open_brace(); - out.new_line(); - let option_1 = out.measure(|out| format_function_call_1(f, out)); - - if (config.function.args == Layout::Auto && option_1 <= config.line_length) || - config.function.args == Layout::Horizontal { - format_function_call_1(f, out); - } else { - format_function_call_2(f, out); - } - - out.close_brace(false); - out.new_line(); - } + self.write_destructor(config, out); + self.write_functions(config, out); let mut emit_op = |op, conjuc| { if !wrote_start_newline { @@ -248,8 +317,12 @@ impl Source for Struct { } } -fn format_function_call_1(f: &Function, out: &mut SourceWriter) { - out.write("return ::"); +fn format_function_call_1(f: &Function, out: &mut SourceWriter, with_return: bool) { + if with_return { + out.write("return ::"); + } else { + out.write("::"); + } out.write(&f.name); out.write("(this"); for &(ref name, _) in &f.args { @@ -259,8 +332,12 @@ fn format_function_call_1(f: &Function, out: &mut SourceWriter) { out.write(");"); } -fn format_function_call_2(f: &Function, out: &mut SourceWriter) { - out.write("return ::"); +fn format_function_call_2(f: &Function, out: &mut SourceWriter, with_return: bool) { + if with_return { + out.write("return ::"); + } else { + out.write("::"); + } out.write(&f.name); out.write("("); let align_lenght = out.line_length_for_align(); diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index d174c214d..1c02b0ef1 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -723,24 +723,11 @@ impl Library { PathValue::Struct(mut s) => { let ty = Type::Path(s.name.clone(), Vec::new()); if let Some(functions) = oop.remove(&ty) { - let opaque = OpaqueItem { - name:s.name.clone(), - generic_params: s.generic_params.clone(), - annotations: s.annotations.clone(), - documentation: s.documentation.clone(), - }; + let opaque = s.as_opaque(); result.items.push(PathValue::OpaqueItem(opaque)); - s.functions = functions.into_iter() - .map(|f| { - Function { - name: f.name, - annotations: f.annotations, - ret: f.ret, - args: f.args[1..].to_owned(), - extern_decl: f.extern_decl, - documentation: f.documentation.clone(), - } - }).collect(); + for f in functions { + s.add_member_function(f.as_member()); + } result.full_objects.push(s); } else { result.items.push(PathValue::Struct(s)); @@ -762,6 +749,11 @@ impl Library { item.rename_fields(&self.config); } + for item in &mut result.full_objects { + item.mangle_paths(&monomorphs); + item.rename_fields(&self.config); + } + // Rename all the arguments according to their rules and mangle any // paths that refer to generic structs that have been monomorph'ed. for func in &mut result.functions { From b06548796371d14989794cd9d0a965e184776bc1 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Thu, 10 Aug 2017 22:21:51 +0200 Subject: [PATCH 4/7] Explicitly delete copy constructor and copy assigne If a destructor is implemented it is unsafe to have a copy constructor without having a clone implementation (Future versions may allow to have a copy construtor if a clone method is provieded from rust side) --- src/bindgen/ir/structure.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 8aa5346db..1007e2d9d 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -109,7 +109,7 @@ impl Struct { if !out.contains_key(&self.name) { out.insert(self.name.clone(), BTreeMap::new()); } - out.get_mut(&self.name).unwrap().insert(generic_values.clone(), + out.get_mut(&self.name).unwrap().insert(generic_values.clone(), Monomorph::Struct(monomorph)); } @@ -191,6 +191,16 @@ impl Struct { if !destructor.extern_decl { out.new_line(); out.new_line(); + // Explicitly disable copy constructor and assignment + out.write(&format!("{0}(const {0}& ) = delete;", self.name)); + out.new_line(); + out.write(&format!("{0}& operator=(const {0}&) = delete;", self.name)); + out.new_line(); + out.write(&format!("{0}({0}&&) = default;", self.name)); + out.new_line(); + out.write(&format!("{0}& operator=({0}&&) = default;", self.name)); + out.new_line(); + out.new_line(); out.write(&format!("~{}()", self.name)); out.open_brace(); @@ -211,7 +221,6 @@ impl Struct { pub fn write_functions(&self, config: &Config, out: &mut SourceWriter) { if !self.functions.is_empty() { out.new_line(); - out.new_line(); } for f in &self.functions { if f.extern_decl { From 3b5868785062977697cf7e084e635b52497c88ee Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Fri, 11 Aug 2017 10:16:31 +0200 Subject: [PATCH 5/7] Skip outputing a return statement if a function only returns void --- src/bindgen/ir/structure.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 1007e2d9d..e48880a30 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -204,13 +204,13 @@ impl Struct { out.write(&format!("~{}()", self.name)); out.open_brace(); - let option_1 = out.measure(|out| format_function_call_1(destructor, out, false)); + let option_1 = out.measure(|out| format_function_call_1(destructor, out)); if (config.function.args == Layout::Auto && option_1 <= config.line_length) || config.function.args == Layout::Horizontal { - format_function_call_1(destructor, out, false); + format_function_call_1(destructor, out); } else { - format_function_call_2(destructor, out, false); + format_function_call_2(destructor, out); } out.close_brace(false); @@ -229,13 +229,13 @@ impl Struct { out.new_line(); f.write_formated(config, out, false); out.open_brace(); - let option_1 = out.measure(|out| format_function_call_1(f, out, true)); + let option_1 = out.measure(|out| format_function_call_1(f, out)); if (config.function.args == Layout::Auto && option_1 <= config.line_length) || config.function.args == Layout::Horizontal { - format_function_call_1(f, out, true); + format_function_call_1(f, out); } else { - format_function_call_2(f, out, true); + format_function_call_2(f, out); } out.close_brace(false); @@ -326,11 +326,11 @@ impl Source for Struct { } } -fn format_function_call_1(f: &Function, out: &mut SourceWriter, with_return: bool) { - if with_return { - out.write("return ::"); - } else { +fn format_function_call_1(f: &Function, out: &mut SourceWriter) { + if f.ret == Type::Primitive(PrimitiveType::Void) { out.write("::"); + } else { + out.write("return ::"); } out.write(&f.name); out.write("(this"); @@ -341,11 +341,11 @@ fn format_function_call_1(f: &Function, out: &mut SourceWriter, wit out.write(");"); } -fn format_function_call_2(f: &Function, out: &mut SourceWriter, with_return: bool) { - if with_return { - out.write("return ::"); - } else { +fn format_function_call_2(f: &Function, out: &mut SourceWriter) { + if f.ret == Type::Primitive(PrimitiveType::Void) { out.write("::"); + } else { + out.write("return ::"); } out.write(&f.name); out.write("("); From 0e9607e6297abf8b8e1274ecc38c59ed386bed53 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Fri, 11 Aug 2017 10:48:30 +0200 Subject: [PATCH 6/7] Fix constness of generated member functions --- src/bindgen/ir/function.rs | 72 ++++++++++++++++++++++++++----------- src/bindgen/ir/structure.rs | 30 ++++++++-------- src/bindgen/library.rs | 4 +-- 3 files changed, 68 insertions(+), 38 deletions(-) diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index 15c05d3ff..a8021c84a 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -16,6 +16,12 @@ use bindgen::utilities::*; use bindgen::writer::*; use bindgen::mangle; +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum FunctionWriteMode { + Global, + MemberFunction, +} + #[derive(Debug, Clone)] pub struct Function { pub name: String, @@ -52,9 +58,6 @@ impl Function { match *ty { Type::ConstPtr(ref t) | Type::Ptr(ref t) => { let t = match **t { - Type::Path(ref t, ref g) if g.is_empty() => { - Type::Path(t.to_owned(), Vec::new()) - } Type::Path(ref p, ref g) => { Type::Path(mangle::mangle_path(p, g), Vec::new()) } @@ -110,15 +113,16 @@ impl Function { } } - pub fn as_member(self) -> Self{ - Function { - args: self.args[1..].to_owned(), - ..self - } - } - - pub fn write_formated(&self, config: &Config, out: &mut SourceWriter, add_semicolon: bool) { - fn write_1(func: &Function, config: &Config, out: &mut SourceWriter, add_semicolon: bool) { + pub fn write_formated(&self, + config: &Config, + out: &mut SourceWriter, + mode: FunctionWriteMode) + { + fn write_1(func: &Function, + config: &Config, + out: &mut SourceWriter, + mode: FunctionWriteMode) + { let prefix = config.function.prefix(&func.annotations); let postfix = config.function.postfix(&func.annotations); @@ -127,17 +131,32 @@ impl Function { out.write(prefix); out.write(" "); } - cdecl::write_func(out, &func, false); + if mode == FunctionWriteMode::Global { + cdecl::write_func(out, &func, false); + } else { + let f = Function { + args: func.args[1..].to_owned(), + ..func.clone() + }; + cdecl::write_func(out, &f, false); + if let Type::ConstPtr(_) = func.args[0].1 { + out.write(" const"); + } + } if let Some(ref postfix) = postfix { out.write(" "); out.write(postfix); } - if add_semicolon { + if mode == FunctionWriteMode::Global { out.write(";"); } } - fn write_2(func: &Function, config: &Config, out: &mut SourceWriter, add_semicolon: bool) { + fn write_2(func: &Function, + config: &Config, + out: &mut SourceWriter, + mode: FunctionWriteMode) + { let prefix = config.function.prefix(&func.annotations); let postfix = config.function.postfix(&func.annotations); @@ -146,30 +165,41 @@ impl Function { out.write(prefix); out.new_line(); } - cdecl::write_func(out, &func, true); + if mode == FunctionWriteMode::Global { + cdecl::write_func(out, &func, true); + } else { + let f = Function { + args: func.args[1..].to_owned(), + ..func.clone() + }; + cdecl::write_func(out, &f, true); + if let Type::ConstPtr(_) = func.args[0].1 { + out.write(" const"); + } + } if let Some(ref postfix) = postfix { out.new_line(); out.write(postfix); } - if add_semicolon { + if mode == FunctionWriteMode::Global { out.write(";"); } }; - let option_1 = out.measure(|out| write_1(self, config, out, add_semicolon)); + let option_1 = out.measure(|out| write_1(self, config, out, mode)); if (config.function.args == Layout::Auto && option_1 <= config.line_length) || config.function.args == Layout::Horizontal { - write_1(self, config, out, add_semicolon); + write_1(self, config, out, mode); } else { - write_2(self, config, out, add_semicolon); + write_2(self, config, out, mode); } } } impl Source for Function { fn write(&self, config: &Config, out: &mut SourceWriter) { - self.write_formated(config, out, true) + self.write_formated(config, out, FunctionWriteMode::Global) } } diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index e48880a30..3bc55558d 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -164,16 +164,18 @@ impl Struct { } } - pub fn add_member_function(&mut self, function: Function) { - - if function.annotations.bool("destructor").unwrap_or(false) - && self.destructor.is_none() && function.args.is_empty() - { - self.destructor = Some(function); - } else if !function.annotations.bool("destructor").unwrap_or(false) { - self.functions.push(function); - } else { - warn!("Found double destructor annotation for struct {}", self.name); + pub fn add_member_functions(&mut self, functions: Vec) { + for function in functions { + if function.annotations.bool("destructor").unwrap_or(false) + && self.destructor.is_none() && function.args.len() == 1 && + function.ret == Type::Primitive(PrimitiveType::Void) + { + self.destructor = Some(function); + } else if !function.annotations.bool("destructor").unwrap_or(false) { + self.functions.push(function); + } else { + warn!("Found double destructor annotation for struct {}", self.name); + } } } @@ -192,7 +194,7 @@ impl Struct { out.new_line(); out.new_line(); // Explicitly disable copy constructor and assignment - out.write(&format!("{0}(const {0}& ) = delete;", self.name)); + out.write(&format!("{0}(const {0}&) = delete;", self.name)); out.new_line(); out.write(&format!("{0}& operator=(const {0}&) = delete;", self.name)); out.new_line(); @@ -227,7 +229,7 @@ impl Struct { continue; } out.new_line(); - f.write_formated(config, out, false); + f.write_formated(config, out, FunctionWriteMode::MemberFunction); out.open_brace(); let option_1 = out.measure(|out| format_function_call_1(f, out)); @@ -334,7 +336,7 @@ fn format_function_call_1(f: &Function, out: &mut SourceWriter) { } out.write(&f.name); out.write("(this"); - for &(ref name, _) in &f.args { + for &(ref name, _) in &f.args[1..] { out.write(", "); out.write(name); } @@ -352,7 +354,7 @@ fn format_function_call_2(f: &Function, out: &mut SourceWriter) { let align_lenght = out.line_length_for_align(); out.push_set_spaces(align_lenght); out.write("this"); - for &(ref name, _) in &f.args { + for &(ref name, _) in &f.args[1..] { out.write(","); out.new_line(); out.write(name); diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 1c02b0ef1..2966b4a26 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -725,9 +725,7 @@ impl Library { if let Some(functions) = oop.remove(&ty) { let opaque = s.as_opaque(); result.items.push(PathValue::OpaqueItem(opaque)); - for f in functions { - s.add_member_function(f.as_member()); - } + s.add_member_functions(functions); result.full_objects.push(s); } else { result.items.push(PathValue::Struct(s)); From 506297fe7d4a37ce1301e11ea9247bfd5f9e1996 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Fri, 11 Aug 2017 11:00:41 +0200 Subject: [PATCH 7/7] Address review comments --- src/bindgen/ir/structure.rs | 4 ++-- src/bindgen/library.rs | 24 ++++++++++++++---------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 3bc55558d..6c213516b 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -351,8 +351,8 @@ fn format_function_call_2(f: &Function, out: &mut SourceWriter) { } out.write(&f.name); out.write("("); - let align_lenght = out.line_length_for_align(); - out.push_set_spaces(align_lenght); + let align_length = out.line_length_for_align(); + out.push_set_spaces(align_length); out.write("this"); for &(ref name, _) in &f.args[1..] { out.write(","); diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 2966b4a26..6543c995f 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -638,10 +638,10 @@ impl Library { // Gather only the items that we need for this // `extern "c"` interface let mut deps = DependencyList::new(); - let mut oop = MemberFunctions::new(); + let mut member_functions = MemberFunctions::new(); for (_, function) in &self.functions { function.add_deps(&self, &mut deps); - function.add_member_function(&mut oop); + function.add_member_function(&mut member_functions); } // Gather a list of all the instantiations of generic structs @@ -722,11 +722,11 @@ impl Library { match item { PathValue::Struct(mut s) => { let ty = Type::Path(s.name.clone(), Vec::new()); - if let Some(functions) = oop.remove(&ty) { + if let Some(functions) = member_functions.remove(&ty) { let opaque = s.as_opaque(); result.items.push(PathValue::OpaqueItem(opaque)); s.add_member_functions(functions); - result.full_objects.push(s); + result.member_function_structs.push(s); } else { result.items.push(PathValue::Struct(s)); } @@ -747,7 +747,7 @@ impl Library { item.rename_fields(&self.config); } - for item in &mut result.full_objects { + for item in &mut result.member_function_structs { item.mangle_paths(&monomorphs); item.rename_fields(&self.config); } @@ -791,7 +791,7 @@ pub struct GeneratedBindings { monomorphs: Monomorphs, items: Vec, functions: Vec, - full_objects: Vec, + member_function_structs: Vec, } impl GeneratedBindings { @@ -801,7 +801,7 @@ impl GeneratedBindings { monomorphs: Monomorphs::new(), items: Vec::new(), functions: Vec::new(), - full_objects: Vec::new(), + member_function_structs: Vec::new(), } } @@ -913,11 +913,15 @@ impl GeneratedBindings { if self.config.language == Language::Cxx { out.new_line(); - out.new_line(); - for full_object in &self.full_objects { + let mut first = true; + for full_object in &self.member_function_structs { + if first { + first = false; + } else { + out.new_line(); + } full_object.write(&self.config, &mut out); out.new_line(); - out.new_line(); } }