diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c5d38e..3ce096f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,12 @@ include(KDECMakeSettings) include(KDECompilerSettings) include(FeatureSummary) +#add_custom_target(rust +# OUTPUT "${CMAKE_SOURCE_DIR}/target/debug/librust.a" +# COMMAND cargo build +# COMMAND cargo build --release +# DEPENDS + set_directory_properties(PROPERTIES EP_PREFIX ${CMAKE_BINARY_DIR}/Rust) ExternalProject_Add( diff --git a/common-rust/src/implementation.rs b/common-rust/src/implementation.rs index aefa8ba..96aebd7 100644 --- a/common-rust/src/implementation.rs +++ b/common-rust/src/implementation.rs @@ -1,14 +1,16 @@ use interface::*; +use types::*; +use libc::{c_int}; pub struct Hello { - notifier: HelloNotifier, + emit: HelloEmitter, hello: String, } impl HelloTrait for Hello { - fn create(notifier: HelloNotifier) -> Self { + fn create(emit: HelloEmitter) -> Self { Hello { - notifier: notifier, + emit: emit, hello: String::new() } } @@ -17,7 +19,7 @@ impl HelloTrait for Hello { } fn set_hello(&mut self, value: String) { self.hello = value; - self.notifier.hello_changed(); + self.emit.hello_changed(); } } @@ -27,13 +29,29 @@ impl Drop for Hello { } pub struct RItemModel { - notifier: RItemModelNotifier + emit: RItemModelEmitter, +// string: String } impl RItemModelTrait for RItemModel { - fn create(notifier: RItemModelNotifier) -> Self { + fn create(emit: RItemModelEmitter) -> Self { RItemModel { - notifier: notifier + emit: emit } } + fn column_count(&self, parent: QModelIndex) -> c_int { + if parent.is_valid() { 0 } else { 2 } + } + fn row_count(&self, parent: QModelIndex) -> c_int { + if parent.is_valid() { 0 } else { 2 } + } + fn index(&self, row: i32, column: i32, parent: QModelIndex) -> QModelIndex { + QModelIndex::flat(row, column) + } + fn parent(&self, index: QModelIndex) -> QModelIndex { + QModelIndex::invalid() + } + fn data(&self, index: QModelIndex, role: c_int) -> Variant { + Variant::String(String::from("hello")) + } } diff --git a/common-rust/src/interface.rs b/common-rust/src/interface.rs index 910615b..ee06372 100644 --- a/common-rust/src/interface.rs +++ b/common-rust/src/interface.rs @@ -1,35 +1,36 @@ use std::slice; -use libc::{uint8_t, uint16_t, size_t}; +use libc::{c_int, uint8_t, uint16_t, size_t, c_void}; +use types::*; use implementation::Hello; use implementation::RItemModel; pub struct HelloQObject {} -pub struct HelloNotifier { +pub struct HelloEmitter { qobject: *const HelloQObject, hello_changed: fn (*const HelloQObject) } -impl HelloNotifier { +impl HelloEmitter { pub fn hello_changed(&self) { (self.hello_changed)(self.qobject); } } pub trait HelloTrait { - fn create(notifier: HelloNotifier) -> Self; + fn create(emit: HelloEmitter) -> Self; fn get_hello(&self) -> &String; fn set_hello(&mut self, value: String); } #[no_mangle] pub extern fn hello_new(qobject: *const HelloQObject, changed: fn(*const HelloQObject)) -> *mut Hello { - let notifier = HelloNotifier { + let emit = HelloEmitter { qobject: qobject, hello_changed: changed }; - let hello = Hello::create(notifier); + let hello = Hello::create(emit); Box::into_raw(Box::new(hello)) } @@ -48,40 +49,37 @@ pub extern fn hello_set(ptr: *mut Hello, s: *const uint16_t, len: size_t) { } #[no_mangle] -pub extern fn hello_size(ptr: *mut Hello) -> size_t { +pub extern fn hello_get(ptr: *mut Hello) -> QString { let hello = unsafe { &mut *ptr }; - hello.get_hello().len() -} - -#[no_mangle] -pub extern fn hello_get(ptr: *mut Hello) -> *const uint8_t { - let hello = unsafe { - &mut *ptr - }; - hello.get_hello().as_ptr() + QString::from(hello.get_hello()) } pub struct RItemModelQObject {} -pub struct RItemModelNotifier { +pub struct RItemModelEmitter { qobject: *const RItemModelQObject } -impl RItemModelNotifier { +impl RItemModelEmitter { } pub trait RItemModelTrait { - fn create(notifier: RItemModelNotifier) -> Self; + fn create(emit: RItemModelEmitter) -> Self; + fn column_count(&self, parent: QModelIndex) -> c_int; + fn row_count(&self, parent: QModelIndex) -> c_int; + fn index(&self, row: c_int, column: c_int, parent: QModelIndex) -> QModelIndex; + fn parent(&self, index: QModelIndex) -> QModelIndex; + fn data(&self, index: QModelIndex, role: c_int) -> Variant; } #[no_mangle] pub extern fn ritemmodel_new(qobject: *const RItemModelQObject) -> *mut RItemModel { - let notifier = RItemModelNotifier { + let emit = RItemModelEmitter { qobject: qobject }; - let ritemmodel = RItemModel::create(notifier); + let ritemmodel = RItemModel::create(emit); Box::into_raw(Box::new(ritemmodel)) } @@ -90,3 +88,44 @@ pub extern fn ritemmodel_free(ptr: *mut RItemModel) { if ptr.is_null() { return } unsafe { Box::from_raw(ptr); } } + +#[no_mangle] +pub extern fn ritemmodel_column_count(ptr: *const RItemModel, parent: QModelIndex) -> i32 { + let ritemmodel = unsafe { + &*ptr + }; + ritemmodel.column_count(parent) +} + +#[no_mangle] +pub extern fn ritemmodel_row_count(ptr: *const RItemModel, parent: QModelIndex) -> i32 { + let ritemmodel = unsafe { + &*ptr + }; + ritemmodel.row_count(parent) +} + +#[no_mangle] +pub extern fn ritemmodel_index(ptr: *const RItemModel, row: i32, column: i32, parent: QModelIndex) -> QModelIndex { + let ritemmodel = unsafe { + &*ptr + }; + ritemmodel.index(row, column, parent) +} + +#[no_mangle] +pub extern fn ritemmodel_parent(ptr: *const RItemModel, index: QModelIndex) -> QModelIndex { + let ritemmodel = unsafe { + &*ptr + }; + ritemmodel.parent(index) +} + +#[no_mangle] +pub extern fn ritemmodel_data(ptr: *const RItemModel, index: QModelIndex, role: c_int, d: *mut c_void, set: fn (*mut c_void, &QVariant)) { + let ritemmodel = unsafe { + &*ptr + }; + let data = ritemmodel.data(index, role); + set(d, &QVariant::from(&data)); +} diff --git a/common-rust/src/lib.rs b/common-rust/src/lib.rs index 81b3d35..b6bc619 100644 --- a/common-rust/src/lib.rs +++ b/common-rust/src/lib.rs @@ -1,5 +1,5 @@ extern crate libc; -#[macro_use] +pub mod types; pub mod interface; pub mod implementation; diff --git a/common-rust/src/types.rs b/common-rust/src/types.rs new file mode 100644 index 0000000..af94a81 --- /dev/null +++ b/common-rust/src/types.rs @@ -0,0 +1,100 @@ +use libc::{c_int, c_uint, uint8_t}; +use std::ptr::null; +use std::marker::PhantomData; + +#[repr(C)] +pub struct QString { + data: *const uint8_t, + len: c_int +} + +impl<'a> From<&'a String> for QString { + fn from(string: &'a String) -> QString { + QString { + len: string.len() as c_int, + data: string.as_ptr() + } + } +} + +pub enum Variant { + None, + Bool(bool), + String(String) +} + +/* values from qvariant.h and qmetatype.h */ +#[repr(u32)] +#[derive(Clone, Copy)] +enum VariantType { + Invalid = 0, + Bool = 1, + String = 10, + ByteArray = 12, +} + +#[repr(C)] +pub struct QVariant<'a> { + type_: c_uint, + len: c_int, + data: *const uint8_t, + phantom: PhantomData<&'a u8> +} + +impl<'a> QVariant<'a> { + pub fn type_(&self) -> u32 { + self.type_ as u32 + } +} + +impl<'a> From<&'a Variant> for QVariant<'a> { + fn from(variant: &'a Variant) -> QVariant { + match variant { + &Variant::None => QVariant { + data: null(), + len: 0, + type_: VariantType::Invalid as c_uint, + phantom: PhantomData + }, + &Variant::Bool(v) => QVariant { + data: null(), + len: v as c_int, + type_: VariantType::Bool as c_uint, + phantom: PhantomData + }, + &Variant::String(ref v) => QVariant { + data: v.as_ptr(), + len: v.len() as c_int, + type_: VariantType::String as c_uint, + phantom: PhantomData + } + } + } +} + +#[repr(C)] +pub struct QModelIndex { + row: c_int, + column: c_int, + internal_id: usize +} + +impl QModelIndex { + pub fn invalid() -> QModelIndex { + QModelIndex { + row: -1, + column: -1, + internal_id: 0 + } + } + pub fn flat(row: c_int, column: c_int) -> QModelIndex { + QModelIndex { + row: row, + column: column, + internal_id: 1 + } + } + pub fn is_valid(&self) -> bool { + self.internal_id != 0 && self.row >= 0 && self.column >= 0 + } +} diff --git a/src/RMailObject.cpp b/src/RMailObject.cpp index 43c4901..f56d6ad 100644 --- a/src/RMailObject.cpp +++ b/src/RMailObject.cpp @@ -1,16 +1,79 @@ #include "RMailObject.h" +#include +#include #include #include +namespace { + typedef struct { + private: + const char* data; + int len; + public: + operator QByteArray() const { + return QByteArray(data, len); + } + } qbytearray_t; + struct qstring_t { + private: + const char* data; + int len; + public: + operator QString() const { + return QString::fromUtf8(data, len); + } + }; + typedef struct { + int row; + int column; + uint64_t id; + } qmodelindex_t; + typedef struct qvariant_t { + unsigned int type; + int value; + const char* data; + } qvariant_t; + QVariant variant(const qvariant_t& v) { + switch (v.type) { + case QVariant::Bool: return QVariant((bool)v.value); + case QVariant::String: return QString::fromUtf8(v.data, v.value); + default:; + } + return QVariant(); + } + +/* + qvariant_t variant(const QVariant& v) { + auto t = v.type(); + switch (t) { + case QVariant::Bool: + return { .type = t, .value = { .vbool = 0 } }; + case QVariant::ByteArray: + return { .type = t, .value = { .vbool = 0 } }; + case QVariant::String: + return { .type = t, .value = { .vbool = 0 } }; + default:; + } + return { .type = QVariant::Invalid, .value = { .vbool = false } }; + } +*/ +} + +typedef void (*qvariant_set)(void*, qvariant_t*); + extern "C" { RMailObjectInterface* hello_new(void*, void (*)(RMailObject*)); void hello_free(RMailObjectInterface*); void hello_set(RMailObjectInterface*, const uint16_t *, size_t); - size_t hello_size(RMailObjectInterface*); - const char* hello_get(RMailObjectInterface*); + qstring_t hello_get(RMailObjectInterface*); RItemModelInterface* ritemmodel_new(void*); void ritemmodel_free(RItemModelInterface*); + int ritemmodel_column_count(RItemModelInterface*, qmodelindex_t parent); + int ritemmodel_row_count(RItemModelInterface*, qmodelindex_t parent); + qmodelindex_t ritemmodel_index(RItemModelInterface*, int row, int column, qmodelindex_t parent); + qmodelindex_t ritemmodel_parent(RItemModelInterface*, qmodelindex_t); + void ritemmodel_data(RItemModelInterface*, qmodelindex_t, int, void*, qvariant_set); } RMailObject::RMailObject(QObject *parent): @@ -27,7 +90,7 @@ RMailObject::~RMailObject() { QString RMailObject::userName() const { - return QString::fromUtf8(hello_get(d), hello_size(d)); + return hello_get(d); } void @@ -58,21 +121,64 @@ RItemModel::~RItemModel() { int RItemModel::columnCount(const QModelIndex &parent) const { - return 0; -} -QVariant RItemModel::data(const QModelIndex &index, int role) const -{ - return 0; -} -QModelIndex RItemModel::index(int row, int column, const QModelIndex &parent) const -{ - return QModelIndex(); -} -QModelIndex RItemModel::parent(const QModelIndex &index) const -{ - return QModelIndex(); + const qmodelindex_t p = { + .row = parent.row(), + .column = parent.column(), + .id = parent.internalId() + }; + return ritemmodel_column_count(d, p); } int RItemModel::rowCount(const QModelIndex &parent) const { - return 0; + const qmodelindex_t p = { + .row = parent.row(), + .column = parent.column(), + .id = parent.internalId() + }; + return ritemmodel_row_count(d, p); +} + +void set_variant(void* v, qvariant_t* val) { + *static_cast(v) = variant(*val); +} + +QVariant RItemModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) { + return QVariant(); + } + if (role != Qt::DisplayRole) { + return QVariant(); + } + const qmodelindex_t i = { + .row = index.row(), + .column = index.column(), + .id = index.internalId() + }; + QVariant v; + ritemmodel_data(d, i, role, &v, set_variant); + return v; +} +QModelIndex RItemModel::index(int row, int column, const QModelIndex &parent) const +{ + const qmodelindex_t p = { + .row = parent.row(), + .column = parent.column(), + .id = parent.internalId() + }; + const qmodelindex_t i = ritemmodel_index(d, row, column, p); + return i.id ?createIndex(i.row, i.column, i.id) :QModelIndex(); +} +QModelIndex RItemModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) { + return QModelIndex(); + } + const qmodelindex_t i = { + .row = index.row(), + .column = index.column(), + .id = index.internalId() + }; + const qmodelindex_t parent = ritemmodel_parent(d, i); + return parent.id ?createIndex(parent.row, parent.column, parent.id) :QModelIndex(); } diff --git a/src/main.cpp b/src/main.cpp index 8df3336..c5970ef 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,7 @@ #include "RMailObject.h" #include +#include #include #include #include @@ -44,6 +45,12 @@ int main (int argc, char *argv[]) parser.process(app); aboutData.processCommandLine(&parser); + RItemModel model; + QTreeView view; + view.setModel(&model); + view.show(); + return app.exec(); +/* RMailObject rmail; rmail.setUserName("RMail"); rmail.userName(); @@ -56,4 +63,5 @@ int main (int argc, char *argv[]) KMessageBox::questionYesNo (0, i18n( "Hello World" ), i18n( "Hello" ), yesButton ) == KMessageBox::Yes? EXIT_SUCCESS: EXIT_FAILURE; +*/ }