Add function to create bindings from runtime Config object
parent
baaa8f230c
commit
6ee8ca626d
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -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;
|
||||
}
|
23
src/cpp.rs
23
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<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(())
|
||||
|
|
20
src/lib.rs
20
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<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)
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
Loading…
Reference in New Issue