From 6ee8ca626d01af93eb771282853c548382b3c0b7 Mon Sep 17 00:00:00 2001 From: Jos van den Oever Date: Fri, 28 Sep 2018 23:23:40 +0200 Subject: [PATCH] Add function to create bindings from runtime Config object --- src/bin/rust_qt_binding_generator.rs | 10 ++- src/configuration.rs | 96 +++++++++++++++------------- src/configuration_private.rs | 48 ++++++++++++++ src/cpp.rs | 23 ++++--- src/lib.rs | 20 ++++-- src/rust.rs | 5 +- 6 files changed, 133 insertions(+), 69 deletions(-) create mode 100644 src/configuration_private.rs diff --git a/src/bin/rust_qt_binding_generator.rs b/src/bin/rust_qt_binding_generator.rs index a04085b..251ca31 100644 --- a/src/bin/rust_qt_binding_generator.rs +++ b/src/bin/rust_qt_binding_generator.rs @@ -1,6 +1,6 @@ extern crate clap; extern crate rust_qt_binding_generator; -use clap::{Arg, App}; +use clap::{App, Arg}; use rust_qt_binding_generator::*; fn main() { @@ -11,19 +11,17 @@ fn main() { Arg::with_name("overwrite-implementation") .long("overwrite-implementation") .help("Overwrite existing implementation."), - ) - .arg( + ).arg( Arg::with_name("config") .multiple(true) .required(true) .takes_value(true) .help("Configuration file(s)"), - ) - .get_matches(); + ).get_matches(); let overwrite_implementation = matches.is_present("overwrite-implementation"); for config in matches.values_of("config").unwrap() { - if let Err(e) = generate_rust_qt_bindings(config, overwrite_implementation) { + if let Err(e) = generate_bindings_from_config_file(config, overwrite_implementation) { eprintln!("{}", e); ::std::process::exit(1); } diff --git a/src/configuration.rs b/src/configuration.rs index d2d7001..b4e370f 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -1,3 +1,4 @@ +use configuration_private::*; use serde_json; use std::collections::{BTreeMap, BTreeSet}; use std::error::Error; @@ -64,8 +65,8 @@ pub struct Config { pub overwrite_implementation: bool, } -impl Config { - pub fn types(&self) -> BTreeSet { +impl ConfigPrivate for Config { + fn types(&self) -> BTreeSet { let mut ops = BTreeSet::new(); for o in self.objects.values() { for p in o.properties.values() { @@ -83,7 +84,7 @@ impl Config { } ops } - pub fn optional_types(&self) -> BTreeSet { + fn optional_types(&self) -> BTreeSet { let mut ops = BTreeSet::new(); for o in self.objects.values() { for p in o.properties.values() { @@ -102,7 +103,7 @@ impl Config { } ops } - pub fn has_list_or_tree(&self) -> bool { + fn has_list_or_tree(&self) -> bool { self.objects .values() .any(|o| o.object_type == ObjectType::List || o.object_type == ObjectType::Tree) @@ -116,13 +117,19 @@ pub struct Object { pub item_properties: BTreeMap, pub object_type: ObjectType, pub properties: BTreeMap, - pub column_count: usize, } -impl Object { - pub fn contains_object(&self) -> bool { +impl ObjectPrivate for Object { + fn contains_object(&self) -> bool { self.properties.values().any(|p| p.is_object()) } + fn column_count(&self) -> usize { + let mut column_count = 1; + for ip in self.item_properties.values() { + column_count = column_count.max(ip.roles.len()); + } + column_count + } } #[derive(PartialEq)] @@ -133,22 +140,25 @@ pub struct Property { pub write: bool, } -impl Property { - pub fn is_object(&self) -> bool { +impl PropertyPrivate for Property { + fn is_object(&self) -> bool { self.property_type.is_object() } - pub fn is_complex(&self) -> bool { + fn is_complex(&self) -> bool { self.property_type.is_complex() } - pub fn type_name(&self) -> &str { - self.property_type.name() - } - pub fn c_get_type(&self) -> String { + fn c_get_type(&self) -> String { let name = self.property_type.name(); name.to_string() + "*, " + &name.to_lowercase() + "_set" } } +impl TypeName for Property { + fn type_name(&self) -> &str { + self.property_type.name() + } +} + #[derive(Deserialize)] #[serde(deny_unknown_fields)] pub struct Rust { @@ -196,8 +206,8 @@ pub enum SimpleType { QUint64, } -impl SimpleType { - pub fn name(&self) -> &str { +impl SimpleTypePrivate for SimpleType { + fn name(&self) -> &str { match self { SimpleType::QString => "QString", SimpleType::QByteArray => "QByteArray", @@ -215,7 +225,7 @@ impl SimpleType { SimpleType::QUint64 => "quint64", } } - pub fn cpp_set_type(&self) -> &str { + fn cpp_set_type(&self) -> &str { match self { SimpleType::QString => "const QString&", SimpleType::QByteArray => "const QByteArray&", @@ -233,7 +243,7 @@ impl SimpleType { SimpleType::QUint64 => "quint64", } } - pub fn c_set_type(&self) -> &str { + fn c_set_type(&self) -> &str { match self { SimpleType::QString => "qstring_t", SimpleType::QByteArray => "qbytearray_t", @@ -251,7 +261,7 @@ impl SimpleType { SimpleType::QUint64 => "quint64", } } - pub fn rust_type(&self) -> &str { + fn rust_type(&self) -> &str { match self { SimpleType::QString => "String", SimpleType::QByteArray => "Vec", @@ -269,7 +279,7 @@ impl SimpleType { SimpleType::QUint64 => "u64", } } - pub fn rust_type_init(&self) -> &str { + fn rust_type_init(&self) -> &str { match self { SimpleType::QString => "String::new()", SimpleType::QByteArray => "Vec::new()", @@ -287,7 +297,7 @@ impl SimpleType { SimpleType::QUint64 => "0", } } - pub fn is_complex(self) -> bool { + fn is_complex(self) -> bool { self == SimpleType::QString || self == SimpleType::QByteArray } } @@ -298,46 +308,46 @@ pub enum Type { Object(Rc), } -impl Type { - pub fn is_object(&self) -> bool { +impl TypePrivate for Type { + fn is_object(&self) -> bool { if let Type::Object(_) = self { true } else { false } } - pub fn is_complex(&self) -> bool { + fn is_complex(&self) -> bool { if let Type::Simple(simple) = self { simple.is_complex() } else { false } } - pub fn name(&self) -> &str { + fn name(&self) -> &str { match self { Type::Simple(s) => s.name(), Type::Object(o) => &o.name, } } - pub fn cpp_set_type(&self) -> &str { + fn cpp_set_type(&self) -> &str { match self { Type::Simple(s) => s.cpp_set_type(), Type::Object(o) => &o.name, } } - pub fn c_set_type(&self) -> &str { + fn c_set_type(&self) -> &str { match self { Type::Simple(s) => s.c_set_type(), Type::Object(o) => &o.name, } } - pub fn rust_type(&self) -> &str { + fn rust_type(&self) -> &str { match self { Type::Simple(s) => s.rust_type(), Type::Object(o) => &o.name, } } - pub fn rust_type_init(&self) -> &str { + fn rust_type_init(&self) -> &str { match self { Type::Simple(s) => s.rust_type_init(), Type::Object(_) => unimplemented!(), @@ -360,25 +370,28 @@ pub struct ItemProperty { pub write: bool, } -impl ItemProperty { - pub fn type_name(&self) -> &str { +impl TypeName for ItemProperty { + fn type_name(&self) -> &str { self.item_property_type.name() } - pub fn is_complex(&self) -> bool { +} + +impl ItemPropertyPrivate for ItemProperty { + fn is_complex(&self) -> bool { self.item_property_type.is_complex() } - pub fn cpp_set_type(&self) -> String { + fn cpp_set_type(&self) -> String { let mut t = self.item_property_type.cpp_set_type().to_string(); if self.optional { t = "option_".to_string() + &t; } t } - pub fn c_get_type(&self) -> String { + fn c_get_type(&self) -> String { let name = self.item_property_type.name(); name.to_string() + "*, " + &name.to_lowercase() + "_set" } - pub fn c_set_type(&self) -> &str { + fn c_set_type(&self) -> &str { self.item_property_type.c_set_type() } } @@ -394,8 +407,8 @@ pub struct Function { pub arguments: Vec, } -impl Function { - pub fn type_name(&self) -> &str { +impl TypeName for Function { + fn type_name(&self) -> &str { self.return_type.name() } } @@ -408,8 +421,8 @@ pub struct Argument { pub argument_type: SimpleType, } -impl Argument { - pub fn type_name(&self) -> &str { +impl TypeName for Argument { + fn type_name(&self) -> &str { self.argument_type.name() } } @@ -450,17 +463,12 @@ fn post_process_object( for p in &a.1.properties { properties.insert(p.0.clone(), post_process_property(p, b, c)?); } - let mut column_count = 1; - for ip in &a.1.item_properties { - column_count = column_count.max(ip.1.roles.len()); - } let object = Rc::new(Object { name: a.0.clone(), object_type: a.1.object_type, functions: a.1.functions.clone(), item_properties: a.1.item_properties.clone(), properties, - column_count, }); b.insert(a.0.clone(), object); Ok(()) diff --git a/src/configuration_private.rs b/src/configuration_private.rs new file mode 100644 index 0000000..0834902 --- /dev/null +++ b/src/configuration_private.rs @@ -0,0 +1,48 @@ +use std::collections::BTreeSet; + +pub trait ConfigPrivate { + fn types(&self) -> BTreeSet; + fn optional_types(&self) -> BTreeSet; + fn has_list_or_tree(&self) -> bool; +} + +pub trait ObjectPrivate { + fn contains_object(&self) -> bool; + fn column_count(&self) -> usize; +} + +pub trait TypeName { + fn type_name(&self) -> &str; +} + +pub trait TypePrivate { + fn is_object(&self) -> bool; + fn is_complex(&self) -> bool; + fn name(&self) -> &str; + fn cpp_set_type(&self) -> &str; + fn c_set_type(&self) -> &str; + fn rust_type(&self) -> &str; + fn rust_type_init(&self) -> &str; +} + +pub trait PropertyPrivate { + fn is_object(&self) -> bool; + fn is_complex(&self) -> bool; + fn c_get_type(&self) -> String; +} + +pub trait SimpleTypePrivate { + fn name(&self) -> &str; + fn cpp_set_type(&self) -> &str; + fn c_set_type(&self) -> &str; + fn rust_type(&self) -> &str; + fn rust_type_init(&self) -> &str; + fn is_complex(self) -> bool; +} + +pub trait ItemPropertyPrivate { + fn is_complex(&self) -> bool; + fn cpp_set_type(&self) -> String; + fn c_get_type(&self) -> String; + fn c_set_type(&self) -> &str; +} diff --git a/src/cpp.rs b/src/cpp.rs index 01ece0d..d03c0be 100644 --- a/src/cpp.rs +++ b/src/cpp.rs @@ -1,4 +1,5 @@ -use configuration::{Config, Function, ItemProperty, Object, ObjectType, Type}; +use configuration::*; +use configuration_private::*; use std::io::{Result, Write}; use util::{snake_case, write_if_different}; @@ -421,7 +422,7 @@ fn write_cpp_object(w: &mut Vec, o: &Object, conf: &Config) -> Result<()> { )?; if o.object_type != ObjectType::Object { writeln!(w, "void {}::initHeaderData() {{", o.name)?; - for col in 0..o.column_count { + for col in 0..o.column_count() { for (name, ip) in &o.item_properties { let empty = Vec::new(); let roles = ip.roles.get(col).unwrap_or(&empty); @@ -893,7 +894,9 @@ void {0}::fetchMore(const QModelIndex &parent) }} }} void {0}::updatePersistentIndexes() {{}}", - o.name, lcname, o.column_count + o.name, + lcname, + o.column_count() )?; } else { writeln!( @@ -1002,7 +1005,9 @@ void {0}::updatePersistentIndexes() {{ }} changePersistentIndexList(from, to); }}", - o.name, lcname, o.column_count + o.name, + lcname, + o.column_count() )?; } writeln!( @@ -1017,7 +1022,7 @@ Qt::ItemFlags {0}::flags(const QModelIndex &i) const auto flags = QAbstractItemModel::flags(i);", o.name, lcname )?; - for col in 0..o.column_count { + for col in 0..o.column_count() { if is_column_write(o, col) { writeln!(w, " if (i.column() == {}) {{", col)?; writeln!(w, " flags |= Qt::ItemIsEditable;\n }}")?; @@ -1036,7 +1041,7 @@ Qt::ItemFlags {0}::flags(const QModelIndex &i) const o.name )?; - for col in 0..o.column_count { + for col in 0..o.column_count() { writeln!(w, " case {}:", col)?; writeln!(w, " switch (role) {{")?; for (i, (name, ip)) in o.item_properties.iter().enumerate() { @@ -1125,7 +1130,7 @@ bool {0}::setHeaderData(int section, Qt::Orientation orientation, const QVariant "bool {}::setData(const QModelIndex &index, const QVariant &value, int role)\n{{", o.name )?; - for col in 0..o.column_count { + for col in 0..o.column_count() { if !is_column_write(o, col) { continue; } @@ -1294,7 +1299,7 @@ fn constructor_args(w: &mut Vec, prefix: &str, o: &Object, conf: &Config) -> o->endRemoveRows(); }}", o.name, - o.column_count - 1 + o.column_count() - 1 )?; } if o.object_type == ObjectType::Tree { @@ -1368,7 +1373,7 @@ fn constructor_args(w: &mut Vec, prefix: &str, o: &Object, conf: &Config) -> }}", o.name, lcname, - o.column_count - 1 + o.column_count() - 1 )?; } Ok(()) diff --git a/src/lib.rs b/src/lib.rs index 2677df8..72e5f08 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,8 @@ extern crate regex; extern crate serde_derive; extern crate serde_json; -mod configuration; +pub mod configuration; +mod configuration_private; mod cpp; mod rust; mod util; @@ -11,8 +12,17 @@ mod util; use std::error::Error; use std::fmt::Display; use std::path::Path; +use configuration::Config; -pub fn generate_rust_qt_bindings + Display>( +pub fn generate_bindings(config: &Config) -> Result<(), Box> { + cpp::write_header(config)?; + cpp::write_cpp(config)?; + rust::write_interface(config)?; + rust::write_implementation(config)?; + Ok(()) +} + +pub fn generate_bindings_from_config_file + Display>( config_file: P, overwrite_implementation: bool, ) -> Result<(), Box> { @@ -20,9 +30,5 @@ pub fn generate_rust_qt_bindings + Display>( if overwrite_implementation { config.overwrite_implementation = true; } - cpp::write_header(&config)?; - cpp::write_cpp(&config)?; - rust::write_interface(&config)?; - rust::write_implementation(&config)?; - Ok(()) + generate_bindings(&config) } diff --git a/src/rust.rs b/src/rust.rs index c13d003..e1d8186 100644 --- a/src/rust.rs +++ b/src/rust.rs @@ -1,6 +1,5 @@ -use configuration::{ - Config, Function, ItemProperty, Object, ObjectType, Property, SimpleType, Type, -}; +use configuration::*; +use configuration_private::*; use std::io::{Result, Write}; use util::{snake_case, write_if_different};