Add function to create bindings from runtime Config object

master
Jos van den Oever 2018-09-28 23:23:40 +02:00
parent baaa8f230c
commit 6ee8ca626d
6 changed files with 133 additions and 69 deletions

View File

@ -1,6 +1,6 @@
extern crate clap; extern crate clap;
extern crate rust_qt_binding_generator; extern crate rust_qt_binding_generator;
use clap::{Arg, App}; use clap::{App, Arg};
use rust_qt_binding_generator::*; use rust_qt_binding_generator::*;
fn main() { fn main() {
@ -11,19 +11,17 @@ fn main() {
Arg::with_name("overwrite-implementation") Arg::with_name("overwrite-implementation")
.long("overwrite-implementation") .long("overwrite-implementation")
.help("Overwrite existing implementation."), .help("Overwrite existing implementation."),
) ).arg(
.arg(
Arg::with_name("config") Arg::with_name("config")
.multiple(true) .multiple(true)
.required(true) .required(true)
.takes_value(true) .takes_value(true)
.help("Configuration file(s)"), .help("Configuration file(s)"),
) ).get_matches();
.get_matches();
let overwrite_implementation = matches.is_present("overwrite-implementation"); let overwrite_implementation = matches.is_present("overwrite-implementation");
for config in matches.values_of("config").unwrap() { 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); eprintln!("{}", e);
::std::process::exit(1); ::std::process::exit(1);
} }

View File

@ -1,3 +1,4 @@
use configuration_private::*;
use serde_json; use serde_json;
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
use std::error::Error; use std::error::Error;
@ -64,8 +65,8 @@ pub struct Config {
pub overwrite_implementation: bool, pub overwrite_implementation: bool,
} }
impl Config { impl ConfigPrivate for Config {
pub fn types(&self) -> BTreeSet<String> { fn types(&self) -> BTreeSet<String> {
let mut ops = BTreeSet::new(); let mut ops = BTreeSet::new();
for o in self.objects.values() { for o in self.objects.values() {
for p in o.properties.values() { for p in o.properties.values() {
@ -83,7 +84,7 @@ impl Config {
} }
ops ops
} }
pub fn optional_types(&self) -> BTreeSet<String> { fn optional_types(&self) -> BTreeSet<String> {
let mut ops = BTreeSet::new(); let mut ops = BTreeSet::new();
for o in self.objects.values() { for o in self.objects.values() {
for p in o.properties.values() { for p in o.properties.values() {
@ -102,7 +103,7 @@ impl Config {
} }
ops ops
} }
pub fn has_list_or_tree(&self) -> bool { fn has_list_or_tree(&self) -> bool {
self.objects self.objects
.values() .values()
.any(|o| o.object_type == ObjectType::List || o.object_type == ObjectType::Tree) .any(|o| o.object_type == ObjectType::List || o.object_type == ObjectType::Tree)
@ -116,13 +117,19 @@ pub struct Object {
pub item_properties: BTreeMap<String, ItemProperty>, pub item_properties: BTreeMap<String, ItemProperty>,
pub object_type: ObjectType, pub object_type: ObjectType,
pub properties: BTreeMap<String, Property>, pub properties: BTreeMap<String, Property>,
pub column_count: usize,
} }
impl Object { impl ObjectPrivate for Object {
pub fn contains_object(&self) -> bool { fn contains_object(&self) -> bool {
self.properties.values().any(|p| p.is_object()) 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)] #[derive(PartialEq)]
@ -133,22 +140,25 @@ pub struct Property {
pub write: bool, pub write: bool,
} }
impl Property { impl PropertyPrivate for Property {
pub fn is_object(&self) -> bool { fn is_object(&self) -> bool {
self.property_type.is_object() self.property_type.is_object()
} }
pub fn is_complex(&self) -> bool { fn is_complex(&self) -> bool {
self.property_type.is_complex() self.property_type.is_complex()
} }
pub fn type_name(&self) -> &str { fn c_get_type(&self) -> String {
self.property_type.name()
}
pub fn c_get_type(&self) -> String {
let name = self.property_type.name(); let name = self.property_type.name();
name.to_string() + "*, " + &name.to_lowercase() + "_set" name.to_string() + "*, " + &name.to_lowercase() + "_set"
} }
} }
impl TypeName for Property {
fn type_name(&self) -> &str {
self.property_type.name()
}
}
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct Rust { pub struct Rust {
@ -196,8 +206,8 @@ pub enum SimpleType {
QUint64, QUint64,
} }
impl SimpleType { impl SimpleTypePrivate for SimpleType {
pub fn name(&self) -> &str { fn name(&self) -> &str {
match self { match self {
SimpleType::QString => "QString", SimpleType::QString => "QString",
SimpleType::QByteArray => "QByteArray", SimpleType::QByteArray => "QByteArray",
@ -215,7 +225,7 @@ impl SimpleType {
SimpleType::QUint64 => "quint64", SimpleType::QUint64 => "quint64",
} }
} }
pub fn cpp_set_type(&self) -> &str { fn cpp_set_type(&self) -> &str {
match self { match self {
SimpleType::QString => "const QString&", SimpleType::QString => "const QString&",
SimpleType::QByteArray => "const QByteArray&", SimpleType::QByteArray => "const QByteArray&",
@ -233,7 +243,7 @@ impl SimpleType {
SimpleType::QUint64 => "quint64", SimpleType::QUint64 => "quint64",
} }
} }
pub fn c_set_type(&self) -> &str { fn c_set_type(&self) -> &str {
match self { match self {
SimpleType::QString => "qstring_t", SimpleType::QString => "qstring_t",
SimpleType::QByteArray => "qbytearray_t", SimpleType::QByteArray => "qbytearray_t",
@ -251,7 +261,7 @@ impl SimpleType {
SimpleType::QUint64 => "quint64", SimpleType::QUint64 => "quint64",
} }
} }
pub fn rust_type(&self) -> &str { fn rust_type(&self) -> &str {
match self { match self {
SimpleType::QString => "String", SimpleType::QString => "String",
SimpleType::QByteArray => "Vec<u8>", SimpleType::QByteArray => "Vec<u8>",
@ -269,7 +279,7 @@ impl SimpleType {
SimpleType::QUint64 => "u64", SimpleType::QUint64 => "u64",
} }
} }
pub fn rust_type_init(&self) -> &str { fn rust_type_init(&self) -> &str {
match self { match self {
SimpleType::QString => "String::new()", SimpleType::QString => "String::new()",
SimpleType::QByteArray => "Vec::new()", SimpleType::QByteArray => "Vec::new()",
@ -287,7 +297,7 @@ impl SimpleType {
SimpleType::QUint64 => "0", SimpleType::QUint64 => "0",
} }
} }
pub fn is_complex(self) -> bool { fn is_complex(self) -> bool {
self == SimpleType::QString || self == SimpleType::QByteArray self == SimpleType::QString || self == SimpleType::QByteArray
} }
} }
@ -298,46 +308,46 @@ pub enum Type {
Object(Rc<Object>), Object(Rc<Object>),
} }
impl Type { impl TypePrivate for Type {
pub fn is_object(&self) -> bool { fn is_object(&self) -> bool {
if let Type::Object(_) = self { if let Type::Object(_) = self {
true true
} else { } else {
false false
} }
} }
pub fn is_complex(&self) -> bool { fn is_complex(&self) -> bool {
if let Type::Simple(simple) = self { if let Type::Simple(simple) = self {
simple.is_complex() simple.is_complex()
} else { } else {
false false
} }
} }
pub fn name(&self) -> &str { fn name(&self) -> &str {
match self { match self {
Type::Simple(s) => s.name(), Type::Simple(s) => s.name(),
Type::Object(o) => &o.name, Type::Object(o) => &o.name,
} }
} }
pub fn cpp_set_type(&self) -> &str { fn cpp_set_type(&self) -> &str {
match self { match self {
Type::Simple(s) => s.cpp_set_type(), Type::Simple(s) => s.cpp_set_type(),
Type::Object(o) => &o.name, Type::Object(o) => &o.name,
} }
} }
pub fn c_set_type(&self) -> &str { fn c_set_type(&self) -> &str {
match self { match self {
Type::Simple(s) => s.c_set_type(), Type::Simple(s) => s.c_set_type(),
Type::Object(o) => &o.name, Type::Object(o) => &o.name,
} }
} }
pub fn rust_type(&self) -> &str { fn rust_type(&self) -> &str {
match self { match self {
Type::Simple(s) => s.rust_type(), Type::Simple(s) => s.rust_type(),
Type::Object(o) => &o.name, Type::Object(o) => &o.name,
} }
} }
pub fn rust_type_init(&self) -> &str { fn rust_type_init(&self) -> &str {
match self { match self {
Type::Simple(s) => s.rust_type_init(), Type::Simple(s) => s.rust_type_init(),
Type::Object(_) => unimplemented!(), Type::Object(_) => unimplemented!(),
@ -360,25 +370,28 @@ pub struct ItemProperty {
pub write: bool, pub write: bool,
} }
impl ItemProperty { impl TypeName for ItemProperty {
pub fn type_name(&self) -> &str { fn type_name(&self) -> &str {
self.item_property_type.name() 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() 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(); let mut t = self.item_property_type.cpp_set_type().to_string();
if self.optional { if self.optional {
t = "option_".to_string() + &t; t = "option_".to_string() + &t;
} }
t t
} }
pub fn c_get_type(&self) -> String { fn c_get_type(&self) -> String {
let name = self.item_property_type.name(); let name = self.item_property_type.name();
name.to_string() + "*, " + &name.to_lowercase() + "_set" 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() self.item_property_type.c_set_type()
} }
} }
@ -394,8 +407,8 @@ pub struct Function {
pub arguments: Vec<Argument>, pub arguments: Vec<Argument>,
} }
impl Function { impl TypeName for Function {
pub fn type_name(&self) -> &str { fn type_name(&self) -> &str {
self.return_type.name() self.return_type.name()
} }
} }
@ -408,8 +421,8 @@ pub struct Argument {
pub argument_type: SimpleType, pub argument_type: SimpleType,
} }
impl Argument { impl TypeName for Argument {
pub fn type_name(&self) -> &str { fn type_name(&self) -> &str {
self.argument_type.name() self.argument_type.name()
} }
} }
@ -450,17 +463,12 @@ fn post_process_object(
for p in &a.1.properties { for p in &a.1.properties {
properties.insert(p.0.clone(), post_process_property(p, b, c)?); 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 { let object = Rc::new(Object {
name: a.0.clone(), name: a.0.clone(),
object_type: a.1.object_type, object_type: a.1.object_type,
functions: a.1.functions.clone(), functions: a.1.functions.clone(),
item_properties: a.1.item_properties.clone(), item_properties: a.1.item_properties.clone(),
properties, properties,
column_count,
}); });
b.insert(a.0.clone(), object); b.insert(a.0.clone(), object);
Ok(()) Ok(())

View File

@ -0,0 +1,48 @@
use std::collections::BTreeSet;
pub trait ConfigPrivate {
fn types(&self) -> BTreeSet<String>;
fn optional_types(&self) -> BTreeSet<String>;
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;
}

View File

@ -1,4 +1,5 @@
use configuration::{Config, Function, ItemProperty, Object, ObjectType, Type}; use configuration::*;
use configuration_private::*;
use std::io::{Result, Write}; use std::io::{Result, Write};
use util::{snake_case, write_if_different}; use util::{snake_case, write_if_different};
@ -421,7 +422,7 @@ fn write_cpp_object(w: &mut Vec<u8>, o: &Object, conf: &Config) -> Result<()> {
)?; )?;
if o.object_type != ObjectType::Object { if o.object_type != ObjectType::Object {
writeln!(w, "void {}::initHeaderData() {{", o.name)?; 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 { for (name, ip) in &o.item_properties {
let empty = Vec::new(); let empty = Vec::new();
let roles = ip.roles.get(col).unwrap_or(&empty); let roles = ip.roles.get(col).unwrap_or(&empty);
@ -893,7 +894,9 @@ void {0}::fetchMore(const QModelIndex &parent)
}} }}
}} }}
void {0}::updatePersistentIndexes() {{}}", void {0}::updatePersistentIndexes() {{}}",
o.name, lcname, o.column_count o.name,
lcname,
o.column_count()
)?; )?;
} else { } else {
writeln!( writeln!(
@ -1002,7 +1005,9 @@ void {0}::updatePersistentIndexes() {{
}} }}
changePersistentIndexList(from, to); changePersistentIndexList(from, to);
}}", }}",
o.name, lcname, o.column_count o.name,
lcname,
o.column_count()
)?; )?;
} }
writeln!( writeln!(
@ -1017,7 +1022,7 @@ Qt::ItemFlags {0}::flags(const QModelIndex &i) const
auto flags = QAbstractItemModel::flags(i);", auto flags = QAbstractItemModel::flags(i);",
o.name, lcname o.name, lcname
)?; )?;
for col in 0..o.column_count { for col in 0..o.column_count() {
if is_column_write(o, col) { if is_column_write(o, col) {
writeln!(w, " if (i.column() == {}) {{", col)?; writeln!(w, " if (i.column() == {}) {{", col)?;
writeln!(w, " flags |= Qt::ItemIsEditable;\n }}")?; writeln!(w, " flags |= Qt::ItemIsEditable;\n }}")?;
@ -1036,7 +1041,7 @@ Qt::ItemFlags {0}::flags(const QModelIndex &i) const
o.name o.name
)?; )?;
for col in 0..o.column_count { for col in 0..o.column_count() {
writeln!(w, " case {}:", col)?; writeln!(w, " case {}:", col)?;
writeln!(w, " switch (role) {{")?; writeln!(w, " switch (role) {{")?;
for (i, (name, ip)) in o.item_properties.iter().enumerate() { 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{{", "bool {}::setData(const QModelIndex &index, const QVariant &value, int role)\n{{",
o.name o.name
)?; )?;
for col in 0..o.column_count { for col in 0..o.column_count() {
if !is_column_write(o, col) { if !is_column_write(o, col) {
continue; continue;
} }
@ -1294,7 +1299,7 @@ fn constructor_args(w: &mut Vec<u8>, prefix: &str, o: &Object, conf: &Config) ->
o->endRemoveRows(); o->endRemoveRows();
}}", }}",
o.name, o.name,
o.column_count - 1 o.column_count() - 1
)?; )?;
} }
if o.object_type == ObjectType::Tree { if o.object_type == ObjectType::Tree {
@ -1368,7 +1373,7 @@ fn constructor_args(w: &mut Vec<u8>, prefix: &str, o: &Object, conf: &Config) ->
}}", }}",
o.name, o.name,
lcname, lcname,
o.column_count - 1 o.column_count() - 1
)?; )?;
} }
Ok(()) Ok(())

View File

@ -3,7 +3,8 @@ extern crate regex;
extern crate serde_derive; extern crate serde_derive;
extern crate serde_json; extern crate serde_json;
mod configuration; pub mod configuration;
mod configuration_private;
mod cpp; mod cpp;
mod rust; mod rust;
mod util; mod util;
@ -11,8 +12,17 @@ mod util;
use std::error::Error; use std::error::Error;
use std::fmt::Display; use std::fmt::Display;
use std::path::Path; use std::path::Path;
use configuration::Config;
pub fn generate_rust_qt_bindings<P: AsRef<Path> + Display>( pub fn generate_bindings(config: &Config) -> Result<(), Box<Error>> {
cpp::write_header(config)?;
cpp::write_cpp(config)?;
rust::write_interface(config)?;
rust::write_implementation(config)?;
Ok(())
}
pub fn generate_bindings_from_config_file<P: AsRef<Path> + Display>(
config_file: P, config_file: P,
overwrite_implementation: bool, overwrite_implementation: bool,
) -> Result<(), Box<Error>> { ) -> Result<(), Box<Error>> {
@ -20,9 +30,5 @@ pub fn generate_rust_qt_bindings<P: AsRef<Path> + Display>(
if overwrite_implementation { if overwrite_implementation {
config.overwrite_implementation = true; config.overwrite_implementation = true;
} }
cpp::write_header(&config)?; generate_bindings(&config)
cpp::write_cpp(&config)?;
rust::write_interface(&config)?;
rust::write_implementation(&config)?;
Ok(())
} }

View File

@ -1,6 +1,5 @@
use configuration::{ use configuration::*;
Config, Function, ItemProperty, Object, ObjectType, Property, SimpleType, Type, use configuration_private::*;
};
use std::io::{Result, Write}; use std::io::{Result, Write};
use util::{snake_case, write_if_different}; use util::{snake_case, write_if_different};