A few fixes for deeply nested objects

This is still broken according to the test test_objects.
master
Jos van den Oever 2017-08-28 09:28:48 +02:00
parent 64bcac54f0
commit c516409326
30 changed files with 342 additions and 61 deletions

View File

@ -4,7 +4,7 @@ version = "0.1.0"
[dependencies]
libc = "*"
sysinfo = "0.3"
sysinfo = "0.3.16"
[lib]
name = "rust"

View File

@ -69,6 +69,7 @@ extern "C" {
void fibonacci_input_set(Fibonacci::Private*, uint);
quint64 fibonacci_result_get(const Fibonacci::Private*);
};
extern "C" {
quint64 fibonacci_list_data_result(const FibonacciList::Private*, int);
void fibonacci_list_sort(FibonacciList::Private*, unsigned char column, Qt::SortOrder order = Qt::AscendingOrder);
@ -168,16 +169,21 @@ extern "C" {
void (*)(FibonacciList*));
void fibonacci_list_free(FibonacciList::Private*);
};
Fibonacci::Fibonacci(bool /*owned*/, QObject *parent):
QObject(parent),
m_d(0),
m_ownsPrivate(false) {}
m_ownsPrivate(false)
{
}
Fibonacci::Fibonacci(QObject *parent):
QObject(parent),
m_d(fibonacci_new(this,
fibonacciInputChanged,
fibonacciResultChanged)),
m_ownsPrivate(true) {
m_ownsPrivate(true)
{
}
Fibonacci::~Fibonacci() {
@ -199,7 +205,10 @@ quint64 Fibonacci::result() const
FibonacciList::FibonacciList(bool /*owned*/, QObject *parent):
QAbstractItemModel(parent),
m_d(0),
m_ownsPrivate(false) {}
m_ownsPrivate(false)
{
}
FibonacciList::FibonacciList(QObject *parent):
QAbstractItemModel(parent),
m_d(fibonacci_list_new(this,
@ -225,7 +234,8 @@ FibonacciList::FibonacciList(QObject *parent):
o->endRemoveRows();
}
)),
m_ownsPrivate(true) {
m_ownsPrivate(true)
{
connect(this, &FibonacciList::newDataReady, this, [this](const QModelIndex& i) {
fetchMore(i);
}, Qt::QueuedConnection);

View File

@ -5,6 +5,9 @@
#include <QObject>
#include <QAbstractItemModel>
class Fibonacci;
class FibonacciList;
class Fibonacci : public QObject
{
Q_OBJECT

View File

@ -220,10 +220,14 @@ extern "C" {
void (*)(Processes*));
void processes_free(Processes::Private*);
};
Processes::Processes(bool /*owned*/, QObject *parent):
QAbstractItemModel(parent),
m_d(0),
m_ownsPrivate(false) {}
m_ownsPrivate(false)
{
}
Processes::Processes(QObject *parent):
QAbstractItemModel(parent),
m_d(processes_new(this,
@ -264,7 +268,8 @@ Processes::Processes(QObject *parent):
o->endRemoveRows();
}
)),
m_ownsPrivate(true) {
m_ownsPrivate(true)
{
connect(this, &Processes::newDataReady, this, [this](const QModelIndex& i) {
fetchMore(i);
}, Qt::QueuedConnection);

View File

@ -5,6 +5,8 @@
#include <QObject>
#include <QAbstractItemModel>
class Processes;
class Processes : public QAbstractItemModel
{
Q_OBJECT

View File

@ -189,10 +189,14 @@ extern "C" {
void (*)(TimeSeries*));
void time_series_free(TimeSeries::Private*);
};
TimeSeries::TimeSeries(bool /*owned*/, QObject *parent):
QAbstractItemModel(parent),
m_d(0),
m_ownsPrivate(false) {}
m_ownsPrivate(false)
{
}
TimeSeries::TimeSeries(QObject *parent):
QAbstractItemModel(parent),
m_d(time_series_new(this,
@ -218,7 +222,8 @@ TimeSeries::TimeSeries(QObject *parent):
o->endRemoveRows();
}
)),
m_ownsPrivate(true) {
m_ownsPrivate(true)
{
connect(this, &TimeSeries::newDataReady, this, [this](const QModelIndex& i) {
fetchMore(i);
}, Qt::QueuedConnection);

View File

@ -5,6 +5,8 @@
#include <QObject>
#include <QAbstractItemModel>
class TimeSeries;
class TimeSeries : public QAbstractItemModel
{
Q_OBJECT

View File

@ -240,10 +240,14 @@ extern "C" {
void tree_path_set(Tree::Private*, qstring_t);
void tree_path_set_none(Tree::Private*);
};
Tree::Tree(bool /*owned*/, QObject *parent):
QAbstractItemModel(parent),
m_d(0),
m_ownsPrivate(false) {}
m_ownsPrivate(false)
{
}
Tree::Tree(QObject *parent):
QAbstractItemModel(parent),
m_d(tree_new(this,
@ -285,7 +289,8 @@ Tree::Tree(QObject *parent):
o->endRemoveRows();
}
)),
m_ownsPrivate(true) {
m_ownsPrivate(true)
{
connect(this, &Tree::newDataReady, this, [this](const QModelIndex& i) {
fetchMore(i);
}, Qt::QueuedConnection);

View File

@ -5,6 +5,8 @@
#include <QObject>
#include <QAbstractItemModel>
class Tree;
class Tree : public QAbstractItemModel
{
Q_OBJECT

View File

@ -325,7 +325,7 @@ class %1 : public %3
Q_OBJEC%2
)").arg(o.name, "T", baseType(o));
for (auto object: conf.objects) {
if (object.containsObject()) {
if (object.containsObject() && o.name != object.name) {
h << " friend class " << object.name << ";\n";
}
}
@ -414,12 +414,13 @@ QString changedF(const Object& o, const Property& p) {
return lowerInitial(o.name) + upperInitial(p.name) + "Changed";
}
void constructorArgs(QTextStream& cpp, const Object& o, const Configuration& conf) {
void constructorArgs(QTextStream& cpp, const QString& prefix, const Object& o, const Configuration& conf) {
const QString lcname(snakeCase(o.name));
for (const Property& p: o.properties) {
if (p.type.type == BindingType::Object) {
cpp << ", m_" << p.name;
constructorArgs(cpp, conf.findObject(p.type.name), conf);
cpp << ", " << prefix << "m_" << p.name;
constructorArgs(cpp, "m_" + p.name + "->",
conf.findObject(p.type.name), conf);
} else {
cpp << ",\n " << changedF(o, p);
}
@ -521,6 +522,40 @@ void writeObjectCDecl(QTextStream& cpp, const Object& o, const Configuration& co
}
}
void initializeMembersEmpty(QTextStream& cpp, const Object& o, const Configuration& conf)
{
for (const Property& p: o.properties) {
if (p.type.type == BindingType::Object) {
initializeMembersEmpty(cpp, conf.findObject(p.type.name), conf);
cpp << QString(" %1m_%2(new %3(false, this)),\n")
.arg(p.name, p.type.name);
}
}
}
void initializeMembersZero(QTextStream& cpp, const Object& o, const Configuration& conf)
{
for (const Property& p: o.properties) {
if (p.type.type == BindingType::Object) {
cpp << QString(" m_%1(new %2(false, this)),\n")
.arg(p.name, p.type.name);
}
}
}
void initializeMembers(QTextStream& cpp, const QString& prefix, const Object& o, const Configuration& conf)
{
for (const Property& p: o.properties) {
if (p.type.type == BindingType::Object) {
initializeMembers(cpp, "m_" + p.name + "->",
conf.findObject(p.type.name), conf);
cpp << QString(" %1m_%2->m_d = %3_%2_get(%1m_d);\n")
.arg(prefix, p.name, snakeCase(o.name));
}
}
}
void writeCppObject(QTextStream& cpp, const Object& o, const Configuration& conf) {
const QString lcname(snakeCase(o.name));
cpp << QString("%1::%1(bool /*owned*/, QObject *parent):\n %2(parent),")
@ -531,24 +566,14 @@ void writeCppObject(QTextStream& cpp, const Object& o, const Configuration& conf
.arg(p.name, p.type.name);
}
}
cpp << " m_d(0),\n m_ownsPrivate(false) {}\n";
cpp << " m_d(0),\n m_ownsPrivate(false)\n{\n}\n\n";
cpp << QString("%1::%1(QObject *parent):\n %2(parent),")
.arg(o.name, baseType(o)) << endl;
for (const Property& p: o.properties) {
if (p.type.type == BindingType::Object) {
cpp << QString(" m_%1(new %2(false, this)),\n")
.arg(p.name, p.type.name);
}
}
initializeMembersZero(cpp, o, conf);
cpp << QString(" m_d(%1_new(this").arg(lcname);
constructorArgs(cpp, o, conf);
cpp << ")),\n m_ownsPrivate(true) {\n";
for (const Property& p: o.properties) {
if (p.type.type == BindingType::Object) {
cpp << QString(" m_%1->m_d = %2_%1_get(this->m_d);\n")
.arg(p.name, snakeCase(o.name));
}
}
constructorArgs(cpp, "", o, conf);
cpp << ")),\n m_ownsPrivate(true)\n{\n";
initializeMembers(cpp, "", o, conf);
if (o.type != ObjectType::Object) {
cpp << QString(R"( connect(this, &%1::newDataReady, this, [this](const QModelIndex& i) {
fetchMore(i);
@ -612,12 +637,11 @@ void writeHeader(const Configuration& conf) {
#include <QObject>
#include <QAbstractItemModel>
)").arg(guard);
for (auto object: conf.objects) {
if (object.containsObject()) {
h << "class " << object.name << ";\n";
}
h << "class " << object.name << ";\n";
}
for (auto object: conf.objects) {
writeHeaderObject(h, object, conf);
@ -706,7 +730,7 @@ void set_qbytearray(QByteArray* v, qbytearray_t* val) {
cpp << "extern \"C\" {\n";
writeObjectCDecl(cpp, object, conf);
cpp << "};" << endl;
cpp << "};\n" << endl;
}
for (auto object: conf.objects) {

View File

@ -204,17 +204,19 @@ parseConfiguration(const QString& path) {
c.hFile = QFileInfo(c.cppFile.dir(), c.cppFile.completeBaseName() + ".h");
const QJsonObject& object = o.value("objects").toObject();
for (const QString& key: object.keys()) {
Object o = parseObject(key, object[key].toObject());
c.objects.append(o);
bindingTypeProperties().append({
.type = BindingType::Object,
.name = o.name,
.cppSetType = o.name,
.cSetType = o.name,
.rustType = o.name,
.name = key,
.cppSetType = key,
.cSetType = key,
.rustType = key,
.rustTypeInit = "",
});
}
for (const QString& key: object.keys()) {
Object o = parseObject(key, object[key].toObject());
c.objects.append(o);
}
const QJsonObject rust = o.value("rust").toObject();
c.rustdir = QDir(base.filePath(rust.value("dir").toString()));
c.interfaceModule = rust.value("interfaceModule").toString();

View File

@ -767,7 +767,7 @@ void writeRustImplementationObject(QTextStream& r, const Object& o) {
}
}
}
r << "}\n";
r << "}\n\n";
}
void writeRustImplementation(const Configuration& conf) {

View File

@ -36,3 +36,4 @@ impl PersonsTrait for Persons {
true
}
}

View File

@ -26,3 +26,4 @@ impl PersonTrait for Person {
self.emit.user_name_changed();
}
}

View File

@ -89,3 +89,4 @@ impl ObjectTrait for Object {
self.emit.uinteger_changed();
}
}

View File

@ -3,6 +3,29 @@
#![allow(dead_code)]
use interface::*;
pub struct Group {
emit: GroupEmitter,
person: Person,
}
impl GroupTrait for Group {
fn create(emit: GroupEmitter, person: Person) -> Group {
Group {
emit: emit,
person: person,
}
}
fn emit(&self) -> &GroupEmitter {
&self.emit
}
fn get_person(&self) -> &Person {
&self.person
}
fn get_mut_person(&mut self) -> &mut Person {
&mut self.person
}
}
pub struct InnerObject {
emit: InnerObjectEmitter,
description: String,
@ -26,6 +49,7 @@ impl InnerObjectTrait for InnerObject {
self.emit.description_changed();
}
}
pub struct Person {
emit: PersonEmitter,
object: InnerObject,
@ -48,3 +72,4 @@ impl PersonTrait for Person {
&mut self.object
}
}

View File

@ -38,6 +38,61 @@ impl<'a> From<&'a String> for QString {
}
}
pub struct GroupQObject {}
#[derive (Clone)]
pub struct GroupEmitter {
qobject: Arc<Mutex<*const GroupQObject>>,
}
unsafe impl Send for GroupEmitter {}
impl GroupEmitter {
fn clear(&self) {
*self.qobject.lock().unwrap() = null();
}
}
pub trait GroupTrait {
fn create(emit: GroupEmitter,
person: Person) -> Self;
fn emit(&self) -> &GroupEmitter;
fn get_person(&self) -> &Person;
fn get_mut_person(&mut self) -> &mut Person;
}
#[no_mangle]
pub extern "C" fn group_new(group: *mut GroupQObject, person: *mut PersonQObject, object: *mut InnerObjectQObject,
description_changed: fn(*const InnerObjectQObject))
-> *mut Group {
let object_emit = InnerObjectEmitter {
qobject: Arc::new(Mutex::new(object)),
description_changed: description_changed,
};
let d_object = InnerObject::create(object_emit);
let person_emit = PersonEmitter {
qobject: Arc::new(Mutex::new(person)),
};
let d_person = Person::create(person_emit,
d_object);
let group_emit = GroupEmitter {
qobject: Arc::new(Mutex::new(group)),
};
let d_group = Group::create(group_emit,
d_person);
Box::into_raw(Box::new(d_group))
}
#[no_mangle]
pub unsafe extern "C" fn group_free(ptr: *mut Group) {
Box::from_raw(ptr).emit().clear();
}
#[no_mangle]
pub unsafe extern "C" fn group_person_get(ptr: *mut Group) -> *mut Person {
(&mut *ptr).get_mut_person()
}
pub struct InnerObjectQObject {}
#[derive (Clone)]

View File

@ -45,3 +45,4 @@ impl PersonsTrait for Persons {
true
}
}

View File

@ -164,10 +164,14 @@ extern "C" {
void (*)(Persons*));
void persons_free(Persons::Private*);
};
Persons::Persons(bool /*owned*/, QObject *parent):
QAbstractItemModel(parent),
m_d(0),
m_ownsPrivate(false) {}
m_ownsPrivate(false)
{
}
Persons::Persons(QObject *parent):
QAbstractItemModel(parent),
m_d(persons_new(this,
@ -193,7 +197,8 @@ Persons::Persons(QObject *parent):
o->endRemoveRows();
}
)),
m_ownsPrivate(true) {
m_ownsPrivate(true)
{
connect(this, &Persons::newDataReady, this, [this](const QModelIndex& i) {
fetchMore(i);
}, Qt::QueuedConnection);

View File

@ -5,6 +5,8 @@
#include <QObject>
#include <QAbstractItemModel>
class Persons;
class Persons : public QAbstractItemModel
{
Q_OBJECT

View File

@ -64,15 +64,20 @@ extern "C" {
void person_user_name_get(const Person::Private*, QString*, qstring_set);
void person_user_name_set(Person::Private*, qstring_t);
};
Person::Person(bool /*owned*/, QObject *parent):
QObject(parent),
m_d(0),
m_ownsPrivate(false) {}
m_ownsPrivate(false)
{
}
Person::Person(QObject *parent):
QObject(parent),
m_d(person_new(this,
personUserNameChanged)),
m_ownsPrivate(true) {
m_ownsPrivate(true)
{
}
Person::~Person() {

View File

@ -5,6 +5,8 @@
#include <QObject>
#include <QAbstractItemModel>
class Person;
class Person : public QObject
{
Q_OBJECT

View File

@ -108,10 +108,14 @@ extern "C" {
quint32 object_uinteger_get(const Object::Private*);
void object_uinteger_set(Object::Private*, uint);
};
Object::Object(bool /*owned*/, QObject *parent):
QObject(parent),
m_d(0),
m_ownsPrivate(false) {}
m_ownsPrivate(false)
{
}
Object::Object(QObject *parent):
QObject(parent),
m_d(object_new(this,
@ -123,7 +127,8 @@ Object::Object(QObject *parent):
objectStringChanged,
objectU64Changed,
objectUintegerChanged)),
m_ownsPrivate(true) {
m_ownsPrivate(true)
{
}
Object::~Object() {

View File

@ -5,6 +5,8 @@
#include <QObject>
#include <QAbstractItemModel>
class Object;
class Object : public QObject
{
Q_OBJECT

View File

@ -6,23 +6,26 @@ class TestRustObjects : public QObject
{
Q_OBJECT
private slots:
void testConstructor();
void testStringGetter();
void testStringSetter();
void testOneLevelConstructor();
void testOneLevelStringGetter();
void testOneLevelStringSetter();
void testTwoLevelsConstructor();
void testTwoLevelsStringGetter();
void testTwoLevelsStringSetter();
};
void TestRustObjects::testConstructor()
void TestRustObjects::testOneLevelConstructor()
{
Person person;
}
void TestRustObjects::testStringGetter()
void TestRustObjects::testOneLevelStringGetter()
{
Person person;
person.object()->setDescription("Konqi");
}
void TestRustObjects::testStringSetter()
void TestRustObjects::testOneLevelStringSetter()
{
// GIVEN
Person person;
@ -37,5 +40,31 @@ void TestRustObjects::testStringSetter()
QCOMPARE(person.object()->description(), QString("Konqi"));
}
void TestRustObjects::testTwoLevelsConstructor()
{
Group group;
}
void TestRustObjects::testTwoLevelsStringGetter()
{
Group group;
group.person()->object()->setDescription("Konqi");
}
void TestRustObjects::testTwoLevelsStringSetter()
{
// GIVEN
Group group;
QSignalSpy spy(group.person()->object(), &InnerObject::descriptionChanged);
// WHEN
group.person()->object()->setDescription("Konqi");
// THEN
QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1);
QCOMPARE(group.person()->object()->description(), QString("Konqi"));
}
QTEST_MAIN(TestRustObjects)
#include "test_objects.moc"

View File

@ -23,6 +23,14 @@
"type": "InnerObject"
}
}
},
"Group": {
"type": "Object",
"properties": {
"person": {
"type": "Person"
}
}
}
}
}

View File

@ -58,26 +58,70 @@ typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*);
void set_qbytearray(QByteArray* v, qbytearray_t* val) {
*v = *val;
}
extern "C" {
Group::Private* group_new(Group*, Person*, InnerObject*, void (*)(InnerObject*));
void group_free(Group::Private*);
Person::Private* group_person_get(const Group::Private*);
};
extern "C" {
InnerObject::Private* inner_object_new(InnerObject*, void (*)(InnerObject*));
void inner_object_free(InnerObject::Private*);
void inner_object_description_get(const InnerObject::Private*, QString*, qstring_set);
void inner_object_description_set(InnerObject::Private*, qstring_t);
};
extern "C" {
Person::Private* person_new(Person*, InnerObject*, void (*)(InnerObject*));
void person_free(Person::Private*);
InnerObject::Private* person_object_get(const Person::Private*);
};
Group::Group(bool /*owned*/, QObject *parent):
QObject(parent),
m_person(new Person(false, this)),
m_d(0),
m_ownsPrivate(false)
{
}
Group::Group(QObject *parent):
QObject(parent),
m_person(new Person(false, this)),
m_d(group_new(this, m_person, m_person->m_object,
innerObjectDescriptionChanged)),
m_ownsPrivate(true)
{
m_person->m_object->m_d = person_object_get(m_person->m_d);
m_person->m_d = group_person_get(m_d);
}
Group::~Group() {
if (m_ownsPrivate) {
group_free(m_d);
}
}
const Person* Group::person() const
{
return m_person;
}
Person* Group::person()
{
return m_person;
}
InnerObject::InnerObject(bool /*owned*/, QObject *parent):
QObject(parent),
m_d(0),
m_ownsPrivate(false) {}
m_ownsPrivate(false)
{
}
InnerObject::InnerObject(QObject *parent):
QObject(parent),
m_d(inner_object_new(this,
innerObjectDescriptionChanged)),
m_ownsPrivate(true) {
m_ownsPrivate(true)
{
}
InnerObject::~InnerObject() {
@ -98,14 +142,18 @@ Person::Person(bool /*owned*/, QObject *parent):
QObject(parent),
m_object(new InnerObject(false, this)),
m_d(0),
m_ownsPrivate(false) {}
m_ownsPrivate(false)
{
}
Person::Person(QObject *parent):
QObject(parent),
m_object(new InnerObject(false, this)),
m_d(person_new(this, m_object,
innerObjectDescriptionChanged)),
m_ownsPrivate(true) {
m_object->m_d = person_object_get(this->m_d);
m_ownsPrivate(true)
{
m_object->m_d = person_object_get(m_d);
}
Person::~Person() {

View File

@ -4,11 +4,35 @@
#include <QObject>
#include <QAbstractItemModel>
class Group;
class InnerObject;
class Person;
class Group : public QObject
{
Q_OBJECT
friend class Person;
public:
class Private;
private:
Person* const m_person;
Private * m_d;
bool m_ownsPrivate;
Q_PROPERTY(Person* person READ person FINAL)
explicit Group(bool owned, QObject *parent);
public:
explicit Group(QObject *parent = nullptr);
~Group();
const Person* person() const;
Person* person();
signals:
};
class InnerObject : public QObject
{
Q_OBJECT
friend class Group;
friend class Person;
public:
class Private;
@ -29,7 +53,7 @@ signals:
class Person : public QObject
{
Q_OBJECT
friend class Person;
friend class Group;
public:
class Private;
private:

View File

@ -182,10 +182,14 @@ extern "C" {
void (*)(Persons*));
void persons_free(Persons::Private*);
};
Persons::Persons(bool /*owned*/, QObject *parent):
QAbstractItemModel(parent),
m_d(0),
m_ownsPrivate(false) {}
m_ownsPrivate(false)
{
}
Persons::Persons(QObject *parent):
QAbstractItemModel(parent),
m_d(persons_new(this,
@ -226,7 +230,8 @@ Persons::Persons(QObject *parent):
o->endRemoveRows();
}
)),
m_ownsPrivate(true) {
m_ownsPrivate(true)
{
connect(this, &Persons::newDataReady, this, [this](const QModelIndex& i) {
fetchMore(i);
}, Qt::QueuedConnection);

View File

@ -5,6 +5,8 @@
#include <QObject>
#include <QAbstractItemModel>
class Persons;
class Persons : public QAbstractItemModel
{
Q_OBJECT