diff --git a/CMakeLists.txt b/CMakeLists.txt index 9933c21..4be54ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,7 @@ endif() add_custom_command( OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/common-rust/src/testinterface.rs" + "${CMAKE_CURRENT_SOURCE_DIR}/common-rust/src/types.rs" COMMAND ${CMAKE_BINARY_DIR}/rust_qt_binding_generator/rust_qt_binding_generator "${CMAKE_CURRENT_SOURCE_DIR}/bindings.json" DEPENDS rust_qt_binding_generator bindings.json ) diff --git a/bindings.json b/bindings.json index 1ae77de..8def7d1 100644 --- a/bindings.json +++ b/bindings.json @@ -3,7 +3,8 @@ "rust": { "dir": "common-rust", "interfaceModule": "testinterface", - "implementationModule": "testimplementation" + "implementationModule": "testimplementation", + "typesModule": "types" }, "objects": [{ "name": "Person", diff --git a/common-rust/src/types.rs b/common-rust/src/types.rs index e3d9760..98a702f 100644 --- a/common-rust/src/types.rs +++ b/common-rust/src/types.rs @@ -1,3 +1,4 @@ +/* generated by rust_qt_binding_generator */ use std::slice; use libc::{c_int, c_uint, uint8_t, uint16_t}; use std::ptr::null; @@ -212,3 +213,5 @@ impl QModelIndex { self.internal_id } } + + diff --git a/rust_qt_binding_generator/rust_qt_binding_generator.cpp b/rust_qt_binding_generator/rust_qt_binding_generator.cpp index 69a2699..0197864 100644 --- a/rust_qt_binding_generator/rust_qt_binding_generator.cpp +++ b/rust_qt_binding_generator/rust_qt_binding_generator.cpp @@ -107,6 +107,7 @@ struct Configuration { QDir rustdir; QString interfaceModule; QString implementationModule; + QString typesModule; QList objects; bool overwriteImplementation; }; @@ -191,6 +192,7 @@ parseConfiguration(const QString& path) { c.rustdir = QDir(base.filePath(rust.value("dir").toString())); c.interfaceModule = rust.value("interfaceModule").toString(); c.implementationModule = rust.value("implementationModule").toString(); + c.typesModule = rust.value("typesModule").toString(); return c; } @@ -605,7 +607,7 @@ extern "C" { void writeRustInterfaceObject(QTextStream& r, const Object& o) { const QString lcname(snakeCase(o.name)); - r << QString(R"(/* generated by rust_qt_binding_generator */ + r << QString(R"( pub struct %1QObject {} #[derive (Clone)] @@ -804,7 +806,7 @@ QString rustFile(const QDir rustdir, const QString& module) { void writeRustInterface(const Configuration& conf) { DifferentFileWriter w(rustFile(conf.rustdir, conf.interfaceModule)); QTextStream r(&w.buffer); - r << QString(R"( + r << QString(R"(/* generated by rust_qt_binding_generator */ #![allow(unknown_lints)] #![allow(mutex_atomic, needless_pass_by_value)] use libc::{c_int, c_void}; @@ -895,6 +897,229 @@ use %1::*; } } +void writeRustTypes(const Configuration& conf) { + DifferentFileWriter w(rustFile(conf.rustdir, conf.typesModule)); + QTextStream r(&w.buffer); + r << QString(R"(/* generated by rust_qt_binding_generator */ +use std::slice; +use libc::{c_int, c_uint, uint8_t, uint16_t}; +use std::ptr::null; +use std::marker::PhantomData; + +#[repr(C)] +pub struct QString { + data: *const uint8_t, + len: c_int, +} + +#[repr(C)] +pub struct QStringIn { + data: *const uint16_t, + len: c_int, +} + +impl QStringIn { + pub fn convert(&self) -> String { + let data = unsafe { slice::from_raw_parts(self.data, self.len as usize) }; + String::from_utf16_lossy(data) + } +} + +impl<'a> From<&'a String> for QString { + fn from(string: &'a String) -> QString { + QString { + len: string.len() as c_int, + data: string.as_ptr(), + } + } +} + +#[repr(C)] +pub struct QByteArray { + data: *const uint8_t, + len: c_int, +} + +impl QByteArray { + pub fn convert(&self) -> Vec { + let data = unsafe { slice::from_raw_parts(self.data, self.len as usize) }; + Vec::from(data) + } +} + +impl<'a> From<&'a Vec> for QByteArray { + fn from(value: &'a Vec) -> QByteArray { + QByteArray { + len: value.len() as c_int, + data: value.as_ptr(), + } + } +} + +#[derive(Clone)] +pub enum Variant { + None, + Bool(bool), + Int(c_int), + String(String), + ByteArray(Vec), +} + +impl From for Variant { + fn from(value: bool) -> Variant { + Variant::Bool(value) + } +} + +impl From for Variant { + fn from(value: String) -> Variant { + Variant::String(value) + } +} + +/* values from qvariant.h and qmetatype.h */ +#[repr(u32)] +#[derive(Clone, Copy)] +enum VariantType { + Invalid = 0, + Bool = 1, + Int = 2, + String = 10, + ByteArray = 12, +} + +#[repr(C)] +pub struct QVariant<'a> { + type_: VariantType, + value: c_int, + data: *const uint8_t, + phantom: PhantomData<&'a u8>, +} + +impl<'a> QVariant<'a> { + pub fn type_(&self) -> u32 { + self.type_ as u32 + } + pub fn convert(&self) -> Variant { + match self.type_ { + VariantType::Bool => { + Variant::Bool(self.value != 0) + }, + VariantType::Int => { + Variant::Int(self.value) + }, + VariantType::String => { + let data = unsafe { + let d = self.data as *const uint16_t; + slice::from_raw_parts(d, self.value as usize) + }; + Variant::String(String::from_utf16_lossy(data)) + } + VariantType::ByteArray => { + let data = unsafe { + slice::from_raw_parts(self.data, self.value as usize) + }; + Variant::ByteArray(Vec::from(data)) + } + _ => Variant::None + } + } +} + +impl<'a> From<&'a Variant> for QVariant<'a> { + fn from(variant: &'a Variant) -> QVariant { + match *variant { + Variant::None => { + QVariant { + data: null(), + value: 0, + type_: VariantType::Invalid, + phantom: PhantomData, + } + } + Variant::Bool(v) => { + QVariant { + data: null(), + value: v as c_int, + type_: VariantType::Bool, + phantom: PhantomData, + } + } + Variant::Int(v) => { + QVariant { + data: null(), + value: v, + type_: VariantType::Int, + phantom: PhantomData, + } + } + Variant::String(ref v) => { + QVariant { + data: v.as_ptr(), + value: v.len() as c_int, + type_: VariantType::String, + phantom: PhantomData, + } + } + Variant::ByteArray(ref v) => { + QVariant { + data: v.as_ptr(), + value: v.len() as c_int, + type_: VariantType::ByteArray, + 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 create(row: c_int, column: c_int, id: usize) -> QModelIndex { + QModelIndex { + row: row, + column: column, + internal_id: id, + } + } + 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 + } + pub fn row(&self) -> c_int { + self.row + } + pub fn column(&self) -> c_int { + self.column + } + pub fn id(&self) -> usize { + self.internal_id + } +} + + +)"); +} + int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); QCoreApplication::setApplicationName(argv[0]); @@ -931,6 +1156,7 @@ int main(int argc, char *argv[]) { writeCpp(configuration); writeRustInterface(configuration); writeRustImplementation(configuration); + writeRustTypes(configuration); return 0; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 48230dd..a8ab941 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,6 +9,7 @@ function(rust_test NAME DIRECTORY) add_custom_command( OUTPUT "${DIR}/src/interface.rs" "${DIR}/src/implementation.rs" + "${DIR}/src/types.rs" "${SRC}/${NAME}_rust.h" # if the cpp file is marked GENERATED, CMake will not check it for moc # "${SRC}/${NAME}_rust.cpp" @@ -20,10 +21,10 @@ function(rust_test NAME DIRECTORY) add_custom_command( OUTPUT "${DIR}/${RUST_TARGET_DIR}/librust.a" COMMAND cargo build ${RUST_BUILD_FLAG} - DEPENDS "${DIRECTORY}/src/lib.rs" - "${DIRECTORY}/src/implementation.rs" - "${DIRECTORY}/src/interface.rs" - "${DIRECTORY}/src/types.rs" + DEPENDS "${DIR}/src/lib.rs" + "${DIR}/src/implementation.rs" + "${DIR}/src/interface.rs" + "${DIR}/src/types.rs" WORKING_DIRECTORY "${DIR}" ) add_custom_target("test_${DIRECTORY}" diff --git a/tests/rust_object/src/types.rs b/tests/rust_object/src/types.rs index e3d9760..98a702f 100644 --- a/tests/rust_object/src/types.rs +++ b/tests/rust_object/src/types.rs @@ -1,3 +1,4 @@ +/* generated by rust_qt_binding_generator */ use std::slice; use libc::{c_int, c_uint, uint8_t, uint16_t}; use std::ptr::null; @@ -212,3 +213,5 @@ impl QModelIndex { self.internal_id } } + + diff --git a/tests/rust_object_types/src/types.rs b/tests/rust_object_types/src/types.rs index e3d9760..98a702f 100644 --- a/tests/rust_object_types/src/types.rs +++ b/tests/rust_object_types/src/types.rs @@ -1,3 +1,4 @@ +/* generated by rust_qt_binding_generator */ use std::slice; use libc::{c_int, c_uint, uint8_t, uint16_t}; use std::ptr::null; @@ -212,3 +213,5 @@ impl QModelIndex { self.internal_id } } + + diff --git a/tests/test_object.json b/tests/test_object.json index cfed296..6ede659 100644 --- a/tests/test_object.json +++ b/tests/test_object.json @@ -3,7 +3,8 @@ "rust": { "dir": "rust_object", "interfaceModule": "interface", - "implementationModule": "implementation" + "implementationModule": "implementation", + "typesModule": "types" }, "objects": [{ "name": "Person", diff --git a/tests/test_object_types.json b/tests/test_object_types.json index 9a71db9..c2ea27f 100644 --- a/tests/test_object_types.json +++ b/tests/test_object_types.json @@ -3,7 +3,8 @@ "rust": { "dir": "rust_object_types", "interfaceModule": "interface", - "implementationModule": "implementation" + "implementationModule": "implementation", + "typesModule": "types" }, "objects": [{ "name": "Object",