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 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);
}

View File

@ -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<String> {
impl ConfigPrivate for Config {
fn types(&self) -> BTreeSet<String> {
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<String> {
fn optional_types(&self) -> BTreeSet<String> {
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<String, ItemProperty>,
pub object_type: ObjectType,
pub properties: BTreeMap<String, Property>,
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<u8>",
@ -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<Object>),
}
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<Argument>,
}
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(())

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 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 {
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<u8>, 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<u8>, prefix: &str, o: &Object, conf: &Config) ->
}}",
o.name,
lcname,
o.column_count - 1
o.column_count() - 1
)?;
}
Ok(())

View File

@ -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<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,
overwrite_implementation: bool,
) -> Result<(), Box<Error>> {
@ -20,9 +30,5 @@ pub fn generate_rust_qt_bindings<P: AsRef<Path> + 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)
}

View File

@ -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};