diff --git a/CMakeLists.txt b/CMakeLists.txt index 4522577..e07180b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,7 +51,7 @@ else() set(RUST_BUILD_FLAG --release) endif() -add_subdirectory(rust_qt_binding_generator) +add_subdirectory(src) enable_testing() add_subdirectory(tests) diff --git a/demo/CMakeLists.txt b/demo/CMakeLists.txt index 48de002..8597966 100644 --- a/demo/CMakeLists.txt +++ b/demo/CMakeLists.txt @@ -7,7 +7,7 @@ add_custom_command( "${CMAKE_CURRENT_SOURCE_DIR}/src/Fibonacci.h" # if the cpp file is marked GENERATED, CMake will not check it for moc # "${CMAKE_CURRENT_SOURCE_DIR}/src/Fibonacci.cpp" - COMMAND ${CMAKE_BINARY_DIR}/rust_qt_binding_generator/rust_qt_binding_generator "${CMAKE_CURRENT_SOURCE_DIR}/fibonacci.json" + COMMAND ${CMAKE_BINARY_DIR}/src/rust_qt_binding_generator "${CMAKE_CURRENT_SOURCE_DIR}/fibonacci.json" DEPENDS rust_qt_binding_generator fibonacci.json ) @@ -18,7 +18,7 @@ add_custom_command( "${CMAKE_CURRENT_SOURCE_DIR}/src/Tree.h" # if the cpp file is marked GENERATED, CMake will not check it for moc # "${CMAKE_CURRENT_SOURCE_DIR}/src/Tree.cpp" - COMMAND ${CMAKE_BINARY_DIR}/rust_qt_binding_generator/rust_qt_binding_generator "${CMAKE_CURRENT_SOURCE_DIR}/tree.json" + COMMAND ${CMAKE_BINARY_DIR}/src/rust_qt_binding_generator "${CMAKE_CURRENT_SOURCE_DIR}/tree.json" DEPENDS rust_qt_binding_generator tree.json ) @@ -29,7 +29,7 @@ add_custom_command( "${CMAKE_CURRENT_SOURCE_DIR}/src/TimeSeries.h" # if the cpp file is marked GENERATED, CMake will not check it for moc # "${CMAKE_CURRENT_SOURCE_DIR}/src/TimeSeries.cpp" - COMMAND ${CMAKE_BINARY_DIR}/rust_qt_binding_generator/rust_qt_binding_generator "${CMAKE_CURRENT_SOURCE_DIR}/time_series.json" + COMMAND ${CMAKE_BINARY_DIR}/src/rust_qt_binding_generator "${CMAKE_CURRENT_SOURCE_DIR}/time_series.json" DEPENDS rust_qt_binding_generator time_series.json ) diff --git a/demo/rust/src/fibonacci_implementation.rs b/demo/rust/src/fibonacci_implementation.rs index 36e83e6..c3037e7 100644 --- a/demo/rust/src/fibonacci_implementation.rs +++ b/demo/rust/src/fibonacci_implementation.rs @@ -1,8 +1,6 @@ #![allow(unused_imports)] #![allow(unused_variables)] #![allow(dead_code)] -use libc::c_int; -use libc::c_uint; use types::*; use std::thread; use fibonacci_interface::*; @@ -80,10 +78,10 @@ impl FibonacciListTrait for FibonacciList { fn emit(&self) -> &FibonacciListEmitter { &self.emit } - fn row_count(&self) -> c_int { + fn row_count(&self) -> usize { 94 } - fn result(&self, row: c_int) -> u64 { + fn result(&self, row: usize) -> u64 { fibonacci(row as u32) as u64 } } diff --git a/demo/rust/src/fibonacci_interface.rs b/demo/rust/src/fibonacci_interface.rs index 8767c1f..65898b5 100644 --- a/demo/rust/src/fibonacci_interface.rs +++ b/demo/rust/src/fibonacci_interface.rs @@ -2,7 +2,7 @@ #![allow(unknown_lints)] #![allow(mutex_atomic, needless_pass_by_value)] #![allow(unused_imports)] -use libc::{c_int, c_uint, c_void}; +use libc::{c_int, c_void}; use types::*; use std::sync::{Arc, Mutex}; use std::ptr::null; @@ -106,9 +106,9 @@ pub struct FibonacciListList { qobject: *const FibonacciListQObject, begin_reset_model: fn(*const FibonacciListQObject), end_reset_model: fn(*const FibonacciListQObject), - begin_insert_rows: fn(*const FibonacciListQObject, c_int, c_int), + begin_insert_rows: fn(*const FibonacciListQObject, usize, usize), end_insert_rows: fn(*const FibonacciListQObject), - begin_remove_rows: fn(*const FibonacciListQObject, c_int, c_int), + begin_remove_rows: fn(*const FibonacciListQObject, usize, usize), end_remove_rows: fn(*const FibonacciListQObject), } @@ -119,13 +119,13 @@ impl FibonacciListList { pub fn end_reset_model(&self) { (self.end_reset_model)(self.qobject); } - pub fn begin_insert_rows(&self, first: c_int, last: c_int) { + pub fn begin_insert_rows(&self, first: usize, last: usize) { (self.begin_insert_rows)(self.qobject, first, last); } pub fn end_insert_rows(&self) { (self.end_insert_rows)(self.qobject); } - pub fn begin_remove_rows(&self, first: c_int, last: c_int) { + pub fn begin_remove_rows(&self, first: usize, last: usize) { (self.begin_remove_rows)(self.qobject, first, last); } pub fn end_remove_rows(&self) { @@ -136,11 +136,11 @@ impl FibonacciListList { pub trait FibonacciListTrait { fn create(emit: FibonacciListEmitter, model: FibonacciListList) -> Self; fn emit(&self) -> &FibonacciListEmitter; - fn row_count(&self) -> c_int; + fn row_count(&self) -> usize; fn can_fetch_more(&self) -> bool { false } fn fetch_more(&mut self) {} - fn sort(&mut self, c_int, SortOrder) {} - fn result(&self, row: c_int) -> u64; + fn sort(&mut self, u8, SortOrder) {} + fn result(&self, item: usize) -> u64; } #[no_mangle] @@ -149,12 +149,12 @@ pub extern "C" fn fibonacci_list_new(qobject: *const FibonacciListQObject, begin_reset_model: fn(*const FibonacciListQObject), end_reset_model: fn(*const FibonacciListQObject), begin_insert_rows: fn(*const FibonacciListQObject, - c_int, - c_int), + usize, + usize), end_insert_rows: fn(*const FibonacciListQObject), begin_remove_rows: fn(*const FibonacciListQObject, - c_int, - c_int), + usize, + usize), end_remove_rows: fn(*const FibonacciListQObject)) -> *mut FibonacciList { let emit = FibonacciListEmitter { @@ -181,7 +181,7 @@ pub unsafe extern "C" fn fibonacci_list_free(ptr: *mut FibonacciList) { #[no_mangle] pub unsafe extern "C" fn fibonacci_list_row_count(ptr: *const FibonacciList) -> c_int { - (&*ptr).row_count() + (&*ptr).row_count() as c_int } #[no_mangle] pub unsafe extern "C" fn fibonacci_list_can_fetch_more(ptr: *const FibonacciList) -> bool { @@ -192,11 +192,11 @@ pub unsafe extern "C" fn fibonacci_list_fetch_more(ptr: *mut FibonacciList) { (&mut *ptr).fetch_more() } #[no_mangle] -pub unsafe extern "C" fn fibonacci_list_sort(ptr: *mut FibonacciList, column: c_int, order: SortOrder) { +pub unsafe extern "C" fn fibonacci_list_sort(ptr: *mut FibonacciList, column: u8, order: SortOrder) { (&mut *ptr).sort(column, order) } #[no_mangle] pub unsafe extern "C" fn fibonacci_list_data_result(ptr: *const FibonacciList, row: c_int) -> u64 { - (&*ptr).result(row).into() + (&*ptr).result(row as usize).into() } diff --git a/demo/rust/src/implementation.rs b/demo/rust/src/implementation.rs index 917e8ce..c0f0740 100644 --- a/demo/rust/src/implementation.rs +++ b/demo/rust/src/implementation.rs @@ -1,7 +1,6 @@ use interface::*; use types::*; use std::fs::*; -use libc::{c_int}; use std::fs::read_dir; use std::path::PathBuf; use std::ffi::OsString; @@ -36,10 +35,10 @@ impl Item for DirEntry { fn file_path(&self) -> Option { self.path.as_ref().map(|p| p.to_string_lossy().into()) } - fn file_permissions(&self) -> c_int { + fn file_permissions(&self) -> i32 { 42 } - fn file_type(&self) -> c_int { + fn file_type(&self) -> i32 { 0 } fn file_size(&self) -> Option { @@ -65,7 +64,7 @@ impl Item for DirEntry { let mut map = q.lock().unwrap(); if !map.contains_key(&id) { map.insert(id, v); - emit.new_data_ready(0, 0); + emit.new_data_ready(id); } }); } @@ -87,15 +86,15 @@ pub trait Item: Default { fn retrieve(id: usize, parents: Vec<&Self>, q: Incoming, emit: TreeEmitter); fn file_name(&self) -> String; fn file_path(&self) -> Option; - fn file_permissions(&self) -> c_int; - fn file_type(&self) -> c_int; + fn file_permissions(&self) -> i32; + fn file_type(&self) -> i32; fn file_size(&self) -> Option; } pub type Tree = RGeneralItemModel; struct Entry { - parent: usize, + id: usize, row: usize, children: Option>, data: T, @@ -114,14 +113,14 @@ impl RGeneralItemModel where T: Sync + Send { self.model.begin_reset_model(); self.entries.clear(); let none0 = Entry { - parent: 0, + id: 0, row: 0, children: Some(vec![1]), data: T::default(), }; self.entries.push(none0); let none1 = Entry { - parent: 0, + id: 0, row: 0, children: None, data: T::default(), @@ -130,7 +129,7 @@ impl RGeneralItemModel where T: Sync + Send { if let Some(ref path) = self.path { self.entries[1].children = Some(vec![2]); let root = Entry { - parent: 1, + id: 1, row: 0, children: None, data: T::create(&path), @@ -139,29 +138,23 @@ impl RGeneralItemModel where T: Sync + Send { } self.model.end_reset_model(); } - fn get_index(&self, row: c_int, parent: usize) -> Option { + fn get_index(&self, item: usize, row: usize) -> Option { // for an invalid index return the root - if parent == 0 || row < 0 { + if item == 0 { return Some(1); } - self.entries.get(parent) + self.entries.get(item) .and_then(|i| i.children.as_ref()) - .and_then(|i| i.get(row as usize)) + .and_then(|i| i.get(row)) .map(|i| *i) } - fn get(&self, row: c_int, parent: usize) -> Option<&Entry> { - self.get_index(row, parent) - .map(|i| &self.entries[i]) + fn get(&self, item: usize) -> &Entry { + &self.entries[item] } - fn get_mut(&mut self, row: c_int, parent: usize) -> Option<&mut Entry> { - self.get_index(row, parent) - .map(move |i| &mut self.entries[i]) - } - fn retrieve(&mut self, row: c_int, parent: usize) { - let id = self.get_index(row, parent).unwrap(); - let parents = self.get_parents(id); + fn retrieve(&mut self, item: usize) { + let parents = self.get_parents(item); let incoming = self.incoming.clone(); - T::retrieve(id, parents, incoming, self.emit.clone()); + T::retrieve(item, parents, incoming, self.emit.clone()); } fn process_incoming(&mut self) { let mut incoming = self.incoming.lock().unwrap(); @@ -174,7 +167,7 @@ impl RGeneralItemModel where T: Sync + Send { { for (r, d) in entries.into_iter().enumerate() { let e = Entry { - parent: id, + id: id, row: r, children: None, data: d, @@ -183,9 +176,8 @@ impl RGeneralItemModel where T: Sync + Send { new_entries.push(e); } if new_entries.len() > 0 { - let ref e = self.entries[id]; - self.model.begin_insert_rows(e.row as c_int, e.parent, 0, - (new_entries.len() - 1) as c_int); + self.model.begin_insert_rows(id, 0, + (new_entries.len() - 1)); } } self.entries[id].children = Some(children); @@ -200,7 +192,7 @@ impl RGeneralItemModel where T: Sync + Send { let mut e = Vec::new(); while pos > 0 { e.push(pos); - pos = self.entries[pos].parent; + pos = self.entries[pos].id; } e.into_iter().rev().map(|i| &self.entries[i].data).collect() } @@ -231,66 +223,54 @@ impl TreeTrait for RGeneralItemModel where T: Sync + Send { self.reset(); } } - fn can_fetch_more(&self, row: c_int, parent: usize) -> bool { - self.get(row, parent) - .map(|entry| entry.children.is_none() - && entry.data.can_fetch_more()) - .unwrap_or(false) + fn can_fetch_more(&self, item: usize) -> bool { + let entry = self.get(item); + entry.children.is_none() && entry.data.can_fetch_more() } - fn fetch_more(&mut self, row: c_int, parent: usize) { + fn fetch_more(&mut self, item: usize) { self.process_incoming(); - if !self.can_fetch_more(row, parent) { + if !self.can_fetch_more(item) { return; } - self.retrieve(row, parent); + self.retrieve(item); } - fn row_count(&self, row: c_int, parent: usize) -> c_int { - let r = self.get(row, parent) - .and_then(|entry| entry.children.as_ref()) + fn row_count(&self, item: usize) -> usize { + let r = self.get(item).children.as_ref() .map(|i| i.len()) - .unwrap_or(0) as c_int; + .unwrap_or(0); // model does lazy loading, signal that data may be available - if r == 0 && self.can_fetch_more(row, parent) { - self.emit.new_data_ready(row, parent); + if r == 0 && self.can_fetch_more(item) { + self.emit.new_data_ready(item); } r } - fn index(&self, row: c_int, parent: usize) -> usize { - self.get_index(row, parent).unwrap_or(0) + fn index(&self, item: usize, row: usize) -> usize { + self.get_index(item, row).unwrap_or(0) } fn parent(&self, index: usize) -> QModelIndex { if index >= self.entries.len() { return QModelIndex::invalid(); } let entry = &self.entries[index]; - QModelIndex::create(entry.row as i32, entry.parent) + QModelIndex::create(entry.row as i32, entry.id) } - fn file_name(&self, row: c_int, parent: usize) -> String { - self.get(row, parent) - .map(|entry| entry.data.file_name()) - .unwrap_or_default() + fn file_name(&self, item: usize) -> String { + self.get(item).data.file_name() } - fn file_permissions(&self, row: c_int, parent: usize) -> c_int { - self.get(row, parent) - .map(|entry| entry.data.file_permissions()) - .unwrap_or_default() + fn file_permissions(&self, item: usize) -> i32 { + self.get(item).data.file_permissions() } - fn file_icon(&self, row: c_int, parent: usize) -> Vec { + #[allow(unused_variables)] + fn file_icon(&self, item: usize) -> Vec { Vec::new() } - fn file_path(&self, row: c_int, parent: usize) -> Option { - self.get(row, parent) - .map(|entry| entry.data.file_path()) - .unwrap_or_default() + fn file_path(&self, item: usize) -> Option { + self.get(item).data.file_path() } - fn file_type(&self, row: c_int, parent: usize) -> c_int { - self.get(row, parent) - .map(|entry| entry.data.file_type()) - .unwrap_or_default() + fn file_type(&self, item: usize) -> i32 { + self.get(item).data.file_type() } - fn file_size(&self, row: c_int, parent: usize) -> Option { - self.get(row, parent) - .map(|entry| entry.data.file_size()) - .unwrap_or(None) + fn file_size(&self, item: usize) -> Option { + self.get(item).data.file_size() } } diff --git a/demo/rust/src/interface.rs b/demo/rust/src/interface.rs index fc64d8f..896c8d7 100644 --- a/demo/rust/src/interface.rs +++ b/demo/rust/src/interface.rs @@ -2,7 +2,7 @@ #![allow(unknown_lints)] #![allow(mutex_atomic, needless_pass_by_value)] #![allow(unused_imports)] -use libc::{c_int, c_uint, c_void}; +use libc::{c_int, c_void}; use types::*; use std::sync::{Arc, Mutex}; use std::ptr::null; @@ -15,7 +15,7 @@ pub struct TreeQObject {} pub struct TreeEmitter { qobject: Arc>, path_changed: fn(*const TreeQObject), - new_data_ready: fn(*const TreeQObject, row: c_int, parent: usize), + new_data_ready: fn(*const TreeQObject, item: usize), } unsafe impl Send for TreeEmitter {} @@ -30,10 +30,10 @@ impl TreeEmitter { (self.path_changed)(ptr); } } - pub fn new_data_ready(&self, row: c_int, parent: usize) { + pub fn new_data_ready(&self, item: usize) { let ptr = *self.qobject.lock().unwrap(); if !ptr.is_null() { - (self.new_data_ready)(ptr, row, parent); + (self.new_data_ready)(ptr, item); } } } @@ -42,9 +42,9 @@ pub struct TreeUniformTree { qobject: *const TreeQObject, begin_reset_model: fn(*const TreeQObject), end_reset_model: fn(*const TreeQObject), - begin_insert_rows: fn(*const TreeQObject,row: c_int, parent: usize, c_int, c_int), + begin_insert_rows: fn(*const TreeQObject, item: usize, usize, usize), end_insert_rows: fn(*const TreeQObject), - begin_remove_rows: fn(*const TreeQObject,row: c_int, parent: usize, c_int, c_int), + begin_remove_rows: fn(*const TreeQObject, item: usize, usize, usize), end_remove_rows: fn(*const TreeQObject), } @@ -55,14 +55,14 @@ impl TreeUniformTree { pub fn end_reset_model(&self) { (self.end_reset_model)(self.qobject); } - pub fn begin_insert_rows(&self,row: c_int, parent: usize, first: c_int, last: c_int) { - (self.begin_insert_rows)(self.qobject,row, parent, first, last); + pub fn begin_insert_rows(&self, item: usize, first: usize, last: usize) { + (self.begin_insert_rows)(self.qobject, item, first, last); } pub fn end_insert_rows(&self) { (self.end_insert_rows)(self.qobject); } - pub fn begin_remove_rows(&self,row: c_int, parent: usize, first: c_int, last: c_int) { - (self.begin_remove_rows)(self.qobject,row, parent, first, last); + pub fn begin_remove_rows(&self, item: usize, first: usize, last: usize) { + (self.begin_remove_rows)(self.qobject, item, first, last); } pub fn end_remove_rows(&self) { (self.end_remove_rows)(self.qobject); @@ -74,33 +74,33 @@ pub trait TreeTrait { fn emit(&self) -> &TreeEmitter; fn get_path(&self) -> Option; fn set_path(&mut self, value: Option); - fn row_count(&self, row: c_int, parent: usize) -> c_int; - fn can_fetch_more(&self, c_int, usize) -> bool { false } - fn fetch_more(&mut self, c_int, usize) {} - fn sort(&mut self, c_int, SortOrder) {} - fn file_icon(&self, row: c_int, parent: usize) -> Vec; - fn file_name(&self, row: c_int, parent: usize) -> String; - fn file_path(&self, row: c_int, parent: usize) -> Option; - fn file_permissions(&self, row: c_int, parent: usize) -> i32; - fn file_size(&self, row: c_int, parent: usize) -> Option; - fn file_type(&self, row: c_int, parent: usize) -> i32; - fn index(&self, row: c_int, parent: usize) -> usize; - fn parent(&self, parent: usize) -> QModelIndex; + fn row_count(&self, item: usize) -> usize; + fn can_fetch_more(&self, item: usize) -> bool { false } + fn fetch_more(&mut self, item: usize) {} + fn sort(&mut self, u8, SortOrder) {} + fn file_icon(&self, item: usize) -> Vec; + fn file_name(&self, item: usize) -> String; + fn file_path(&self, item: usize) -> Option; + fn file_permissions(&self, item: usize) -> i32; + fn file_size(&self, item: usize) -> Option; + fn file_type(&self, item: usize) -> i32; + fn index(&self, item: usize, row: usize) -> usize; + fn parent(&self, item: usize) -> QModelIndex; } #[no_mangle] pub extern "C" fn tree_new(qobject: *const TreeQObject, path_changed: fn(*const TreeQObject), - new_data_ready: fn(*const TreeQObject, row: c_int, parent: usize), + new_data_ready: fn(*const TreeQObject, item: usize), begin_reset_model: fn(*const TreeQObject), end_reset_model: fn(*const TreeQObject), - begin_insert_rows: fn(*const TreeQObject,row: c_int, parent: usize, - c_int, - c_int), + begin_insert_rows: fn(*const TreeQObject, item: usize, + usize, + usize), end_insert_rows: fn(*const TreeQObject), - begin_remove_rows: fn(*const TreeQObject,row: c_int, parent: usize, - c_int, - c_int), + begin_remove_rows: fn(*const TreeQObject, item: usize, + usize, + usize), end_remove_rows: fn(*const TreeQObject)) -> *mut Tree { let emit = TreeEmitter { @@ -146,69 +146,66 @@ pub unsafe extern "C" fn tree_path_set_none(ptr: *mut Tree) { } #[no_mangle] -pub unsafe extern "C" fn tree_row_count(ptr: *const Tree, row: c_int, parent: usize) -> c_int { - (&*ptr).row_count(row, parent) +pub unsafe extern "C" fn tree_row_count(ptr: *const Tree, row: c_int, item: usize) -> c_int { + (&*ptr).row_count((&*ptr).index(item, row as usize)) as c_int } #[no_mangle] -pub unsafe extern "C" fn tree_can_fetch_more(ptr: *const Tree, row: c_int, parent: usize) -> bool { - (&*ptr).can_fetch_more(row, parent) +pub unsafe extern "C" fn tree_can_fetch_more(ptr: *const Tree, row: c_int, item: usize) -> bool { + (&*ptr).can_fetch_more((&*ptr).index(item, row as usize)) } #[no_mangle] -pub unsafe extern "C" fn tree_fetch_more(ptr: *mut Tree, row: c_int, parent: usize) { - (&mut *ptr).fetch_more(row, parent) +pub unsafe extern "C" fn tree_fetch_more(ptr: *mut Tree, row: c_int, item: usize) { + (&mut *ptr).fetch_more((&*ptr).index(item, row as usize)) } #[no_mangle] -pub unsafe extern "C" fn tree_sort(ptr: *mut Tree, column: c_int, order: SortOrder) { +pub unsafe extern "C" fn tree_sort(ptr: *mut Tree, column: u8, order: SortOrder) { (&mut *ptr).sort(column, order) } #[no_mangle] -pub unsafe extern "C" fn tree_data_file_icon(ptr: *const Tree, - row: c_int, parent: usize, +pub unsafe extern "C" fn tree_data_file_icon(ptr: *const Tree, row: c_int, item: usize, d: *mut c_void, set: fn(*mut c_void, QByteArray)) { - let data = (&*ptr).file_icon(row, parent); + let data = (&*ptr).file_icon((&*ptr).index(item, row as usize)); set(d, QByteArray::from(&data)); } #[no_mangle] -pub unsafe extern "C" fn tree_data_file_name(ptr: *const Tree, - row: c_int, parent: usize, +pub unsafe extern "C" fn tree_data_file_name(ptr: *const Tree, row: c_int, item: usize, d: *mut c_void, set: fn(*mut c_void, QString)) { - let data = (&*ptr).file_name(row, parent); + let data = (&*ptr).file_name((&*ptr).index(item, row as usize)); set(d, QString::from(&data)); } #[no_mangle] -pub unsafe extern "C" fn tree_data_file_path(ptr: *const Tree, - row: c_int, parent: usize, +pub unsafe extern "C" fn tree_data_file_path(ptr: *const Tree, row: c_int, item: usize, d: *mut c_void, set: fn(*mut c_void, QString)) { - let data = (&*ptr).file_path(row, parent); + let data = (&*ptr).file_path((&*ptr).index(item, row as usize)); if let Some(data) = data { set(d, QString::from(&data)); } } #[no_mangle] -pub unsafe extern "C" fn tree_data_file_permissions(ptr: *const Tree, row: c_int, parent: usize) -> i32 { - (&*ptr).file_permissions(row, parent).into() +pub unsafe extern "C" fn tree_data_file_permissions(ptr: *const Tree, row: c_int, item: usize) -> i32 { + (&*ptr).file_permissions((&*ptr).index(item, row as usize)).into() } #[no_mangle] -pub unsafe extern "C" fn tree_data_file_size(ptr: *const Tree, row: c_int, parent: usize) -> COption { - (&*ptr).file_size(row, parent).into() +pub unsafe extern "C" fn tree_data_file_size(ptr: *const Tree, row: c_int, item: usize) -> COption { + (&*ptr).file_size((&*ptr).index(item, row as usize)).into() } #[no_mangle] -pub unsafe extern "C" fn tree_data_file_type(ptr: *const Tree, row: c_int, parent: usize) -> i32 { - (&*ptr).file_type(row, parent).into() +pub unsafe extern "C" fn tree_data_file_type(ptr: *const Tree, row: c_int, item: usize) -> i32 { + (&*ptr).file_type((&*ptr).index(item, row as usize)).into() } #[no_mangle] pub unsafe extern "C" fn tree_index(ptr: *const Tree, row: c_int, parent: usize) -> usize { - (&*ptr).index(row, parent) + (&*ptr).index(parent, row as usize) } #[no_mangle] pub unsafe extern "C" fn tree_parent(ptr: *const Tree, parent: usize) -> QModelIndex { diff --git a/demo/rust/src/time_series_implementation.rs b/demo/rust/src/time_series_implementation.rs index f742bfd..c612a0f 100644 --- a/demo/rust/src/time_series_implementation.rs +++ b/demo/rust/src/time_series_implementation.rs @@ -1,9 +1,3 @@ -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] -use libc::c_int; -use libc::c_uint; -use types::*; use time_series_interface::*; #[derive (Default, Clone)] @@ -36,21 +30,20 @@ impl TimeSeriesTrait for TimeSeries { fn emit(&self) -> &TimeSeriesEmitter { &self.emit } - fn row_count(&self) -> c_int { - self.list.len() as c_int + fn row_count(&self) -> usize { + self.list.len() as usize } - fn input(&self, row: c_int) -> u32 { + fn input(&self, row: usize) -> u32 { self.list[row as usize].input } - fn set_input(&mut self, row: c_int, v: u32) -> bool { -println!("setting input to {} {}", row, v); + fn set_input(&mut self, row: usize, v: u32) -> bool { self.list[row as usize].input = v; true } - fn result(&self, row: c_int) -> u32 { + fn result(&self, row: usize) -> u32 { self.list[row as usize].result } - fn set_result(&mut self, row: c_int, v: u32) -> bool { + fn set_result(&mut self, row: usize, v: u32) -> bool { self.list[row as usize].result = v; true } diff --git a/demo/rust/src/time_series_interface.rs b/demo/rust/src/time_series_interface.rs index 64dae7e..9e7f549 100644 --- a/demo/rust/src/time_series_interface.rs +++ b/demo/rust/src/time_series_interface.rs @@ -2,7 +2,7 @@ #![allow(unknown_lints)] #![allow(mutex_atomic, needless_pass_by_value)] #![allow(unused_imports)] -use libc::{c_int, c_uint, c_void}; +use libc::{c_int, c_void}; use types::*; use std::sync::{Arc, Mutex}; use std::ptr::null; @@ -35,9 +35,9 @@ pub struct TimeSeriesList { qobject: *const TimeSeriesQObject, begin_reset_model: fn(*const TimeSeriesQObject), end_reset_model: fn(*const TimeSeriesQObject), - begin_insert_rows: fn(*const TimeSeriesQObject, c_int, c_int), + begin_insert_rows: fn(*const TimeSeriesQObject, usize, usize), end_insert_rows: fn(*const TimeSeriesQObject), - begin_remove_rows: fn(*const TimeSeriesQObject, c_int, c_int), + begin_remove_rows: fn(*const TimeSeriesQObject, usize, usize), end_remove_rows: fn(*const TimeSeriesQObject), } @@ -48,13 +48,13 @@ impl TimeSeriesList { pub fn end_reset_model(&self) { (self.end_reset_model)(self.qobject); } - pub fn begin_insert_rows(&self, first: c_int, last: c_int) { + pub fn begin_insert_rows(&self, first: usize, last: usize) { (self.begin_insert_rows)(self.qobject, first, last); } pub fn end_insert_rows(&self) { (self.end_insert_rows)(self.qobject); } - pub fn begin_remove_rows(&self, first: c_int, last: c_int) { + pub fn begin_remove_rows(&self, first: usize, last: usize) { (self.begin_remove_rows)(self.qobject, first, last); } pub fn end_remove_rows(&self) { @@ -65,14 +65,14 @@ impl TimeSeriesList { pub trait TimeSeriesTrait { fn create(emit: TimeSeriesEmitter, model: TimeSeriesList) -> Self; fn emit(&self) -> &TimeSeriesEmitter; - fn row_count(&self) -> c_int; + fn row_count(&self) -> usize; fn can_fetch_more(&self) -> bool { false } fn fetch_more(&mut self) {} - fn sort(&mut self, c_int, SortOrder) {} - fn input(&self, row: c_int) -> u32; - fn set_input(&mut self, row: c_int, u32) -> bool; - fn result(&self, row: c_int) -> u32; - fn set_result(&mut self, row: c_int, u32) -> bool; + fn sort(&mut self, u8, SortOrder) {} + fn input(&self, item: usize) -> u32; + fn set_input(&mut self, item: usize, u32) -> bool; + fn result(&self, item: usize) -> u32; + fn set_result(&mut self, item: usize, u32) -> bool; } #[no_mangle] @@ -81,12 +81,12 @@ pub extern "C" fn time_series_new(qobject: *const TimeSeriesQObject, begin_reset_model: fn(*const TimeSeriesQObject), end_reset_model: fn(*const TimeSeriesQObject), begin_insert_rows: fn(*const TimeSeriesQObject, - c_int, - c_int), + usize, + usize), end_insert_rows: fn(*const TimeSeriesQObject), begin_remove_rows: fn(*const TimeSeriesQObject, - c_int, - c_int), + usize, + usize), end_remove_rows: fn(*const TimeSeriesQObject)) -> *mut TimeSeries { let emit = TimeSeriesEmitter { @@ -113,7 +113,7 @@ pub unsafe extern "C" fn time_series_free(ptr: *mut TimeSeries) { #[no_mangle] pub unsafe extern "C" fn time_series_row_count(ptr: *const TimeSeries) -> c_int { - (&*ptr).row_count() + (&*ptr).row_count() as c_int } #[no_mangle] pub unsafe extern "C" fn time_series_can_fetch_more(ptr: *const TimeSeries) -> bool { @@ -124,26 +124,26 @@ pub unsafe extern "C" fn time_series_fetch_more(ptr: *mut TimeSeries) { (&mut *ptr).fetch_more() } #[no_mangle] -pub unsafe extern "C" fn time_series_sort(ptr: *mut TimeSeries, column: c_int, order: SortOrder) { +pub unsafe extern "C" fn time_series_sort(ptr: *mut TimeSeries, column: u8, order: SortOrder) { (&mut *ptr).sort(column, order) } #[no_mangle] pub unsafe extern "C" fn time_series_data_input(ptr: *const TimeSeries, row: c_int) -> u32 { - (&*ptr).input(row).into() + (&*ptr).input(row as usize).into() } #[no_mangle] pub unsafe extern "C" fn time_series_set_data_input(ptr: *mut TimeSeries, row: c_int, v: u32) -> bool { - (&mut *ptr).set_input(row, v) + (&mut *ptr).set_input(row as usize, v) } #[no_mangle] pub unsafe extern "C" fn time_series_data_result(ptr: *const TimeSeries, row: c_int) -> u32 { - (&*ptr).result(row).into() + (&*ptr).result(row as usize).into() } #[no_mangle] pub unsafe extern "C" fn time_series_set_data_result(ptr: *mut TimeSeries, row: c_int, v: u32) -> bool { - (&mut *ptr).set_result(row, v) + (&mut *ptr).set_result(row as usize, v) } diff --git a/demo/src/Fibonacci.cpp b/demo/src/Fibonacci.cpp index 48ba47e..5e0076a 100644 --- a/demo/src/Fibonacci.cpp +++ b/demo/src/Fibonacci.cpp @@ -61,6 +61,95 @@ extern "C" { quint32 fibonacci_input_get(const Fibonacci::Private*); 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); + + int fibonacci_list_row_count(const FibonacciList::Private*); + bool fibonacci_list_can_fetch_more(const FibonacciList::Private*); + void fibonacci_list_fetch_more(FibonacciList::Private*); +} +int FibonacciList::columnCount(const QModelIndex &parent) const +{ + return (parent.isValid()) ? 0 : 1; +} + +bool FibonacciList::hasChildren(const QModelIndex &parent) const +{ + return rowCount(parent) > 0; +} + +int FibonacciList::rowCount(const QModelIndex &parent) const +{ + return (parent.isValid()) ? 0 : fibonacci_list_row_count(d); +} + +QModelIndex FibonacciList::index(int row, int column, const QModelIndex &parent) const +{ + if (!parent.isValid() && row >= 0 && row < rowCount(parent) && column >= 0 && column < 1) { + return createIndex(row, column, (quintptr)0); + } + return QModelIndex(); +} + +QModelIndex FibonacciList::parent(const QModelIndex &) const +{ + return QModelIndex(); +} + +bool FibonacciList::canFetchMore(const QModelIndex &parent) const +{ + return (parent.isValid()) ? 0 : fibonacci_list_can_fetch_more(d); +} + +void FibonacciList::fetchMore(const QModelIndex &parent) +{ + if (!parent.isValid()) { + fibonacci_list_fetch_more(d); + } +} + +void FibonacciList::sort(int column, Qt::SortOrder order) +{ + fibonacci_list_sort(d, column, order); +} +Qt::ItemFlags FibonacciList::flags(const QModelIndex &i) const +{ + auto flags = QAbstractItemModel::flags(i); + return flags; +} +QVariant FibonacciList::data(const QModelIndex &index, int role) const +{ + QVariant v; + QString s; + QByteArray b; + switch (index.column()) { + case 0: + switch (role) { + case Qt::DisplayRole: + case Qt::UserRole + 0: + v = fibonacci_list_data_result(d, index.row()); + break; + } + break; + } + return v; +} +QHash FibonacciList::roleNames() const { + QHash names = QAbstractItemModel::roleNames(); + names.insert(Qt::UserRole + 0, "result"); + return names; +} +bool FibonacciList::setData(const QModelIndex &index, const QVariant &value, int role) +{ + bool set = false; + if (set) { + emit dataChanged(index, index, QVector() << role); + } + return set; +} +extern "C" { FibonacciList::Private* fibonacci_list_new(FibonacciList*, void (*)(const FibonacciList*), void (*)(FibonacciList*), @@ -125,90 +214,3 @@ FibonacciList::FibonacciList(QObject *parent): FibonacciList::~FibonacciList() { fibonacci_list_free(d); } -extern "C" { - quint64 fibonacci_list_data_result(const FibonacciList::Private*, int); - void fibonacci_list_sort(FibonacciList::Private*, int column, Qt::SortOrder order = Qt::AscendingOrder); - - int fibonacci_list_row_count(const FibonacciList::Private*); - bool fibonacci_list_can_fetch_more(const FibonacciList::Private*); - void fibonacci_list_fetch_more(FibonacciList::Private*); -} -int FibonacciList::columnCount(const QModelIndex &parent) const -{ - return (parent.isValid()) ? 0 : 1; -} - -bool FibonacciList::hasChildren(const QModelIndex &parent) const -{ - return rowCount(parent) > 0; -} - -int FibonacciList::rowCount(const QModelIndex &parent) const -{ - return (parent.isValid()) ? 0 : fibonacci_list_row_count(d); -} - -QModelIndex FibonacciList::index(int row, int column, const QModelIndex &parent) const -{ - if (!parent.isValid() && row >= 0 && row < rowCount(parent) && column >= 0 && column < 1) { - return createIndex(row, column, (quintptr)0); - } - return QModelIndex(); -} - -QModelIndex FibonacciList::parent(const QModelIndex &) const -{ - return QModelIndex(); -} - -bool FibonacciList::canFetchMore(const QModelIndex &parent) const -{ - return (parent.isValid()) ? 0 : fibonacci_list_can_fetch_more(d); -} - -void FibonacciList::fetchMore(const QModelIndex &parent) -{ - if (!parent.isValid()) { - fibonacci_list_fetch_more(d); - } -} - -void FibonacciList::sort(int column, Qt::SortOrder order) -{ - fibonacci_list_sort(d, column, order); -} -Qt::ItemFlags FibonacciList::flags(const QModelIndex &i) const -{ - auto flags = QAbstractItemModel::flags(i); - return flags; -} -QVariant FibonacciList::data(const QModelIndex &index, int role) const -{ - QVariant v; - QString s; - QByteArray b; - switch (index.column()) { - case 0: - switch (role) { - case 256: - case 0: - v = fibonacci_list_data_result(d, index.row()); - break; - } - break; - } - return v; -} -QHash FibonacciList::roleNames() const { - QHash names = QAbstractItemModel::roleNames(); - names.insert(256, "result"); - return names; -} -bool FibonacciList::setData(const QModelIndex &index, const QVariant &value, int role) -{ - bool set = false; - if (set) { - emit dataChanged(index, index, QVector() << role); - } - return set; -} diff --git a/demo/src/TimeSeries.cpp b/demo/src/TimeSeries.cpp index c532397..f1f6a95 100644 --- a/demo/src/TimeSeries.cpp +++ b/demo/src/TimeSeries.cpp @@ -55,57 +55,12 @@ void set_qbytearray(QByteArray* v, qbytearray_t* val) { *v = *val; } -extern "C" { - TimeSeries::Private* time_series_new(TimeSeries*, - void (*)(const TimeSeries*), - void (*)(TimeSeries*), - void (*)(TimeSeries*), - void (*)(TimeSeries*, int, int), - void (*)(TimeSeries*), - void (*)(TimeSeries*, int, int), - void (*)(TimeSeries*)); - void time_series_free(TimeSeries::Private*); -}; -TimeSeries::TimeSeries(QObject *parent): - QAbstractItemModel(parent), - d(time_series_new(this, - [](const TimeSeries* o) { - emit o->newDataReady(QModelIndex()); - }, - [](TimeSeries* o) { - o->beginResetModel(); - }, - [](TimeSeries* o) { - o->endResetModel(); - }, - [](TimeSeries* o, int first, int last) { - o->beginInsertRows(QModelIndex(), first, last); - }, - [](TimeSeries* o) { - o->endInsertRows(); - }, - [](TimeSeries* o, int first, int last) { - o->beginRemoveRows(QModelIndex(), first, last); - }, - [](TimeSeries* o) { - o->endRemoveRows(); - } - )) { - connect(this, &TimeSeries::newDataReady, this, [this](const QModelIndex& i) { - fetchMore(i); - }, Qt::QueuedConnection); -} - - -TimeSeries::~TimeSeries() { - time_series_free(d); -} extern "C" { uint time_series_data_input(const TimeSeries::Private*, int); bool time_series_set_data_input(TimeSeries::Private*, int, uint); uint time_series_data_result(const TimeSeries::Private*, int); bool time_series_set_data_result(TimeSeries::Private*, int, uint); - void time_series_sort(TimeSeries::Private*, int column, Qt::SortOrder order = Qt::AscendingOrder); + void time_series_sort(TimeSeries::Private*, unsigned char column, Qt::SortOrder order = Qt::AscendingOrder); int time_series_row_count(const TimeSeries::Private*); bool time_series_can_fetch_more(const TimeSeries::Private*); @@ -174,24 +129,21 @@ QVariant TimeSeries::data(const QModelIndex &index, int role) const switch (index.column()) { case 0: switch (role) { - case 256: - case 0: - case 2: + case Qt::DisplayRole: + case Qt::EditRole: + case Qt::UserRole + 0: v = time_series_data_input(d, index.row()); break; - case 257: + case Qt::UserRole + 1: v = time_series_data_result(d, index.row()); break; } break; case 1: switch (role) { - case 256: - v = time_series_data_input(d, index.row()); - break; - case 257: - case 0: - case 2: + case Qt::DisplayRole: + case Qt::EditRole: + case Qt::UserRole + 1: v = time_series_data_result(d, index.row()); break; } @@ -201,26 +153,23 @@ QVariant TimeSeries::data(const QModelIndex &index, int role) const } QHash TimeSeries::roleNames() const { QHash names = QAbstractItemModel::roleNames(); - names.insert(256, "input"); - names.insert(257, "result"); + names.insert(Qt::UserRole + 0, "input"); + names.insert(Qt::UserRole + 1, "result"); return names; } bool TimeSeries::setData(const QModelIndex &index, const QVariant &value, int role) { bool set = false; if (index.column() == 0) { - if (role == 256 || role == 0 || role == 2) { + if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole + 0) { set = time_series_set_data_input(d, index.row(), value.value()); } - if (role == 257) { + if (role == Qt::UserRole + 1) { set = time_series_set_data_result(d, index.row(), value.value()); } } if (index.column() == 1) { - if (role == 256) { - set = time_series_set_data_input(d, index.row(), value.value()); - } - if (role == 257 || role == 0 || role == 2) { + if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole + 1) { set = time_series_set_data_result(d, index.row(), value.value()); } } @@ -229,3 +178,48 @@ bool TimeSeries::setData(const QModelIndex &index, const QVariant &value, int ro } return set; } +extern "C" { + TimeSeries::Private* time_series_new(TimeSeries*, + void (*)(const TimeSeries*), + void (*)(TimeSeries*), + void (*)(TimeSeries*), + void (*)(TimeSeries*, int, int), + void (*)(TimeSeries*), + void (*)(TimeSeries*, int, int), + void (*)(TimeSeries*)); + void time_series_free(TimeSeries::Private*); +}; +TimeSeries::TimeSeries(QObject *parent): + QAbstractItemModel(parent), + d(time_series_new(this, + [](const TimeSeries* o) { + emit o->newDataReady(QModelIndex()); + }, + [](TimeSeries* o) { + o->beginResetModel(); + }, + [](TimeSeries* o) { + o->endResetModel(); + }, + [](TimeSeries* o, int first, int last) { + o->beginInsertRows(QModelIndex(), first, last); + }, + [](TimeSeries* o) { + o->endInsertRows(); + }, + [](TimeSeries* o, int first, int last) { + o->beginRemoveRows(QModelIndex(), first, last); + }, + [](TimeSeries* o) { + o->endRemoveRows(); + } + )) { + connect(this, &TimeSeries::newDataReady, this, [this](const QModelIndex& i) { + fetchMore(i); + }, Qt::QueuedConnection); +} + + +TimeSeries::~TimeSeries() { + time_series_free(d); +} diff --git a/demo/src/Tree.cpp b/demo/src/Tree.cpp index b1d7132..8670691 100644 --- a/demo/src/Tree.cpp +++ b/demo/src/Tree.cpp @@ -55,68 +55,6 @@ void set_qbytearray(QByteArray* v, qbytearray_t* val) { *v = *val; } -extern "C" { - Tree::Private* tree_new(Tree*, void (*)(Tree*), - void (*)(const Tree*, int, quintptr), - void (*)(Tree*), - void (*)(Tree*), - void (*)(Tree*, int, quintptr, int, int), - void (*)(Tree*), - void (*)(Tree*, int, quintptr, int, int), - void (*)(Tree*)); - void tree_free(Tree::Private*); - void tree_path_get(const Tree::Private*, QString*, qstring_set); - void tree_path_set(Tree::Private*, qstring_t); - void tree_path_set_none(Tree::Private*); -}; -Tree::Tree(QObject *parent): - QAbstractItemModel(parent), - d(tree_new(this, - [](Tree* o) { emit o->pathChanged(); }, - [](const Tree* o, int row, quintptr id) { - emit o->newDataReady(o->createIndex(row, 0, id)); - }, - [](Tree* o) { - o->beginResetModel(); - }, - [](Tree* o) { - o->endResetModel(); - }, - [](Tree* o, int row, quintptr id, int first, int last) { - o->beginInsertRows(o->createIndex(row, 0, id), first, last); - }, - [](Tree* o) { - o->endInsertRows(); - }, - [](Tree* o, int row, quintptr id, int first, int last) { - o->beginRemoveRows(o->createIndex(row, 0, id), first, last); - }, - [](Tree* o) { - o->endRemoveRows(); - } - )) { - connect(this, &Tree::newDataReady, this, [this](const QModelIndex& i) { - fetchMore(i); - }, Qt::QueuedConnection); -} - - -Tree::~Tree() { - tree_free(d); -} -QString Tree::path() const -{ - QString v; - tree_path_get(d, &v, set_qstring); - return v; -} -void Tree::setPath(const QString& v) { - if (v.isNull()) { - tree_path_set_none(d); - } else { - tree_path_set(d, v); - } -} extern "C" { void tree_data_file_icon(const Tree::Private*, int, quintptr, QByteArray*, qbytearray_set); void tree_data_file_name(const Tree::Private*, int, quintptr, QString*, qstring_set); @@ -124,7 +62,7 @@ extern "C" { qint32 tree_data_file_permissions(const Tree::Private*, int, quintptr); option tree_data_file_size(const Tree::Private*, int, quintptr); qint32 tree_data_file_type(const Tree::Private*, int, quintptr); - void tree_sort(Tree::Private*, int column, Qt::SortOrder order = Qt::AscendingOrder); + void tree_sort(Tree::Private*, unsigned char column, Qt::SortOrder order = Qt::AscendingOrder); int tree_row_count(const Tree::Private*, int, quintptr); bool tree_can_fetch_more(const Tree::Private*, int, quintptr); @@ -201,131 +139,60 @@ QVariant Tree::data(const QModelIndex &index, int role) const switch (index.column()) { case 0: switch (role) { - case 256: - case 1: + case Qt::DecorationRole: + case Qt::UserRole + 0: tree_data_file_icon(d, index.row(), index.internalId(), &b, set_qbytearray); if (!b.isNull()) v.setValue(b); break; - case 257: - case 0: + case Qt::DisplayRole: + case Qt::UserRole + 1: tree_data_file_name(d, index.row(), index.internalId(), &s, set_qstring); if (!s.isNull()) v.setValue(s); break; - case 258: + case Qt::UserRole + 2: tree_data_file_path(d, index.row(), index.internalId(), &s, set_qstring); if (!s.isNull()) v.setValue(s); break; - case 259: + case Qt::UserRole + 3: v = tree_data_file_permissions(d, index.row(), index.internalId()); break; - case 260: + case Qt::UserRole + 4: v = tree_data_file_size(d, index.row(), index.internalId()); break; - case 261: + case Qt::UserRole + 5: v = tree_data_file_type(d, index.row(), index.internalId()); break; } break; case 1: switch (role) { - case 256: - tree_data_file_icon(d, index.row(), index.internalId(), &b, set_qbytearray); - if (!b.isNull()) v.setValue(b); - break; - case 257: - tree_data_file_name(d, index.row(), index.internalId(), &s, set_qstring); - if (!s.isNull()) v.setValue(s); - break; - case 258: - tree_data_file_path(d, index.row(), index.internalId(), &s, set_qstring); - if (!s.isNull()) v.setValue(s); - break; - case 259: - v = tree_data_file_permissions(d, index.row(), index.internalId()); - break; - case 260: - case 0: + case Qt::DisplayRole: + case Qt::UserRole + 4: v = tree_data_file_size(d, index.row(), index.internalId()); break; - case 261: - v = tree_data_file_type(d, index.row(), index.internalId()); - break; } break; case 2: switch (role) { - case 256: - tree_data_file_icon(d, index.row(), index.internalId(), &b, set_qbytearray); - if (!b.isNull()) v.setValue(b); - break; - case 257: - tree_data_file_name(d, index.row(), index.internalId(), &s, set_qstring); - if (!s.isNull()) v.setValue(s); - break; - case 258: - case 0: + case Qt::DisplayRole: + case Qt::UserRole + 2: tree_data_file_path(d, index.row(), index.internalId(), &s, set_qstring); if (!s.isNull()) v.setValue(s); break; - case 259: - v = tree_data_file_permissions(d, index.row(), index.internalId()); - break; - case 260: - v = tree_data_file_size(d, index.row(), index.internalId()); - break; - case 261: - v = tree_data_file_type(d, index.row(), index.internalId()); - break; } break; case 3: switch (role) { - case 256: - tree_data_file_icon(d, index.row(), index.internalId(), &b, set_qbytearray); - if (!b.isNull()) v.setValue(b); - break; - case 257: - tree_data_file_name(d, index.row(), index.internalId(), &s, set_qstring); - if (!s.isNull()) v.setValue(s); - break; - case 258: - tree_data_file_path(d, index.row(), index.internalId(), &s, set_qstring); - if (!s.isNull()) v.setValue(s); - break; - case 259: - case 0: + case Qt::DisplayRole: + case Qt::UserRole + 3: v = tree_data_file_permissions(d, index.row(), index.internalId()); break; - case 260: - v = tree_data_file_size(d, index.row(), index.internalId()); - break; - case 261: - v = tree_data_file_type(d, index.row(), index.internalId()); - break; } break; case 4: switch (role) { - case 256: - tree_data_file_icon(d, index.row(), index.internalId(), &b, set_qbytearray); - if (!b.isNull()) v.setValue(b); - break; - case 257: - tree_data_file_name(d, index.row(), index.internalId(), &s, set_qstring); - if (!s.isNull()) v.setValue(s); - break; - case 258: - tree_data_file_path(d, index.row(), index.internalId(), &s, set_qstring); - if (!s.isNull()) v.setValue(s); - break; - case 259: - v = tree_data_file_permissions(d, index.row(), index.internalId()); - break; - case 260: - v = tree_data_file_size(d, index.row(), index.internalId()); - break; - case 261: - case 0: + case Qt::DisplayRole: + case Qt::UserRole + 5: v = tree_data_file_type(d, index.row(), index.internalId()); break; } @@ -335,12 +202,12 @@ QVariant Tree::data(const QModelIndex &index, int role) const } QHash Tree::roleNames() const { QHash names = QAbstractItemModel::roleNames(); - names.insert(256, "fileIcon"); - names.insert(257, "fileName"); - names.insert(258, "filePath"); - names.insert(259, "filePermissions"); - names.insert(260, "fileSize"); - names.insert(261, "fileType"); + names.insert(Qt::UserRole + 0, "fileIcon"); + names.insert(Qt::UserRole + 1, "fileName"); + names.insert(Qt::UserRole + 2, "filePath"); + names.insert(Qt::UserRole + 3, "filePermissions"); + names.insert(Qt::UserRole + 4, "fileSize"); + names.insert(Qt::UserRole + 5, "fileType"); return names; } bool Tree::setData(const QModelIndex &index, const QVariant &value, int role) @@ -351,3 +218,68 @@ bool Tree::setData(const QModelIndex &index, const QVariant &value, int role) } return set; } +extern "C" { + Tree::Private* tree_new(Tree*, void (*)(Tree*), + void (*)(const Tree*, quintptr), + void (*)(Tree*), + void (*)(Tree*), + void (*)(Tree*, quintptr, int, int), + void (*)(Tree*), + void (*)(Tree*, quintptr, int, int), + void (*)(Tree*)); + void tree_free(Tree::Private*); + void tree_path_get(const Tree::Private*, QString*, qstring_set); + void tree_path_set(Tree::Private*, qstring_t); + void tree_path_set_none(Tree::Private*); +}; +Tree::Tree(QObject *parent): + QAbstractItemModel(parent), + d(tree_new(this, + [](Tree* o) { emit o->pathChanged(); }, + [](const Tree* o, quintptr id) { + auto i = tree_parent(o->d, id); + emit o->newDataReady(o->createIndex(i.row, 0, i.id)); + }, + [](Tree* o) { + o->beginResetModel(); + }, + [](Tree* o) { + o->endResetModel(); + }, + [](Tree* o, quintptr id, int first, int last) { + auto i = tree_parent(o->d, id); + o->beginInsertRows(o->createIndex(i.row, 0, i.id), first, last); + }, + [](Tree* o) { + o->endInsertRows(); + }, + [](Tree* o, quintptr id, int first, int last) { + auto i = tree_parent(o->d, id); + o->beginRemoveRows(o->createIndex(i.row, 0, i.id), first, last); + }, + [](Tree* o) { + o->endRemoveRows(); + } + )) { + connect(this, &Tree::newDataReady, this, [this](const QModelIndex& i) { + fetchMore(i); + }, Qt::QueuedConnection); +} + + +Tree::~Tree() { + tree_free(d); +} +QString Tree::path() const +{ + QString v; + tree_path_get(d, &v, set_qstring); + return v; +} +void Tree::setPath(const QString& v) { + if (v.isNull()) { + tree_path_set_none(d); + } else { + tree_path_set(d, v); + } +} diff --git a/dev b/dev index d587b74..a4e8886 100644 --- a/dev +++ b/dev @@ -14,4 +14,4 @@ else charts="qt5.qtcharts libsForQt5.kirigami_2" fi -nix-shell -p cmake ninja gcc rustc cargo qt5.full extra-cmake-modules kdeFrameworks.kwidgetsaddons kdeFrameworks.kcoreaddons kdeFrameworks.ki18n appstream cmakeCurses kdeFrameworks.ktexteditor qt5.qtquickcontrols2 $charts +nix-shell -p qtcreator kmail cmake ninja gcc rustc cargo qt5.full extra-cmake-modules kdeFrameworks.kwidgetsaddons kdeFrameworks.kcoreaddons kdeFrameworks.ki18n appstream cmakeCurses kdeFrameworks.ktexteditor qt5.qtquickcontrols2 $charts diff --git a/rust_qt_binding_generator/rust_qt_binding_generator.cpp b/rust_qt_binding_generator/rust_qt_binding_generator.cpp deleted file mode 100644 index 7579111..0000000 --- a/rust_qt_binding_generator/rust_qt_binding_generator.cpp +++ /dev/null @@ -1,1594 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -using std::endl; - -QTextStream out(stdout); -QTextStream err(stderr); - -enum class ObjectType { - Object, - List, - UniformTree -}; - -enum class BindingType { - Bool, - Int, - UInt, - ULongLong, - QString, - QByteArray -}; - -struct BindingTypeProperties { - QString name; - QString cppSetType; - QString cSetType; - QString rustType; - QString rustTypeInit; - bool isComplex() const { - return name.startsWith("Q"); - } -}; - -BindingTypeProperties simpleType(const char* name, const char* init) { - return { - .name = name, - .cppSetType = name, - .cSetType = name, - .rustType = name, - .rustTypeInit = init, - }; -} - -const QMap& bindingTypeProperties() { - static QMap p; - if (p.empty()) { - QMap f; - f.insert(BindingType::Bool, simpleType("bool", "true")); - f.insert(BindingType::Int, { - .name = "qint32", - .cppSetType = "qint32", - .cSetType = "qint32", - .rustType = "i32", - .rustTypeInit = "0", - }); - f.insert(BindingType::UInt, { - .name = "quint32", - .cppSetType = "uint", - .cSetType = "uint", - .rustType = "u32", - .rustTypeInit = "0" - }); - f.insert(BindingType::ULongLong, { - .name = "quint64", - .cppSetType = "quint64", - .cSetType = "quint64", - .rustType = "u64", - .rustTypeInit = "0" - }); - f.insert(BindingType::QString, { - .name = "QString", - .cppSetType = "const QString&", - .cSetType = "qstring_t", - .rustType = "String", - .rustTypeInit = "String::new()" - }); - f.insert(BindingType::QByteArray, { - .name = "QByteArray", - .cppSetType = "const QByteArray&", - .cSetType = "qbytearray_t", - .rustType = "Vec", - .rustTypeInit = "Vec::new()" - }); - p = f; - } - return p; -} - -struct Property { - QString name; - BindingTypeProperties type; - bool write; - bool optional; -}; - -struct ItemProperty { - QString name; - BindingTypeProperties type; - bool write; - bool optional; - int userRole; - QList> roles; -}; - -struct Object { - QString name; - ObjectType type; - QList properties; - QList itemProperties; - int columnCount; -}; - -struct Configuration { - QFileInfo hFile; - QFileInfo cppFile; - QDir rustdir; - QString interfaceModule; - QString implementationModule; - QString typesModule; - QList objects; - bool overwriteImplementation; -}; - -BindingTypeProperties parseBindingType(const QString& value) { - QMapIterator i(bindingTypeProperties()); - while (i.hasNext()) { - i.next(); - if (value == i.value().name) { - return i.value(); - } - } - err << QCoreApplication::translate("main", - "'%1' is not a supported type. Try one of\n").arg(value); - for (auto i: bindingTypeProperties()) { - err << " " << i.name << "\n"; - } - err.flush(); - exit(1); -} - -template -QString cppSetType(const T& p) -{ - if (p.optional) { - return "option<" + p.type.cppSetType + ">"; - } - return p.type.cppSetType; -} - -template -QString rustType(const T& p) -{ - if (p.optional) { - return "Option<" + p.type.rustType + ">"; - } - return p.type.rustType; -} - -template -QString rustCType(const T& p) -{ - if (p.optional) { - return "COption<" + p.type.rustType + ">"; - } - return p.type.rustType; -} - -template -QString rustTypeInit(const T& p) -{ - if (p.optional) { - return "None"; - } - return p.type.rustTypeInit; -} - -Property -parseProperty(const QString& name, const QJsonObject& json) { - Property p; - p.name = name; - p.type = parseBindingType(json.value("type").toString()); - p.write = json.value("write").toBool(); - p.optional = json.value("optional").toBool(); - return p; -} - -Qt::ItemDataRole parseItemDataRole(const QString& s) { - const QString name = s.left(1).toUpper() + s.mid(1) + "Role"; - int v = QMetaEnum::fromType() - .keyToValue(name.toUtf8()); - if (v >= 0) { - return (Qt::ItemDataRole)v; - } - err << QCoreApplication::translate("main", - "%1 is not a valid role name.\n").arg(s); - err.flush(); - exit(1); -} - -ItemProperty -parseItemProperty(const QString& name, const QJsonObject& json, int userRole) { - ItemProperty ip; - ip.name = name; - ip.type = parseBindingType(json.value("type").toString()); - ip.write = json.value("write").toBool(); - ip.optional = json.value("optional").toBool(); - ip.userRole = userRole; - QJsonArray roles = json.value("roles").toArray(); - for (auto r: roles) { - QList l; - for (auto v: r.toArray()) { - l.append(parseItemDataRole(v.toString())); - } - ip.roles.append(l); - } - return ip; -} - -Object -parseObject(const QString& name, const QJsonObject& json) { - Object o; - o.name = name; - QString type = json.value("type").toString(); - if (type == "List") { - o.type = ObjectType::List; - } else if (type == "UniformTree") { - o.type = ObjectType::UniformTree; - } else { - o.type = ObjectType::Object; - } - const QJsonObject& properties = json.value("properties").toObject(); - for (const QString& key: properties.keys()) { - o.properties.append(parseProperty(key, properties[key].toObject())); - } - const QJsonObject& itemProperties = json.value("itemProperties").toObject(); - if (o.type != ObjectType::Object && itemProperties.size() == 0) { - err << QCoreApplication::translate("main", - "No item properties are defined for %1.\n").arg(o.name); - err.flush(); - exit(1); - } else if (o.type == ObjectType::Object && itemProperties.size() > 0) { - err << QCoreApplication::translate("main", - "%1 is an Object and should not have itemProperties.").arg(o.name); - err.flush(); - exit(1); - } - o.columnCount = 0; - for (const QString& key: itemProperties.keys()) { - ItemProperty p = parseItemProperty(key, itemProperties[key].toObject(), - Qt::UserRole + o.itemProperties.size()); - o.columnCount = qMax(o.columnCount, p.roles.size()); - o.itemProperties.append(p); - } - return o; -} - -Configuration -parseConfiguration(const QString& path) { - QFile configurationFile(path); - const QDir base = QFileInfo(configurationFile).dir(); - if (!configurationFile.open(QIODevice::ReadOnly)) { - err << QCoreApplication::translate("main", - "Cannot read %1.\n").arg(configurationFile.fileName()); - err.flush(); - exit(1); - } - const QByteArray data(configurationFile.readAll()); - QJsonParseError error; - const QJsonDocument doc(QJsonDocument::fromJson(data, &error)); - if (error.error != QJsonParseError::NoError) { - err << error.errorString(); - err.flush(); - exit(1); - } - const QJsonObject o = doc.object(); - Configuration c; - c.cppFile = QFileInfo(base, o.value("cppFile").toString()); - QDir(c.cppFile.dir()).mkpath("."); - c.hFile = QFileInfo(c.cppFile.dir(), c.cppFile.completeBaseName() + ".h"); - const QJsonObject& object = o.value("objects").toObject(); - for (const QString& key: object.keys()) { - c.objects.append(parseObject(key, object[key].toObject())); - } - const QJsonObject rust = o.value("rust").toObject(); - 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; -} - -QString upperInitial(const QString& name) { - return name.left(1).toUpper() + name.mid(1); -} - -QString snakeCase(const QString& name) { - return name.left(1).toLower() + name.mid(1) - .replace(QRegExp("([A-Z])"), "_\\1").toLower(); -} - -QString writeProperty(const QString& name) { - return "WRITE set" + upperInitial(name) + " "; -} - -QString cGetType(const BindingTypeProperties& type) { - return type.name + "*, " + type.name.toLower() + "_set"; -} - -QString baseType(const Object& o) { - if (o.type != ObjectType::Object) { - return "QAbstractItemModel"; - } - return "QObject"; -} - -void writeHeaderItemModel(QTextStream& h) { - h << QString(R"( - int columnCount(const QModelIndex &parent = QModelIndex()) const override; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; - QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; - QModelIndex parent(const QModelIndex &index) const override; - bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - bool canFetchMore(const QModelIndex &parent) const override; - void fetchMore(const QModelIndex &parent) override; - Qt::ItemFlags flags(const QModelIndex &index) const override; - void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; - QHash roleNames() const override; -signals: - // new data is ready to be made available to the model with fetchMore() - void newDataReady(const QModelIndex &parent) const; -)"); -} - -bool isColumnWrite(const Object& o, int col) { - for (auto ip: o.itemProperties) { - if (ip.write && ip.roles.size() > col && ip.roles[col].size() > 0) { - return true; - } - } - return false; -} - -void writeCppModel(QTextStream& cpp, const Object& o) { - const QString lcname(snakeCase(o.name)); - QString indexDecl = ", int"; - QString index = ", index.row()"; - if (o.type == ObjectType::UniformTree) { - indexDecl = ", int, quintptr"; - index = ", index.row(), index.internalId()"; - } - - cpp << "extern \"C\" {\n"; - for (auto ip: o.itemProperties) { - if (ip.type.isComplex()) { - cpp << QString(" void %2_data_%3(const %1::Private*%5, %4);\n") - .arg(o.name, lcname, snakeCase(ip.name), cGetType(ip.type), indexDecl); - } else { - cpp << QString(" %4 %2_data_%3(const %1::Private*%5);\n") - .arg(o.name, lcname, snakeCase(ip.name), cppSetType(ip), indexDecl); - } - if (ip.write) { - cpp << QString(" bool %2_set_data_%3(%1::Private*%5, %4);") - .arg(o.name, lcname, snakeCase(ip.name), ip.type.cSetType, indexDecl) << endl; - if (ip.optional) { - cpp << QString(" bool %2_set_data_%3_none(%1::Private*%4);") - .arg(o.name, lcname, snakeCase(ip.name), indexDecl) << endl; - } - } - } - cpp << QString(" void %2_sort(%1::Private*, int column, Qt::SortOrder order = Qt::AscendingOrder);\n").arg(o.name, lcname); - if (o.type == ObjectType::List) { - cpp << QString(R"( - int %2_row_count(const %1::Private*); - bool %2_can_fetch_more(const %1::Private*); - void %2_fetch_more(%1::Private*); -} -int %1::columnCount(const QModelIndex &parent) const -{ - return (parent.isValid()) ? 0 : %3; -} - -bool %1::hasChildren(const QModelIndex &parent) const -{ - return rowCount(parent) > 0; -} - -int %1::rowCount(const QModelIndex &parent) const -{ - return (parent.isValid()) ? 0 : %2_row_count(d); -} - -QModelIndex %1::index(int row, int column, const QModelIndex &parent) const -{ - if (!parent.isValid() && row >= 0 && row < rowCount(parent) && column >= 0 && column < %3) { - return createIndex(row, column, (quintptr)0); - } - return QModelIndex(); -} - -QModelIndex %1::parent(const QModelIndex &) const -{ - return QModelIndex(); -} - -bool %1::canFetchMore(const QModelIndex &parent) const -{ - return (parent.isValid()) ? 0 : %2_can_fetch_more(d); -} - -void %1::fetchMore(const QModelIndex &parent) -{ - if (!parent.isValid()) { - %2_fetch_more(d); - } -} -)").arg(o.name, lcname, QString::number(o.columnCount)); - } else { - cpp << QString(R"( - int %2_row_count(const %1::Private*, int, quintptr); - bool %2_can_fetch_more(const %1::Private*, int, quintptr); - void %2_fetch_more(%1::Private*, int, quintptr); - quintptr %2_index(const %1::Private*, int, quintptr); - qmodelindex_t %2_parent(const %1::Private*, quintptr); -} -int %1::columnCount(const QModelIndex &) const -{ - return %3; -} - -bool %1::hasChildren(const QModelIndex &parent) const -{ - return rowCount(parent) > 0; -} - -int %1::rowCount(const QModelIndex &parent) const -{ - if (parent.isValid() && parent.column() != 0) { - return 0; - } - return %2_row_count(d, parent.row(), parent.internalId()); -} - -QModelIndex %1::index(int row, int column, const QModelIndex &parent) const -{ - if (row < 0 || column < 0 || column >= %3) { - return QModelIndex(); - } - if (parent.isValid() && parent.column() != 0) { - return QModelIndex(); - } - const quintptr id = %2_index(d, parent.row(), parent.internalId()); - return createIndex(row, column, id); -} - -QModelIndex %1::parent(const QModelIndex &index) const -{ - if (!index.isValid()) { - return QModelIndex(); - } - const qmodelindex_t parent = %2_parent(d, index.internalId()); - return parent.id ?createIndex(parent.row, 0, parent.id) :QModelIndex(); -} - -bool %1::canFetchMore(const QModelIndex &parent) const -{ - if (parent.isValid() && parent.column() != 0) { - return false; - } - return %2_can_fetch_more(d, parent.row(), parent.internalId()); -} - -void %1::fetchMore(const QModelIndex &parent) -{ - %2_fetch_more(d, parent.row(), parent.internalId()); -} -)").arg(o.name, lcname, QString::number(o.columnCount)); - } - - cpp << QString(R"( -void %1::sort(int column, Qt::SortOrder order) -{ - %2_sort(d, column, order); -} -Qt::ItemFlags %1::flags(const QModelIndex &i) const -{ - auto flags = QAbstractItemModel::flags(i); -)").arg(o.name, lcname); - for (int col = 0; col < o.columnCount; ++col) { - if (isColumnWrite(o, col)) { - cpp << " if (i.column() == " << col << ") {\n"; - cpp << " flags |= Qt::ItemIsEditable;\n }\n"; - } - } - cpp << QString(R"( return flags; -} -QVariant %1::data(const QModelIndex &index, int role) const -{ - QVariant v; - QString s; - QByteArray b; - switch (index.column()) { -)").arg(o.name); - - for (int col = 0; col < o.columnCount; ++col) { - cpp << QString(" case %1:\n").arg(col); - cpp << QString(" switch (role) {\n"); - for (auto ip: o.itemProperties) { - cpp << QString(" case %1:\n").arg(ip.userRole); - for (auto r: ip.roles.value(col)) { - cpp << QString(" case %1:\n").arg(r); - } - if (ip.type.name == "QString") { - cpp << QString(" %1_data_%2(d%4, &s, set_%3);\n") - .arg(lcname, snakeCase(ip.name), ip.type.name.toLower(), index); - cpp << " if (!s.isNull()) v.setValue(s);\n"; - } else if (ip.type.name == "QByteArray") { - cpp << QString(" %1_data_%2(d%4, &b, set_%3);\n") - .arg(lcname, snakeCase(ip.name), ip.type.name.toLower(), index); - cpp << " if (!b.isNull()) v.setValue(b);\n"; - } else { - cpp << QString(" v = %1_data_%2(d%3);\n") - .arg(lcname, snakeCase(ip.name), index); - } - cpp << " break;\n"; - } - cpp << " }\n"; - cpp << " break;\n"; - } - cpp << " }\n return v;\n}\n"; - cpp << "QHash " << o.name << "::roleNames() const {\n"; - cpp << " QHash names = QAbstractItemModel::roleNames();\n"; - for (auto ip: o.itemProperties) { - cpp << " names.insert(" << ip.userRole << ", \"" << ip.name << "\");\n"; - } - cpp << " return names;\n"; - cpp << QString(R"(} -bool %1::setData(const QModelIndex &index, const QVariant &value, int role) -{ -)").arg(o.name); - cpp << " bool set = false;\n"; - for (int col = 0; col < o.columnCount; ++col) { - if (!isColumnWrite(o, col)) { - continue; - } - cpp << " if (index.column() == " << col << ") {\n"; - for (auto ip: o.itemProperties) { - if (!ip.write) { - continue; - } - cpp << " if (role == " << ip.userRole; - for (auto r: ip.roles.value(col)) { - cpp << QString(" || role == %1").arg(r); - } - cpp << ") {\n"; - if (ip.optional) { - QString test = "!value.isValid()"; - if (ip.type.isComplex()) { - test += " || value.isNull()"; - } - cpp << " if (" << test << ") {\n"; - cpp << QString(" set = %1_set_data_%2_none(d%3);") - .arg(lcname, snakeCase(ip.name), index) << endl; - cpp << " } else\n"; - } - QString val = QString("value.value<%1>()").arg(ip.type.name); - cpp << QString(" set = %1_set_data_%2(d%3, %4);") - .arg(lcname, snakeCase(ip.name), index, val) << endl; - cpp << " }\n"; - } - cpp << " }\n"; - } - cpp << R"( if (set) { - emit dataChanged(index, index, QVector() << role); - } - return set; -} -)"; -} - -void writeHeaderObject(QTextStream& h, const Object& o) { - h << QString(R"( -class %1 : public %3 -{ - Q_OBJEC%2 -public: - class Private; -private: - Private * const d; -)").arg(o.name, "T", baseType(o)); - for (auto p: o.properties) { - h << QString(" Q_PROPERTY(%1 %2 READ %2 %3NOTIFY %2Changed FINAL)") - .arg(p.type.name, p.name, - p.write ? writeProperty(p.name) :"") << endl; - } - h << QString(R"(public: - explicit %1(QObject *parent = nullptr); - ~%1(); -)").arg(o.name); - for (auto p: o.properties) { - h << " " << p.type.name << " " << p.name << "() const;" << endl; - if (p.write) { - h << " void set" << upperInitial(p.name) << "(" << p.type.cppSetType << " v);" << endl; - } - } - if (baseType(o) == "QAbstractItemModel") { - writeHeaderItemModel(h); - } - h << "signals:" << endl; - for (auto p: o.properties) { - h << " void " << p.name << "Changed();" << endl; - } - h << "private:" << endl; - for (auto p: o.properties) { - h << " " << p.type.name << " m_" << p.name << ";" << endl; - } - h << "};" << endl; -} - -void writeObjectCDecl(QTextStream& cpp, const Object& o) { - const QString lcname(snakeCase(o.name)); - cpp << QString(" %1::Private* %2_new(%1*").arg(o.name, lcname); - for (int i = 0; i < o.properties.size(); ++i) { - cpp << QString(", void (*)(%1*)").arg(o.name); - } - if (o.type == ObjectType::List) { - cpp << QString(R"(, - void (*)(const %1*), - void (*)(%1*), - void (*)(%1*), - void (*)(%1*, int, int), - void (*)(%1*), - void (*)(%1*, int, int), - void (*)(%1*))").arg(o.name); - } - if (o.type == ObjectType::UniformTree) { - cpp << QString(R"(, - void (*)(const %1*, int, quintptr), - void (*)(%1*), - void (*)(%1*), - void (*)(%1*, int, quintptr, int, int), - void (*)(%1*), - void (*)(%1*, int, quintptr, int, int), - void (*)(%1*))").arg(o.name); - } - cpp << ");" << endl; - cpp << QString(" void %2_free(%1::Private*);").arg(o.name, lcname) - << endl; - for (const Property& p: o.properties) { - const QString base = QString("%1_%2").arg(lcname, snakeCase(p.name)); - if (p.type.isComplex()) { - cpp << QString(" void %2_get(const %1::Private*, %3);") - .arg(o.name, base, cGetType(p.type)) << endl; - } else { - cpp << QString(" %3 %2_get(const %1::Private*);") - .arg(o.name, base, p.type.name) << endl; - } - if (p.write) { - cpp << QString(" void %2_set(%1::Private*, %3);") - .arg(o.name, base, p.type.cSetType) << endl; - if (p.optional) { - cpp << QString(" void %2_set_none(%1::Private*);") - .arg(o.name, base) << endl; - } - } - } -} - -void writeCppObject(QTextStream& cpp, const Object& o) { - const QString lcname(snakeCase(o.name)); - cpp << QString("%1::%1(QObject *parent):\n %2(parent),") - .arg(o.name, baseType(o)) << endl; - cpp << QString(" d(%1_new(this").arg(lcname); - for (const Property& p: o.properties) { - cpp << QString(",\n [](%1* o) { emit o->%2Changed(); }") - .arg(o.name, p.name); - } - if (o.type == ObjectType::List) { - cpp << QString(R"(, - [](const %1* o) { - emit o->newDataReady(QModelIndex()); - }, - [](%1* o) { - o->beginResetModel(); - }, - [](%1* o) { - o->endResetModel(); - }, - [](%1* o, int first, int last) { - o->beginInsertRows(QModelIndex(), first, last); - }, - [](%1* o) { - o->endInsertRows(); - }, - [](%1* o, int first, int last) { - o->beginRemoveRows(QModelIndex(), first, last); - }, - [](%1* o) { - o->endRemoveRows(); - } - )) { - connect(this, &%1::newDataReady, this, [this](const QModelIndex& i) { - fetchMore(i); - }, Qt::QueuedConnection); -} -)").arg(o.name); - } - if (o.type == ObjectType::UniformTree) { - cpp << QString(R"(, - [](const %1* o, int row, quintptr id) { - emit o->newDataReady(o->createIndex(row, 0, id)); - }, - [](%1* o) { - o->beginResetModel(); - }, - [](%1* o) { - o->endResetModel(); - }, - [](%1* o, int row, quintptr id, int first, int last) { - o->beginInsertRows(o->createIndex(row, 0, id), first, last); - }, - [](%1* o) { - o->endInsertRows(); - }, - [](%1* o, int row, quintptr id, int first, int last) { - o->beginRemoveRows(o->createIndex(row, 0, id), first, last); - }, - [](%1* o) { - o->endRemoveRows(); - } - )) { - connect(this, &%1::newDataReady, this, [this](const QModelIndex& i) { - fetchMore(i); - }, Qt::QueuedConnection); -} -)").arg(o.name); - } - if (o.type == ObjectType::Object) { - cpp << QString(")) {}"); - } - cpp << QString(R"( - -%1::~%1() { - %2_free(d); -} -)").arg(o.name, lcname); - - for (const Property& p: o.properties) { - const QString base = QString("%1_%2").arg(lcname, snakeCase(p.name)); - cpp << QString("%3 %1::%2() const\n{\n").arg(o.name, p.name, p.type.name); - if (p.type.isComplex()) { - cpp << " " << p.type.name << " v;\n"; - cpp << " " << base << "_get(d, &v, set_" << p.type.name.toLower() - << ");\n"; - cpp << " return v;\n}\n"; - } else { - cpp << QString(" return %1_get(d);\n}\n").arg(base); - } - if (p.write) { - cpp << "void " << o.name << "::set" << upperInitial(p.name) << "(" << p.type.cppSetType << " v) {" << endl; - if (p.optional) { - cpp << QString(" if (v.isNull()) {") << endl; - cpp << QString(" %1_set_none(d);").arg(base) << endl; - cpp << QString(" } else {") << endl; - cpp << QString(" %1_set(d, v);").arg(base) << endl; - cpp << QString(" }") << endl; - } else { - cpp << QString(" %1_set(d, v);").arg(base) << endl; - } - cpp << "}" << endl; - } - } - if (o.type != ObjectType::Object) { - writeCppModel(cpp, o); - } -} - -// Only write a file if it is different -class DifferentFileWriter { -public: - const QString path; - QByteArray buffer; - bool overwrite; - DifferentFileWriter(const QString& p, bool o = true) :path(p), overwrite(o) - { - } - ~DifferentFileWriter() { - const QByteArray old = read(); - if (old != buffer && (old.isNull() || overwrite)) { - write(); - } - } - QByteArray read() const { - QByteArray content; - QFile file(path); - if (file.open(QIODevice::ReadOnly)) { - content = file.readAll(); - } - return content; - } - void write() const { - QFile file(path); - if (!file.open(QIODevice::WriteOnly)) { - err << QCoreApplication::translate("main", - "Cannot write %1.\n").arg(file.fileName()); - err.flush(); - exit(1); - } - file.write(buffer); - file.close(); - } -}; - -void writeHeader(const Configuration& conf) { - DifferentFileWriter w(conf.hFile.absoluteFilePath()); - QTextStream h(&w.buffer); - const QString guard(conf.hFile.fileName().replace('.', '_').toUpper()); - h << QString(R"(/* generated by rust_qt_binding_generator */ -#ifndef %1 -#define %1 - -#include -#include -)").arg(guard); - - for (auto object: conf.objects) { - writeHeaderObject(h, object); - } - - h << QString("#endif // %1\n").arg(guard); -} - -void writeCpp(const Configuration& conf) { - DifferentFileWriter w(conf.cppFile.absoluteFilePath()); - QTextStream cpp(&w.buffer); - cpp << QString(R"(/* generated by rust_qt_binding_generator */ -#include "%1" - -namespace { - template - struct option { - private: - T value; - bool some; - public: - operator QVariant() const { - if (some) { - return QVariant(value); - } - return QVariant(); - } - }; - struct qbytearray_t { - private: - const char* data; - int len; - public: - qbytearray_t(const QByteArray& v): - data(v.data()), - len(v.size()) { - } - operator QByteArray() const { - return QByteArray(data, len); - } - }; - struct qstring_t { - private: - const void* data; - int len; - public: - qstring_t(const QString& v): - data(static_cast(v.utf16())), - len(v.size()) { - } - operator QString() const { - return QString::fromUtf8(static_cast(data), len); - } - }; - struct qmodelindex_t { - int row; - quintptr id; - }; -} -typedef void (*qstring_set)(QString*, qstring_t*); -void set_qstring(QString* v, qstring_t* val) { - *v = *val; -} -typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*); -void set_qbytearray(QByteArray* v, qbytearray_t* val) { - *v = *val; -} - -extern "C" { -)").arg(conf.hFile.fileName()); - - for (auto object: conf.objects) { - writeObjectCDecl(cpp, object); - } - cpp << "};" << endl; - - for (auto object: conf.objects) { - writeCppObject(cpp, object); - } -} - -void writeRustInterfaceObject(QTextStream& r, const Object& o) { - const QString lcname(snakeCase(o.name)); - r << QString(R"( -pub struct %1QObject {} - -#[derive (Clone)] -pub struct %1Emitter { - qobject: Arc>, -)").arg(o.name); - for (const Property& p: o.properties) { - r << QString(" %2_changed: fn(*const %1QObject),\n") - .arg(o.name, snakeCase(p.name)); - } - if (o.type == ObjectType::List) { - r << QString(" new_data_ready: fn(*const %1QObject),\n") - .arg(o.name); - } else if (o.type == ObjectType::UniformTree) { - r << QString(" new_data_ready: fn(*const %1QObject, row: c_int, parent: usize),\n") - .arg(o.name); - } - r << QString(R"(} - -unsafe impl Send for %1Emitter {} - -impl %1Emitter { - fn clear(&self) { - *self.qobject.lock().unwrap() = null(); - } -)").arg(o.name); - for (const Property& p: o.properties) { - r << QString(R"( pub fn %1_changed(&self) { - let ptr = *self.qobject.lock().unwrap(); - if !ptr.is_null() { - (self.%1_changed)(ptr); - } - } -)").arg(snakeCase(p.name)); - } - if (o.type == ObjectType::List) { - r << R"( pub fn new_data_ready(&self) { - let ptr = *self.qobject.lock().unwrap(); - if !ptr.is_null() { - (self.new_data_ready)(ptr); - } - } -)"; - } else if (o.type == ObjectType::UniformTree) { - r << R"( pub fn new_data_ready(&self, row: c_int, parent: usize) { - let ptr = *self.qobject.lock().unwrap(); - if !ptr.is_null() { - (self.new_data_ready)(ptr, row, parent); - } - } -)"; - } - - QString modelStruct = ""; - if (o.type != ObjectType::Object) { - QString type = o.type == ObjectType::List ? "List" : "UniformTree"; - modelStruct = ", model: " + o.name + type; - QString index; - QString indexDecl; - if (o.type == ObjectType::UniformTree) { - indexDecl = "row: c_int, parent: usize,"; - index = "row, parent,"; - } - r << QString(R"(} - -pub struct %1%2 { - qobject: *const %1QObject, - begin_reset_model: fn(*const %1QObject), - end_reset_model: fn(*const %1QObject), - begin_insert_rows: fn(*const %1QObject,%3 c_int, c_int), - end_insert_rows: fn(*const %1QObject), - begin_remove_rows: fn(*const %1QObject,%3 c_int, c_int), - end_remove_rows: fn(*const %1QObject), -} - -impl %1%2 { - pub fn begin_reset_model(&self) { - (self.begin_reset_model)(self.qobject); - } - pub fn end_reset_model(&self) { - (self.end_reset_model)(self.qobject); - } - pub fn begin_insert_rows(&self,%3 first: c_int, last: c_int) { - (self.begin_insert_rows)(self.qobject,%4 first, last); - } - pub fn end_insert_rows(&self) { - (self.end_insert_rows)(self.qobject); - } - pub fn begin_remove_rows(&self,%3 first: c_int, last: c_int) { - (self.begin_remove_rows)(self.qobject,%4 first, last); - } - pub fn end_remove_rows(&self) { - (self.end_remove_rows)(self.qobject); - } -)").arg(o.name, type, indexDecl, index); - } - - r << QString(R"(} - -pub trait %1Trait { - fn create(emit: %1Emitter%2) -> Self; - fn emit(&self) -> &%1Emitter; -)").arg(o.name, modelStruct); - for (const Property& p: o.properties) { - const QString lc(snakeCase(p.name)); - r << QString(" fn get_%1(&self) -> %2;\n").arg(lc, rustType(p)); - if (p.write) { - r << QString(" fn set_%1(&mut self, value: %2);\n").arg(lc, rustType(p)); - } - } - if (o.type != ObjectType::Object) { - QString index; - if (o.type == ObjectType::UniformTree) { - index = ", row: c_int, parent: usize"; - } - r << QString(" fn row_count(&self%1) -> c_int;\n").arg(index); - if (o.type == ObjectType::UniformTree) { - index = ", c_int, usize"; - } - r << QString(R"( fn can_fetch_more(&self%1) -> bool { false } - fn fetch_more(&mut self%1) {} - fn sort(&mut self, c_int, SortOrder) {} -)").arg(index); - if (o.type == ObjectType::List) { - index = ", row: c_int"; - } else if (o.type == ObjectType::UniformTree) { - index = ", row: c_int, parent: usize"; - } - for (auto ip: o.itemProperties) { - r << QString(" fn %1(&self%3) -> %2;\n") - .arg(snakeCase(ip.name), rustType(ip), index); - if (ip.write) { - r << QString(" fn set_%1(&mut self%3, %2) -> bool;\n") - .arg(snakeCase(ip.name), rustType(ip), index); - } - } - } - if (o.type == ObjectType::UniformTree) { - r << " fn index(&self, row: c_int, parent: usize) -> usize;\n"; - r << " fn parent(&self, parent: usize) -> QModelIndex;\n"; - } - - r << QString(R"(} - -#[no_mangle] -pub extern "C" fn %2_new(qobject: *const %1QObject)").arg(o.name, lcname); - for (const Property& p: o.properties) { - r << QString(",\n %2_changed: fn(*const %1QObject)") - .arg(o.name, snakeCase(p.name)); - } - if (o.type == ObjectType::List) { - r << QString(",\n new_data_ready: fn(*const %1QObject)") - .arg(o.name); - } else if (o.type == ObjectType::UniformTree) { - r << QString(",\n new_data_ready: fn(*const %1QObject, row: c_int, parent: usize)") - .arg(o.name); - } - if (o.type != ObjectType::Object) { - QString indexDecl; - if (o.type == ObjectType::UniformTree) { - indexDecl = "row: c_int, parent: usize,"; - } - r << QString(R"(, - begin_reset_model: fn(*const %1QObject), - end_reset_model: fn(*const %1QObject), - begin_insert_rows: fn(*const %1QObject,%2 - c_int, - c_int), - end_insert_rows: fn(*const %1QObject), - begin_remove_rows: fn(*const %1QObject,%2 - c_int, - c_int), - end_remove_rows: fn(*const %1QObject))").arg(o.name, indexDecl); - } - r << QString(R"() - -> *mut %1 { - let emit = %1Emitter { - qobject: Arc::new(Mutex::new(qobject)), -)").arg(o.name); - for (const Property& p: o.properties) { - r << QString(" %1_changed: %1_changed,\n").arg(snakeCase(p.name)); - } - if (o.type != ObjectType::Object) { - r << QString(" new_data_ready: new_data_ready,\n"); - } - QString model = ""; - if (o.type != ObjectType::Object) { - const QString type = o.type == ObjectType::List ? "List" : "UniformTree"; - model = ", model"; - r << QString(R"( }; - let model = %1%2 { - qobject: qobject, - begin_reset_model: begin_reset_model, - end_reset_model: end_reset_model, - begin_insert_rows: begin_insert_rows, - end_insert_rows: end_insert_rows, - begin_remove_rows: begin_remove_rows, - end_remove_rows: end_remove_rows, -)").arg(o.name, type); - } - r << QString(R"( }; - let d = %1::create(emit%3); - Box::into_raw(Box::new(d)) -} - -#[no_mangle] -pub unsafe extern "C" fn %2_free(ptr: *mut %1) { - Box::from_raw(ptr).emit().clear(); -} -)").arg(o.name, lcname, model); - for (const Property& p: o.properties) { - const QString base = QString("%1_%2").arg(lcname, snakeCase(p.name)); - QString ret = ") -> " + rustType(p); - if (p.type.isComplex() && !p.optional) { - r << QString(R"( -#[no_mangle] -pub unsafe extern "C" fn %2_get(ptr: *const %1, - p: *mut c_void, - set: fn(*mut c_void, %4)) { - let data = (&*ptr).get_%3(); - set(p, %4::from(&data)); -} -)").arg(o.name, base, snakeCase(p.name), p.type.name); - if (p.write) { - const QString type = p.type.name == "QString" ? "QStringIn" : p.type.name; - r << QString(R"( -#[no_mangle] -pub unsafe extern "C" fn %2_set(ptr: *mut %1, v: %4) { - (&mut *ptr).set_%3(v.convert()); -} -)").arg(o.name, base, snakeCase(p.name), type); - } - } else if (p.type.isComplex()) { - r << QString(R"( -#[no_mangle] -pub unsafe extern "C" fn %2_get(ptr: *const %1, - p: *mut c_void, - set: fn(*mut c_void, %4)) { - let data = (&*ptr).get_%3(); - if let Some(data) = data { - set(p, %4::from(&data)); - } -} -)").arg(o.name, base, snakeCase(p.name), p.type.name); - if (p.write) { - const QString type = p.type.name == "QString" ? "QStringIn" : p.type.name; - r << QString(R"( -#[no_mangle] -pub unsafe extern "C" fn %2_set(ptr: *mut %1, v: %4) { - (&mut *ptr).set_%3(Some(v.convert())); -} -#[no_mangle] -pub unsafe extern "C" fn %2_set_none(ptr: *mut %1) { - (&mut *ptr).set_%3(None); -} -)").arg(o.name, base, snakeCase(p.name), type); - } - } else { - r << QString(R"( -#[no_mangle] -pub unsafe extern "C" fn %2_get(ptr: *const %1) -> %4 { - (&*ptr).get_%3() -} -)").arg(o.name, base, snakeCase(p.name), rustType(p)); - if (p.write) { - r << QString(R"( -#[no_mangle] -pub unsafe extern "C" fn %2_set(ptr: *mut %1, v: %4) { - (&mut *ptr).set_%3(v); -} -)").arg(o.name, base, snakeCase(p.name), rustType(p)); - } - } - } - if (o.type != ObjectType::Object) { - QString indexDecl; - QString index; - if (o.type == ObjectType::UniformTree) { - indexDecl = ", row: c_int, parent: usize"; - index = "row, parent"; - } - r << QString(R"( -#[no_mangle] -pub unsafe extern "C" fn %2_row_count(ptr: *const %1%3) -> c_int { - (&*ptr).row_count(%4) -} -#[no_mangle] -pub unsafe extern "C" fn %2_can_fetch_more(ptr: *const %1%3) -> bool { - (&*ptr).can_fetch_more(%4) -} -#[no_mangle] -pub unsafe extern "C" fn %2_fetch_more(ptr: *mut %1%3) { - (&mut *ptr).fetch_more(%4) -} -#[no_mangle] -pub unsafe extern "C" fn %2_sort(ptr: *mut %1, column: c_int, order: SortOrder) { - (&mut *ptr).sort(column, order) -} -)").arg(o.name, lcname, indexDecl, index); - if (o.type == ObjectType::UniformTree) { - indexDecl = ", parent: usize"; - index = ", parent"; - } - for (auto ip: o.itemProperties) { - if (ip.type.isComplex() && !ip.optional) { - r << QString(R"( -#[no_mangle] -pub unsafe extern "C" fn %2_data_%3(ptr: *const %1, - row: c_int%5, - d: *mut c_void, - set: fn(*mut c_void, %4)) { - let data = (&*ptr).%3(row%6); - set(d, %4::from(&data)); -} -)").arg(o.name, lcname, snakeCase(ip.name), ip.type.name, indexDecl, index); - } else if (ip.type.isComplex()) { - r << QString(R"( -#[no_mangle] -pub unsafe extern "C" fn %2_data_%3(ptr: *const %1, - row: c_int%5, - d: *mut c_void, - set: fn(*mut c_void, %4)) { - let data = (&*ptr).%3(row%6); - if let Some(data) = data { - set(d, %4::from(&data)); - } -} -)").arg(o.name, lcname, snakeCase(ip.name), ip.type.name, indexDecl, index); - } else { - r << QString(R"( -#[no_mangle] -pub unsafe extern "C" fn %2_data_%3(ptr: *const %1, row: c_int%5) -> %4 { - (&*ptr).%3(row%6).into() -} -)").arg(o.name, lcname, snakeCase(ip.name), rustCType(ip), indexDecl, index); - } - if (ip.write) { - QString val = "v"; - QString type = ip.type.rustType; - if (ip.type.isComplex()) { - val = val + ".convert()"; - type = ip.type.name == "QString" ? "QStringIn" : ip.type.name; - } - if (ip.optional) { - val = "Some(" + val + ")"; - } - r << QString(R"( -#[no_mangle] -pub unsafe extern "C" fn %2_set_data_%3(ptr: *mut %1, row: c_int%4, v: %6) -> bool { - (&mut *ptr).set_%3(row%5, %7) -} -)").arg(o.name, lcname, snakeCase(ip.name), indexDecl, index, type, val); - } - if (ip.write && ip.optional) { - r << QString(R"( -#[no_mangle] -pub unsafe extern "C" fn %2_set_data_%3_none(ptr: *mut %1, row: c_int%4) -> bool { - (&mut *ptr).set_%3(row%5, None) -} -)").arg(o.name, lcname, snakeCase(ip.name), indexDecl, index); - } - } - } - if (o.type == ObjectType::UniformTree) { - r << QString(R"( -#[no_mangle] -pub unsafe extern "C" fn %2_index(ptr: *const %1, row: c_int, parent: usize) -> usize { - (&*ptr).index(row, parent) -} -#[no_mangle] -pub unsafe extern "C" fn %2_parent(ptr: *const %1, parent: usize) -> QModelIndex { - (&*ptr).parent(parent) -} -)").arg(o.name, lcname); - - } -} - -QString rustFile(const QDir rustdir, const QString& module) { - QDir src(rustdir.absoluteFilePath("src")); - QString path = src.absoluteFilePath(module + ".rs"); - return path; -} - -void writeRustInterface(const Configuration& conf) { - DifferentFileWriter w(rustFile(conf.rustdir, conf.interfaceModule)); - QTextStream r(&w.buffer); - r << QString(R"(/* generated by rust_qt_binding_generator */ -#![allow(unknown_lints)] -#![allow(mutex_atomic, needless_pass_by_value)] -#![allow(unused_imports)] -use libc::{c_int, c_uint, c_void}; -use types::*; -use std::sync::{Arc, Mutex}; -use std::ptr::null; - -use %1::*; -)").arg(conf.implementationModule); - - for (auto object: conf.objects) { - writeRustInterfaceObject(r, object); - } -} - -void writeRustImplementationObject(QTextStream& r, const Object& o) { - const QString lcname(snakeCase(o.name)); - if (o.type != ObjectType::Object) { - r << "#[derive (Default, Clone)]\n"; - r << QString("struct %1Item {\n").arg(o.name); - for (auto ip: o.itemProperties) { - const QString lc(snakeCase(ip.name)); - r << QString(" %1: %2,\n").arg(lc, ip.type.rustType); - } - r << "}\n\n"; - } - QString modelStruct = ""; - r << QString("pub struct %1 {\n emit: %1Emitter,\n").arg((o.name)); - if (o.type == ObjectType::List) { - modelStruct = ", model: " + o.name + "List"; - r << QString(" model: %1List,\n").arg(o.name); - } else if (o.type == ObjectType::UniformTree) { - modelStruct = ", model: " + o.name + "UniformTree"; - r << QString(" model: %1UniformTree,\n").arg(o.name); - } - for (const Property& p: o.properties) { - const QString lc(snakeCase(p.name)); - r << QString(" %1: %2,\n").arg(lc, rustType(p)); - } - if (o.type != ObjectType::Object) { - r << QString(" list: Vec<%1Item>,\n").arg(o.name); - } - r << "}\n\n"; - r << QString(R"(impl %1Trait for %1 { - fn create(emit: %1Emitter%2) -> %1 { - %1 { - emit: emit, -)").arg(o.name, modelStruct); - if (o.type != ObjectType::Object) { - r << QString(" model: model,\n"); - } - for (const Property& p: o.properties) { - const QString lc(snakeCase(p.name)); - r << QString(" %1: %2,\n").arg(lc, rustTypeInit(p)); - } - if (o.type != ObjectType::Object) { - r << QString(" list: vec![%1Item::default(); 10],\n") - .arg(o.name); - } - r << QString(R"( } - } - fn emit(&self) -> &%1Emitter { - &self.emit - } -)").arg(o.name); - for (const Property& p: o.properties) { - const QString lc(snakeCase(p.name)); - r << QString(" fn get_%1(&self) -> %2 {\n").arg(lc, rustType(p)); - if (p.type.isComplex()) { - r << QString(" self.%1.clone()\n").arg(lc); - } else { - r << QString(" self.%1\n").arg(lc); - } - r << " }\n"; - if (p.write) { - r << QString(R"( fn set_%1(&mut self, value: %2) { - self.%1 = value; - self.emit.%1_changed(); - } -)").arg(lc, rustType(p)); - } - } - if (o.type != ObjectType::Object) { - QString index; - if (o.type == ObjectType::UniformTree) { - index = ", row: c_int, parent: usize"; - } - r << " fn row_count(&self" << index << ") -> c_int {\n self.list.len() as c_int\n }\n"; - if (o.type == ObjectType::UniformTree) { - index = ", parent: usize"; - } - for (auto ip: o.itemProperties) { - const QString lc(snakeCase(ip.name)); - r << QString(" fn %1(&self, row: c_int%3) -> %2 {\n") - .arg(lc, rustType(ip), index); - r << " self.list[row as usize]." << lc << ".clone()\n"; - r << " }\n"; - if (ip.write) { - r << QString(" fn set_%1(&mut self, row: c_int%3, v: %2) -> bool {\n") - .arg(snakeCase(ip.name), rustType(ip), index); - r << " self.list[row as usize]." << lc << " = v;\n"; - r << " true\n"; - r << " }\n"; - } - } - } - if (o.type == ObjectType::UniformTree) { - r << R"( fn index(&self, row: c_int, parent: usize) -> usize { - 0 - } - fn parent(&self, parent: usize) -> QModelIndex { - QModelIndex::create(0, 0) - } -)"; - } - r << "}\n"; -} - -void writeRustImplementation(const Configuration& conf) { - DifferentFileWriter w(rustFile(conf.rustdir, conf.implementationModule), - conf.overwriteImplementation); - QTextStream r(&w.buffer); - r << QString(R"(#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] -use libc::c_int; -use libc::c_uint; -use types::*; -use %1::*; - -)").arg(conf.interfaceModule); - - for (auto object: conf.objects) { - writeRustImplementationObject(r, object); - } -} - -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 */ -#![allow(dead_code)] -use std::slice; -use libc::{c_int, uint8_t, uint16_t}; - -#[repr(C)] -pub struct COption { - data: T, - some: bool, -} - -impl From> for COption where T: Default { - fn from(t: Option) -> COption { - if let Some(v) = t { - COption { - data: v, - some: true - } - } else { - COption { - data: T::default(), - some: false - } - } - } -} - -#[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(), - } - } -} - -#[repr(C)] -pub struct QModelIndex { - row: c_int, - internal_id: usize, -} - -impl QModelIndex { - pub fn invalid() -> QModelIndex { - QModelIndex { - row: -1, - internal_id: 0, - } - } - pub fn create(row: c_int, id: usize) -> QModelIndex { - QModelIndex { - row: row, - internal_id: id, - } - } -} - -#[repr(C)] -pub enum SortOrder { - Ascending = 0, - Descending = 1 -} - -)"); -} - -int main(int argc, char *argv[]) { - QCoreApplication app(argc, argv); - QCoreApplication::setApplicationName(argv[0]); - QCoreApplication::setApplicationVersion("0.1"); - - QCommandLineParser parser; - parser.setApplicationDescription("Generates bindings between Qt and Rust"); - parser.addHelpOption(); - parser.addVersionOption(); - parser.addPositionalArgument("configuration", - QCoreApplication::translate("main", "Configuration file(s)")); - - // A boolean option (--overwrite-implementation) - QCommandLineOption overwriteOption(QStringList() - << "overwrite-implementation", - QCoreApplication::translate("main", - "Overwrite existing implementation.")); - parser.addOption(overwriteOption); - - parser.process(app); - - const QStringList args = parser.positionalArguments(); - if (args.isEmpty()) { - err << QCoreApplication::translate("main", - "Configuration file is missing.\n"); - return 1; - } - - for (auto path: args) { - const QString configurationFile(path); - Configuration configuration = parseConfiguration(configurationFile); - configuration.overwriteImplementation = parser.isSet(overwriteOption); - - writeHeader(configuration); - writeCpp(configuration); - writeRustInterface(configuration); - writeRustImplementation(configuration); - writeRustTypes(configuration); - } - - return 0; -} diff --git a/rust_qt_binding_generator/CMakeLists.txt b/src/CMakeLists.txt similarity index 64% rename from rust_qt_binding_generator/CMakeLists.txt rename to src/CMakeLists.txt index 3739a2b..bc6d40f 100644 --- a/rust_qt_binding_generator/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,6 @@ -add_executable(rust_qt_binding_generator rust_qt_binding_generator.cpp) +add_executable(rust_qt_binding_generator main.cpp + parseJson.cpp cpp.cpp rust.cpp helper.cpp) target_link_libraries(rust_qt_binding_generator Qt5::Core ) diff --git a/rust_qt_binding_generator/README.md b/src/README.md similarity index 100% rename from rust_qt_binding_generator/README.md rename to src/README.md diff --git a/src/cpp.cpp b/src/cpp.cpp new file mode 100644 index 0000000..09492ea --- /dev/null +++ b/src/cpp.cpp @@ -0,0 +1,603 @@ +#include "structs.h" +#include "cpp.h" +#include "helper.h" +#include + +template +QString cppSetType(const T& p) +{ + if (p.optional) { + return "option<" + p.type.cppSetType + ">"; + } + return p.type.cppSetType; +} + +QString upperInitial(const QString& name) { + return name.left(1).toUpper() + name.mid(1); +} + +QString writeProperty(const QString& name) { + return "WRITE set" + upperInitial(name) + " "; +} + +QString baseType(const Object& o) { + if (o.type != ObjectType::Object) { + return "QAbstractItemModel"; + } + return "QObject"; +} + +QString cGetType(const BindingTypeProperties& type) { + return type.name + "*, " + type.name.toLower() + "_set"; +} + +void writeHeaderItemModel(QTextStream& h) { + h << QString(R"( + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &index) const override; + bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + bool canFetchMore(const QModelIndex &parent) const override; + void fetchMore(const QModelIndex &parent) override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; + QHash roleNames() const override; +signals: + // new data is ready to be made available to the model with fetchMore() + void newDataReady(const QModelIndex &parent) const; +)"); +} + +bool isColumnWrite(const Object& o, int col) { + for (auto ip: o.itemProperties) { + if (ip.write && ip.roles.size() > col && ip.roles[col].size() > 0) { + return true; + } + } + return false; +} + +void writeCppModel(QTextStream& cpp, const Object& o) { + const QString lcname(snakeCase(o.name)); + QString indexDecl = ", int"; + QString index = ", index.row()"; + if (o.type == ObjectType::UniformTree) { + indexDecl = ", int, quintptr"; + index = ", index.row(), index.internalId()"; + } + + cpp << "extern \"C\" {\n"; + for (auto ip: o.itemProperties) { + if (ip.type.isComplex()) { + cpp << QString(" void %2_data_%3(const %1::Private*%5, %4);\n") + .arg(o.name, lcname, snakeCase(ip.name), cGetType(ip.type), indexDecl); + } else { + cpp << QString(" %4 %2_data_%3(const %1::Private*%5);\n") + .arg(o.name, lcname, snakeCase(ip.name), cppSetType(ip), indexDecl); + } + if (ip.write) { + cpp << QString(" bool %2_set_data_%3(%1::Private*%5, %4);") + .arg(o.name, lcname, snakeCase(ip.name), ip.type.cSetType, indexDecl) << endl; + if (ip.optional) { + cpp << QString(" bool %2_set_data_%3_none(%1::Private*%4);") + .arg(o.name, lcname, snakeCase(ip.name), indexDecl) << endl; + } + } + } + cpp << QString(" void %2_sort(%1::Private*, unsigned char column, Qt::SortOrder order = Qt::AscendingOrder);\n").arg(o.name, lcname); + if (o.type == ObjectType::List) { + cpp << QString(R"( + int %2_row_count(const %1::Private*); + bool %2_can_fetch_more(const %1::Private*); + void %2_fetch_more(%1::Private*); +} +int %1::columnCount(const QModelIndex &parent) const +{ + return (parent.isValid()) ? 0 : %3; +} + +bool %1::hasChildren(const QModelIndex &parent) const +{ + return rowCount(parent) > 0; +} + +int %1::rowCount(const QModelIndex &parent) const +{ + return (parent.isValid()) ? 0 : %2_row_count(d); +} + +QModelIndex %1::index(int row, int column, const QModelIndex &parent) const +{ + if (!parent.isValid() && row >= 0 && row < rowCount(parent) && column >= 0 && column < %3) { + return createIndex(row, column, (quintptr)0); + } + return QModelIndex(); +} + +QModelIndex %1::parent(const QModelIndex &) const +{ + return QModelIndex(); +} + +bool %1::canFetchMore(const QModelIndex &parent) const +{ + return (parent.isValid()) ? 0 : %2_can_fetch_more(d); +} + +void %1::fetchMore(const QModelIndex &parent) +{ + if (!parent.isValid()) { + %2_fetch_more(d); + } +} +)").arg(o.name, lcname, QString::number(o.columnCount)); + } else { + cpp << QString(R"( + int %2_row_count(const %1::Private*, int, quintptr); + bool %2_can_fetch_more(const %1::Private*, int, quintptr); + void %2_fetch_more(%1::Private*, int, quintptr); + quintptr %2_index(const %1::Private*, int, quintptr); + qmodelindex_t %2_parent(const %1::Private*, quintptr); +} +int %1::columnCount(const QModelIndex &) const +{ + return %3; +} + +bool %1::hasChildren(const QModelIndex &parent) const +{ + return rowCount(parent) > 0; +} + +int %1::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid() && parent.column() != 0) { + return 0; + } + return %2_row_count(d, parent.row(), parent.internalId()); +} + +QModelIndex %1::index(int row, int column, const QModelIndex &parent) const +{ + if (row < 0 || column < 0 || column >= %3) { + return QModelIndex(); + } + if (parent.isValid() && parent.column() != 0) { + return QModelIndex(); + } + const quintptr id = %2_index(d, parent.row(), parent.internalId()); + return createIndex(row, column, id); +} + +QModelIndex %1::parent(const QModelIndex &index) const +{ + if (!index.isValid()) { + return QModelIndex(); + } + const qmodelindex_t parent = %2_parent(d, index.internalId()); + return parent.id ?createIndex(parent.row, 0, parent.id) :QModelIndex(); +} + +bool %1::canFetchMore(const QModelIndex &parent) const +{ + if (parent.isValid() && parent.column() != 0) { + return false; + } + return %2_can_fetch_more(d, parent.row(), parent.internalId()); +} + +void %1::fetchMore(const QModelIndex &parent) +{ + %2_fetch_more(d, parent.row(), parent.internalId()); +} +)").arg(o.name, lcname, QString::number(o.columnCount)); + } + + cpp << QString(R"( +void %1::sort(int column, Qt::SortOrder order) +{ + %2_sort(d, column, order); +} +Qt::ItemFlags %1::flags(const QModelIndex &i) const +{ + auto flags = QAbstractItemModel::flags(i); +)").arg(o.name, lcname); + for (int col = 0; col < o.columnCount; ++col) { + if (isColumnWrite(o, col)) { + cpp << " if (i.column() == " << col << ") {\n"; + cpp << " flags |= Qt::ItemIsEditable;\n }\n"; + } + } + cpp << QString(R"( return flags; +} +QVariant %1::data(const QModelIndex &index, int role) const +{ + QVariant v; + QString s; + QByteArray b; + switch (index.column()) { +)").arg(o.name); + + auto metaRoles = QMetaEnum::fromType(); + for (int col = 0; col < o.columnCount; ++col) { + cpp << QString(" case %1:\n").arg(col); + cpp << QString(" switch (role) {\n"); + for (int i = 0; i < o.itemProperties.size(); ++i) { + auto ip = o.itemProperties[i]; + auto roles = ip.roles.value(col); + if (col > 0 && roles.size() == 0) { + continue; + } + for (auto role: roles) { + cpp << QString(" case Qt::%1:\n").arg(metaRoles.valueToKey(role)); + } + cpp << QString(" case Qt::UserRole + %1:\n").arg(i); + if (ip.type.name == "QString") { + cpp << QString(" %1_data_%2(d%4, &s, set_%3);\n") + .arg(lcname, snakeCase(ip.name), ip.type.name.toLower(), index); + cpp << " if (!s.isNull()) v.setValue(s);\n"; + } else if (ip.type.name == "QByteArray") { + cpp << QString(" %1_data_%2(d%4, &b, set_%3);\n") + .arg(lcname, snakeCase(ip.name), ip.type.name.toLower(), index); + cpp << " if (!b.isNull()) v.setValue(b);\n"; + } else { + cpp << QString(" v = %1_data_%2(d%3);\n") + .arg(lcname, snakeCase(ip.name), index); + } + cpp << " break;\n"; + } + cpp << " }\n"; + cpp << " break;\n"; + } + cpp << " }\n return v;\n}\n"; + cpp << "QHash " << o.name << "::roleNames() const {\n"; + cpp << " QHash names = QAbstractItemModel::roleNames();\n"; + for (int i = 0; i < o.itemProperties.size(); ++i) { + auto ip = o.itemProperties[i]; + cpp << " names.insert(Qt::UserRole + " << i << ", \"" << ip.name << "\");\n"; + } + cpp << " return names;\n"; + cpp << QString(R"(} +bool %1::setData(const QModelIndex &index, const QVariant &value, int role) +{ +)").arg(o.name); + cpp << " bool set = false;\n"; + for (int col = 0; col < o.columnCount; ++col) { + if (!isColumnWrite(o, col)) { + continue; + } + cpp << " if (index.column() == " << col << ") {\n"; + for (int i = 0; i < o.itemProperties.size(); ++i) { + auto ip = o.itemProperties[i]; + if (!ip.write) { + continue; + } + auto roles = ip.roles.value(col); + if (col > 0 && roles.size() == 0) { + continue; + } + cpp << " if ("; + for (auto role: roles) { + cpp << QString("role == Qt::%1 || ").arg(metaRoles.valueToKey(role)); + } + cpp << "role == Qt::UserRole + " << i << ") {\n"; + if (ip.optional) { + QString test = "!value.isValid()"; + if (ip.type.isComplex()) { + test += " || value.isNull()"; + } + cpp << " if (" << test << ") {\n"; + cpp << QString(" set = %1_set_data_%2_none(d%3);") + .arg(lcname, snakeCase(ip.name), index) << endl; + cpp << " } else\n"; + } + QString val = QString("value.value<%1>()").arg(ip.type.name); + cpp << QString(" set = %1_set_data_%2(d%3, %4);") + .arg(lcname, snakeCase(ip.name), index, val) << endl; + cpp << " }\n"; + } + cpp << " }\n"; + } + cpp << R"( if (set) { + emit dataChanged(index, index, QVector() << role); + } + return set; +} +)"; +} + +void writeHeaderObject(QTextStream& h, const Object& o) { + h << QString(R"( +class %1 : public %3 +{ + Q_OBJEC%2 +public: + class Private; +private: + Private * const d; +)").arg(o.name, "T", baseType(o)); + for (auto p: o.properties) { + h << QString(" Q_PROPERTY(%1 %2 READ %2 %3NOTIFY %2Changed FINAL)") + .arg(p.type.name, p.name, + p.write ? writeProperty(p.name) :"") << endl; + } + h << QString(R"(public: + explicit %1(QObject *parent = nullptr); + ~%1(); +)").arg(o.name); + for (auto p: o.properties) { + h << " " << p.type.name << " " << p.name << "() const;" << endl; + if (p.write) { + h << " void set" << upperInitial(p.name) << "(" << p.type.cppSetType << " v);" << endl; + } + } + if (baseType(o) == "QAbstractItemModel") { + writeHeaderItemModel(h); + } + h << "signals:" << endl; + for (auto p: o.properties) { + h << " void " << p.name << "Changed();" << endl; + } + h << "private:" << endl; + for (auto p: o.properties) { + h << " " << p.type.name << " m_" << p.name << ";" << endl; + } + h << "};" << endl; +} + +void writeObjectCDecl(QTextStream& cpp, const Object& o) { + const QString lcname(snakeCase(o.name)); + cpp << QString(" %1::Private* %2_new(%1*").arg(o.name, lcname); + for (int i = 0; i < o.properties.size(); ++i) { + cpp << QString(", void (*)(%1*)").arg(o.name); + } + if (o.type == ObjectType::List) { + cpp << QString(R"(, + void (*)(const %1*), + void (*)(%1*), + void (*)(%1*), + void (*)(%1*, int, int), + void (*)(%1*), + void (*)(%1*, int, int), + void (*)(%1*))").arg(o.name); + } + if (o.type == ObjectType::UniformTree) { + cpp << QString(R"(, + void (*)(const %1*, quintptr), + void (*)(%1*), + void (*)(%1*), + void (*)(%1*, quintptr, int, int), + void (*)(%1*), + void (*)(%1*, quintptr, int, int), + void (*)(%1*))").arg(o.name); + } + cpp << ");" << endl; + cpp << QString(" void %2_free(%1::Private*);").arg(o.name, lcname) + << endl; + for (const Property& p: o.properties) { + const QString base = QString("%1_%2").arg(lcname, snakeCase(p.name)); + if (p.type.isComplex()) { + cpp << QString(" void %2_get(const %1::Private*, %3);") + .arg(o.name, base, cGetType(p.type)) << endl; + } else { + cpp << QString(" %3 %2_get(const %1::Private*);") + .arg(o.name, base, p.type.name) << endl; + } + if (p.write) { + cpp << QString(" void %2_set(%1::Private*, %3);") + .arg(o.name, base, p.type.cSetType) << endl; + if (p.optional) { + cpp << QString(" void %2_set_none(%1::Private*);") + .arg(o.name, base) << endl; + } + } + } +} + +void writeCppObject(QTextStream& cpp, const Object& o) { + const QString lcname(snakeCase(o.name)); + cpp << QString("%1::%1(QObject *parent):\n %2(parent),") + .arg(o.name, baseType(o)) << endl; + cpp << QString(" d(%1_new(this").arg(lcname); + for (const Property& p: o.properties) { + cpp << QString(",\n [](%1* o) { emit o->%2Changed(); }") + .arg(o.name, p.name); + } + if (o.type == ObjectType::List) { + cpp << QString(R"(, + [](const %1* o) { + emit o->newDataReady(QModelIndex()); + }, + [](%1* o) { + o->beginResetModel(); + }, + [](%1* o) { + o->endResetModel(); + }, + [](%1* o, int first, int last) { + o->beginInsertRows(QModelIndex(), first, last); + }, + [](%1* o) { + o->endInsertRows(); + }, + [](%1* o, int first, int last) { + o->beginRemoveRows(QModelIndex(), first, last); + }, + [](%1* o) { + o->endRemoveRows(); + } + )) { + connect(this, &%1::newDataReady, this, [this](const QModelIndex& i) { + fetchMore(i); + }, Qt::QueuedConnection); +} +)").arg(o.name); + } + if (o.type == ObjectType::UniformTree) { + cpp << QString(R"(, + [](const %1* o, quintptr id) { + auto i = %2_parent(o->d, id); + emit o->newDataReady(o->createIndex(i.row, 0, i.id)); + }, + [](%1* o) { + o->beginResetModel(); + }, + [](%1* o) { + o->endResetModel(); + }, + [](%1* o, quintptr id, int first, int last) { + auto i = %2_parent(o->d, id); + o->beginInsertRows(o->createIndex(i.row, 0, i.id), first, last); + }, + [](%1* o) { + o->endInsertRows(); + }, + [](%1* o, quintptr id, int first, int last) { + auto i = %2_parent(o->d, id); + o->beginRemoveRows(o->createIndex(i.row, 0, i.id), first, last); + }, + [](%1* o) { + o->endRemoveRows(); + } + )) { + connect(this, &%1::newDataReady, this, [this](const QModelIndex& i) { + fetchMore(i); + }, Qt::QueuedConnection); +} +)").arg(o.name, lcname); + } + if (o.type == ObjectType::Object) { + cpp << QString(")) {}"); + } + cpp << QString(R"( + +%1::~%1() { + %2_free(d); +} +)").arg(o.name, lcname); + + for (const Property& p: o.properties) { + const QString base = QString("%1_%2").arg(lcname, snakeCase(p.name)); + cpp << QString("%3 %1::%2() const\n{\n").arg(o.name, p.name, p.type.name); + if (p.type.isComplex()) { + cpp << " " << p.type.name << " v;\n"; + cpp << " " << base << "_get(d, &v, set_" << p.type.name.toLower() + << ");\n"; + cpp << " return v;\n}\n"; + } else { + cpp << QString(" return %1_get(d);\n}\n").arg(base); + } + if (p.write) { + cpp << "void " << o.name << "::set" << upperInitial(p.name) << "(" << p.type.cppSetType << " v) {" << endl; + if (p.optional) { + cpp << QString(" if (v.isNull()) {") << endl; + cpp << QString(" %1_set_none(d);").arg(base) << endl; + cpp << QString(" } else {") << endl; + cpp << QString(" %1_set(d, v);").arg(base) << endl; + cpp << QString(" }") << endl; + } else { + cpp << QString(" %1_set(d, v);").arg(base) << endl; + } + cpp << "}" << endl; + } + } +} + +void writeHeader(const Configuration& conf) { + DifferentFileWriter w(conf.hFile.absoluteFilePath()); + QTextStream h(&w.buffer); + const QString guard(conf.hFile.fileName().replace('.', '_').toUpper()); + h << QString(R"(/* generated by rust_qt_binding_generator */ +#ifndef %1 +#define %1 + +#include +#include +)").arg(guard); + + for (auto object: conf.objects) { + writeHeaderObject(h, object); + } + + h << QString("#endif // %1\n").arg(guard); +} + +void writeCpp(const Configuration& conf) { + DifferentFileWriter w(conf.cppFile.absoluteFilePath()); + QTextStream cpp(&w.buffer); + cpp << QString(R"(/* generated by rust_qt_binding_generator */ +#include "%1" + +namespace { + template + struct option { + private: + T value; + bool some; + public: + operator QVariant() const { + if (some) { + return QVariant(value); + } + return QVariant(); + } + }; + struct qbytearray_t { + private: + const char* data; + int len; + public: + qbytearray_t(const QByteArray& v): + data(v.data()), + len(v.size()) { + } + operator QByteArray() const { + return QByteArray(data, len); + } + }; + struct qstring_t { + private: + const void* data; + int len; + public: + qstring_t(const QString& v): + data(static_cast(v.utf16())), + len(v.size()) { + } + operator QString() const { + return QString::fromUtf8(static_cast(data), len); + } + }; + struct qmodelindex_t { + int row; + quintptr id; + }; +} +typedef void (*qstring_set)(QString*, qstring_t*); +void set_qstring(QString* v, qstring_t* val) { + *v = *val; +} +typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*); +void set_qbytearray(QByteArray* v, qbytearray_t* val) { + *v = *val; +} + +)").arg(conf.hFile.fileName()); + + for (auto object: conf.objects) { + if (object.type != ObjectType::Object) { + writeCppModel(cpp, object); + } + + cpp << "extern \"C\" {\n"; + writeObjectCDecl(cpp, object); + cpp << "};" << endl; + } + + for (auto object: conf.objects) { + writeCppObject(cpp, object); + } +} diff --git a/src/cpp.h b/src/cpp.h new file mode 100644 index 0000000..aaae925 --- /dev/null +++ b/src/cpp.h @@ -0,0 +1,3 @@ +class Configuration; +void writeHeader(const Configuration& conf); +void writeCpp(const Configuration& conf); diff --git a/src/helper.cpp b/src/helper.cpp new file mode 100644 index 0000000..b432776 --- /dev/null +++ b/src/helper.cpp @@ -0,0 +1,3 @@ +#include + +QTextStream err(stderr); diff --git a/src/helper.h b/src/helper.h new file mode 100644 index 0000000..269f49f --- /dev/null +++ b/src/helper.h @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +static QTextStream err; + +inline QString snakeCase(const QString& name) { + return name.left(1).toLower() + name.mid(1) + .replace(QRegExp("([A-Z])"), "_\\1").toLower(); +} + +// Only write a file if it is different +class DifferentFileWriter { +public: + const QString path; + QByteArray buffer; + bool overwrite; + DifferentFileWriter(const QString& p, bool o = true) :path(p), overwrite(o) + { + } + ~DifferentFileWriter() { + const QByteArray old = read(); + if (old != buffer && (old.isNull() || overwrite)) { + write(); + } + } + QByteArray read() const { + QByteArray content; + QFile file(path); + if (file.open(QIODevice::ReadOnly)) { + content = file.readAll(); + } + return content; + } + void write() const { + QFile file(path); + if (!file.open(QIODevice::WriteOnly)) { + err << QCoreApplication::translate("main", + "Cannot write %1.\n").arg(file.fileName()); + err.flush(); + exit(1); + } + file.write(buffer); + file.close(); + } +}; diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..ee9b0c9 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,48 @@ +#include "parseJson.h" +#include "cpp.h" +#include "rust.h" +#include "helper.h" +#include + +int main(int argc, char *argv[]) { + QCoreApplication app(argc, argv); + QCoreApplication::setApplicationName(argv[0]); + QCoreApplication::setApplicationVersion("0.1"); + + QCommandLineParser parser; + parser.setApplicationDescription("Generates bindings between Qt and Rust"); + parser.addHelpOption(); + parser.addVersionOption(); + parser.addPositionalArgument("configuration", + QCoreApplication::translate("main", "Configuration file(s)")); + + // A boolean option (--overwrite-implementation) + QCommandLineOption overwriteOption(QStringList() + << "overwrite-implementation", + QCoreApplication::translate("main", + "Overwrite existing implementation.")); + parser.addOption(overwriteOption); + + parser.process(app); + + const QStringList args = parser.positionalArguments(); + if (args.isEmpty()) { + err << QCoreApplication::translate("main", + "Configuration file is missing.\n"); + return 1; + } + + for (auto path: args) { + const QString configurationFile(path); + Configuration configuration = parseConfiguration(configurationFile); + configuration.overwriteImplementation = parser.isSet(overwriteOption); + + writeHeader(configuration); + writeCpp(configuration); + writeRustInterface(configuration); + writeRustImplementation(configuration); + writeRustTypes(configuration); + } + + return 0; +} diff --git a/src/parseJson.cpp b/src/parseJson.cpp new file mode 100644 index 0000000..3bccb4a --- /dev/null +++ b/src/parseJson.cpp @@ -0,0 +1,191 @@ +#include "parseJson.h" +#include "helper.h" +#include +#include +#include +#include + +BindingTypeProperties simpleType(const char* name, const char* init) { + return { + .name = name, + .cppSetType = name, + .cSetType = name, + .rustType = name, + .rustTypeInit = init, + }; +} + +const QMap& bindingTypeProperties() { + static QMap p; + if (p.empty()) { + QMap f; + f.insert(BindingType::Bool, simpleType("bool", "true")); + f.insert(BindingType::Int, { + .name = "qint32", + .cppSetType = "qint32", + .cSetType = "qint32", + .rustType = "i32", + .rustTypeInit = "0", + }); + f.insert(BindingType::UInt, { + .name = "quint32", + .cppSetType = "uint", + .cSetType = "uint", + .rustType = "u32", + .rustTypeInit = "0" + }); + f.insert(BindingType::ULongLong, { + .name = "quint64", + .cppSetType = "quint64", + .cSetType = "quint64", + .rustType = "u64", + .rustTypeInit = "0" + }); + f.insert(BindingType::QString, { + .name = "QString", + .cppSetType = "const QString&", + .cSetType = "qstring_t", + .rustType = "String", + .rustTypeInit = "String::new()" + }); + f.insert(BindingType::QByteArray, { + .name = "QByteArray", + .cppSetType = "const QByteArray&", + .cSetType = "qbytearray_t", + .rustType = "Vec", + .rustTypeInit = "Vec::new()" + }); + p = f; + } + return p; +} + +BindingTypeProperties parseBindingType(const QString& value) { + QMapIterator i(bindingTypeProperties()); + while (i.hasNext()) { + i.next(); + if (value == i.value().name) { + return i.value(); + } + } + err << QCoreApplication::translate("main", + "'%1' is not a supported type. Try one of\n").arg(value); + for (auto i: bindingTypeProperties()) { + err << " " << i.name << "\n"; + } + err.flush(); + exit(1); +} + +Property +parseProperty(const QString& name, const QJsonObject& json) { + Property p; + p.name = name; + p.type = parseBindingType(json.value("type").toString()); + p.write = json.value("write").toBool(); + p.optional = json.value("optional").toBool(); + return p; +} + +Qt::ItemDataRole parseItemDataRole(const QString& s) { + const QString name = s.left(1).toUpper() + s.mid(1) + "Role"; + int v = QMetaEnum::fromType() + .keyToValue(name.toUtf8()); + if (v >= 0) { + return (Qt::ItemDataRole)v; + } + err << QCoreApplication::translate("main", + "%1 is not a valid role name.\n").arg(s); + err.flush(); + exit(1); +} + +ItemProperty +parseItemProperty(const QString& name, const QJsonObject& json) { + ItemProperty ip; + ip.name = name; + ip.type = parseBindingType(json.value("type").toString()); + ip.write = json.value("write").toBool(); + ip.optional = json.value("optional").toBool(); + QJsonArray roles = json.value("roles").toArray(); + for (auto r: roles) { + QList l; + for (auto v: r.toArray()) { + l.append(parseItemDataRole(v.toString())); + } + ip.roles.append(l); + } + return ip; +} + +Object +parseObject(const QString& name, const QJsonObject& json) { + Object o; + o.name = name; + QString type = json.value("type").toString(); + if (type == "List") { + o.type = ObjectType::List; + } else if (type == "UniformTree") { + o.type = ObjectType::UniformTree; + } else { + o.type = ObjectType::Object; + } + const QJsonObject& properties = json.value("properties").toObject(); + for (const QString& key: properties.keys()) { + o.properties.append(parseProperty(key, properties[key].toObject())); + } + const QJsonObject& itemProperties = json.value("itemProperties").toObject(); + if (o.type != ObjectType::Object && itemProperties.size() == 0) { + err << QCoreApplication::translate("main", + "No item properties are defined for %1.\n").arg(o.name); + err.flush(); + exit(1); + } else if (o.type == ObjectType::Object && itemProperties.size() > 0) { + err << QCoreApplication::translate("main", + "%1 is an Object and should not have itemProperties.").arg(o.name); + err.flush(); + exit(1); + } + o.columnCount = 0; + for (const QString& key: itemProperties.keys()) { + ItemProperty p = parseItemProperty(key, itemProperties[key].toObject()); + o.columnCount = qMax(o.columnCount, p.roles.size()); + o.itemProperties.append(p); + } + return o; +} + +Configuration +parseConfiguration(const QString& path) { + QFile configurationFile(path); + const QDir base = QFileInfo(configurationFile).dir(); + if (!configurationFile.open(QIODevice::ReadOnly)) { + err << QCoreApplication::translate("main", + "Cannot read %1.\n").arg(configurationFile.fileName()); + err.flush(); + exit(1); + } + const QByteArray data(configurationFile.readAll()); + QJsonParseError error; + const QJsonDocument doc(QJsonDocument::fromJson(data, &error)); + if (error.error != QJsonParseError::NoError) { + err << error.errorString(); + err.flush(); + exit(1); + } + const QJsonObject o = doc.object(); + Configuration c; + c.cppFile = QFileInfo(base, o.value("cppFile").toString()); + QDir(c.cppFile.dir()).mkpath("."); + c.hFile = QFileInfo(c.cppFile.dir(), c.cppFile.completeBaseName() + ".h"); + const QJsonObject& object = o.value("objects").toObject(); + for (const QString& key: object.keys()) { + c.objects.append(parseObject(key, object[key].toObject())); + } + const QJsonObject rust = o.value("rust").toObject(); + 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; +} diff --git a/src/parseJson.h b/src/parseJson.h new file mode 100644 index 0000000..7f23d38 --- /dev/null +++ b/src/parseJson.h @@ -0,0 +1,3 @@ +#include "structs.h" + +Configuration parseConfiguration(const QString& path); diff --git a/src/rust.cpp b/src/rust.cpp new file mode 100644 index 0000000..c8aafb7 --- /dev/null +++ b/src/rust.cpp @@ -0,0 +1,653 @@ +#include "structs.h" +#include "helper.h" + +template +QString rustType(const T& p) +{ + if (p.optional) { + return "Option<" + p.type.rustType + ">"; + } + return p.type.rustType; +} + +template +QString rustCType(const T& p) +{ + if (p.optional) { + return "COption<" + p.type.rustType + ">"; + } + return p.type.rustType; +} + +template +QString rustTypeInit(const T& p) +{ + if (p.optional) { + return "None"; + } + return p.type.rustTypeInit; +} + +void writeRustInterfaceObject(QTextStream& r, const Object& o) { + const QString lcname(snakeCase(o.name)); + r << QString(R"( +pub struct %1QObject {} + +#[derive (Clone)] +pub struct %1Emitter { + qobject: Arc>, +)").arg(o.name); + for (const Property& p: o.properties) { + r << QString(" %2_changed: fn(*const %1QObject),\n") + .arg(o.name, snakeCase(p.name)); + } + if (o.type == ObjectType::List) { + r << QString(" new_data_ready: fn(*const %1QObject),\n") + .arg(o.name); + } else if (o.type == ObjectType::UniformTree) { + r << QString(" new_data_ready: fn(*const %1QObject, item: usize),\n") + .arg(o.name); + } + r << QString(R"(} + +unsafe impl Send for %1Emitter {} + +impl %1Emitter { + fn clear(&self) { + *self.qobject.lock().unwrap() = null(); + } +)").arg(o.name); + for (const Property& p: o.properties) { + r << QString(R"( pub fn %1_changed(&self) { + let ptr = *self.qobject.lock().unwrap(); + if !ptr.is_null() { + (self.%1_changed)(ptr); + } + } +)").arg(snakeCase(p.name)); + } + if (o.type == ObjectType::List) { + r << R"( pub fn new_data_ready(&self) { + let ptr = *self.qobject.lock().unwrap(); + if !ptr.is_null() { + (self.new_data_ready)(ptr); + } + } +)"; + } else if (o.type == ObjectType::UniformTree) { + r << R"( pub fn new_data_ready(&self, item: usize) { + let ptr = *self.qobject.lock().unwrap(); + if !ptr.is_null() { + (self.new_data_ready)(ptr, item); + } + } +)"; + } + + QString modelStruct = ""; + if (o.type != ObjectType::Object) { + QString type = o.type == ObjectType::List ? "List" : "UniformTree"; + modelStruct = ", model: " + o.name + type; + QString index; + QString indexDecl; + if (o.type == ObjectType::UniformTree) { + indexDecl = " item: usize,"; + index = " item,"; + } + r << QString(R"(} + +pub struct %1%2 { + qobject: *const %1QObject, + begin_reset_model: fn(*const %1QObject), + end_reset_model: fn(*const %1QObject), + begin_insert_rows: fn(*const %1QObject,%3 usize, usize), + end_insert_rows: fn(*const %1QObject), + begin_remove_rows: fn(*const %1QObject,%3 usize, usize), + end_remove_rows: fn(*const %1QObject), +} + +impl %1%2 { + pub fn begin_reset_model(&self) { + (self.begin_reset_model)(self.qobject); + } + pub fn end_reset_model(&self) { + (self.end_reset_model)(self.qobject); + } + pub fn begin_insert_rows(&self,%3 first: usize, last: usize) { + (self.begin_insert_rows)(self.qobject,%4 first, last); + } + pub fn end_insert_rows(&self) { + (self.end_insert_rows)(self.qobject); + } + pub fn begin_remove_rows(&self,%3 first: usize, last: usize) { + (self.begin_remove_rows)(self.qobject,%4 first, last); + } + pub fn end_remove_rows(&self) { + (self.end_remove_rows)(self.qobject); + } +)").arg(o.name, type, indexDecl, index); + } + + r << QString(R"(} + +pub trait %1Trait { + fn create(emit: %1Emitter%2) -> Self; + fn emit(&self) -> &%1Emitter; +)").arg(o.name, modelStruct); + for (const Property& p: o.properties) { + const QString lc(snakeCase(p.name)); + r << QString(" fn get_%1(&self) -> %2;\n").arg(lc, rustType(p)); + if (p.write) { + r << QString(" fn set_%1(&mut self, value: %2);\n").arg(lc, rustType(p)); + } + } + if (o.type != ObjectType::Object) { + QString index; + if (o.type == ObjectType::UniformTree) { + index = ", item: usize"; + } + r << QString(R"( fn row_count(&self%1) -> usize; + fn can_fetch_more(&self%1) -> bool { false } + fn fetch_more(&mut self%1) {} + fn sort(&mut self, u8, SortOrder) {} +)").arg(index); + for (auto ip: o.itemProperties) { + r << QString(" fn %1(&self, item: usize) -> %2;\n") + .arg(snakeCase(ip.name), rustType(ip)); + if (ip.write) { + r << QString(" fn set_%1(&mut self, item: usize, %2) -> bool;\n") + .arg(snakeCase(ip.name), rustType(ip)); + } + } + } + if (o.type == ObjectType::UniformTree) { + r << " fn index(&self, item: usize, row: usize) -> usize;\n"; + r << " fn parent(&self, item: usize) -> QModelIndex;\n"; + } + + r << QString(R"(} + +#[no_mangle] +pub extern "C" fn %2_new(qobject: *const %1QObject)").arg(o.name, lcname); + for (const Property& p: o.properties) { + r << QString(",\n %2_changed: fn(*const %1QObject)") + .arg(o.name, snakeCase(p.name)); + } + if (o.type == ObjectType::List) { + r << QString(",\n new_data_ready: fn(*const %1QObject)") + .arg(o.name); + } else if (o.type == ObjectType::UniformTree) { + r << QString(",\n new_data_ready: fn(*const %1QObject, item: usize)") + .arg(o.name); + } + if (o.type != ObjectType::Object) { + QString indexDecl; + if (o.type == ObjectType::UniformTree) { + indexDecl = " item: usize,"; + } + r << QString(R"(, + begin_reset_model: fn(*const %1QObject), + end_reset_model: fn(*const %1QObject), + begin_insert_rows: fn(*const %1QObject,%2 + usize, + usize), + end_insert_rows: fn(*const %1QObject), + begin_remove_rows: fn(*const %1QObject,%2 + usize, + usize), + end_remove_rows: fn(*const %1QObject))").arg(o.name, indexDecl); + } + r << QString(R"() + -> *mut %1 { + let emit = %1Emitter { + qobject: Arc::new(Mutex::new(qobject)), +)").arg(o.name); + for (const Property& p: o.properties) { + r << QString(" %1_changed: %1_changed,\n").arg(snakeCase(p.name)); + } + if (o.type != ObjectType::Object) { + r << QString(" new_data_ready: new_data_ready,\n"); + } + QString model = ""; + if (o.type != ObjectType::Object) { + const QString type = o.type == ObjectType::List ? "List" : "UniformTree"; + model = ", model"; + r << QString(R"( }; + let model = %1%2 { + qobject: qobject, + begin_reset_model: begin_reset_model, + end_reset_model: end_reset_model, + begin_insert_rows: begin_insert_rows, + end_insert_rows: end_insert_rows, + begin_remove_rows: begin_remove_rows, + end_remove_rows: end_remove_rows, +)").arg(o.name, type); + } + r << QString(R"( }; + let d = %1::create(emit%3); + Box::into_raw(Box::new(d)) +} + +#[no_mangle] +pub unsafe extern "C" fn %2_free(ptr: *mut %1) { + Box::from_raw(ptr).emit().clear(); +} +)").arg(o.name, lcname, model); + for (const Property& p: o.properties) { + const QString base = QString("%1_%2").arg(lcname, snakeCase(p.name)); + QString ret = ") -> " + rustType(p); + if (p.type.isComplex() && !p.optional) { + r << QString(R"( +#[no_mangle] +pub unsafe extern "C" fn %2_get(ptr: *const %1, + p: *mut c_void, + set: fn(*mut c_void, %4)) { + let data = (&*ptr).get_%3(); + set(p, %4::from(&data)); +} +)").arg(o.name, base, snakeCase(p.name), p.type.name); + if (p.write) { + const QString type = p.type.name == "QString" ? "QStringIn" : p.type.name; + r << QString(R"( +#[no_mangle] +pub unsafe extern "C" fn %2_set(ptr: *mut %1, v: %4) { + (&mut *ptr).set_%3(v.convert()); +} +)").arg(o.name, base, snakeCase(p.name), type); + } + } else if (p.type.isComplex()) { + r << QString(R"( +#[no_mangle] +pub unsafe extern "C" fn %2_get(ptr: *const %1, + p: *mut c_void, + set: fn(*mut c_void, %4)) { + let data = (&*ptr).get_%3(); + if let Some(data) = data { + set(p, %4::from(&data)); + } +} +)").arg(o.name, base, snakeCase(p.name), p.type.name); + if (p.write) { + const QString type = p.type.name == "QString" ? "QStringIn" : p.type.name; + r << QString(R"( +#[no_mangle] +pub unsafe extern "C" fn %2_set(ptr: *mut %1, v: %4) { + (&mut *ptr).set_%3(Some(v.convert())); +} +#[no_mangle] +pub unsafe extern "C" fn %2_set_none(ptr: *mut %1) { + (&mut *ptr).set_%3(None); +} +)").arg(o.name, base, snakeCase(p.name), type); + } + } else { + r << QString(R"( +#[no_mangle] +pub unsafe extern "C" fn %2_get(ptr: *const %1) -> %4 { + (&*ptr).get_%3() +} +)").arg(o.name, base, snakeCase(p.name), rustType(p)); + if (p.write) { + r << QString(R"( +#[no_mangle] +pub unsafe extern "C" fn %2_set(ptr: *mut %1, v: %4) { + (&mut *ptr).set_%3(v); +} +)").arg(o.name, base, snakeCase(p.name), rustType(p)); + } + } + } + if (o.type != ObjectType::Object) { + QString indexDecl; + QString index; + if (o.type == ObjectType::UniformTree) { + indexDecl = ", row: c_int, item: usize"; + index = "(&*ptr).index(item, row as usize)"; + } + r << QString(R"( +#[no_mangle] +pub unsafe extern "C" fn %2_row_count(ptr: *const %1%3) -> c_int { + (&*ptr).row_count(%4) as c_int +} +#[no_mangle] +pub unsafe extern "C" fn %2_can_fetch_more(ptr: *const %1%3) -> bool { + (&*ptr).can_fetch_more(%4) +} +#[no_mangle] +pub unsafe extern "C" fn %2_fetch_more(ptr: *mut %1%3) { + (&mut *ptr).fetch_more(%4) +} +#[no_mangle] +pub unsafe extern "C" fn %2_sort(ptr: *mut %1, column: u8, order: SortOrder) { + (&mut *ptr).sort(column, order) +} +)").arg(o.name, lcname, indexDecl, index); + if (o.type == ObjectType::List) { + indexDecl = ", row: c_int"; + index = "row as usize"; + } + for (auto ip: o.itemProperties) { + if (ip.type.isComplex() && !ip.optional) { + r << QString(R"( +#[no_mangle] +pub unsafe extern "C" fn %2_data_%3(ptr: *const %1%5, + d: *mut c_void, + set: fn(*mut c_void, %4)) { + let data = (&*ptr).%3(%6); + set(d, %4::from(&data)); +} +)").arg(o.name, lcname, snakeCase(ip.name), ip.type.name, indexDecl, index); + } else if (ip.type.isComplex()) { + r << QString(R"( +#[no_mangle] +pub unsafe extern "C" fn %2_data_%3(ptr: *const %1%5, + d: *mut c_void, + set: fn(*mut c_void, %4)) { + let data = (&*ptr).%3(%6); + if let Some(data) = data { + set(d, %4::from(&data)); + } +} +)").arg(o.name, lcname, snakeCase(ip.name), ip.type.name, indexDecl, index); + } else { + r << QString(R"( +#[no_mangle] +pub unsafe extern "C" fn %2_data_%3(ptr: *const %1%5) -> %4 { + (&*ptr).%3(%6).into() +} +)").arg(o.name, lcname, snakeCase(ip.name), rustCType(ip), indexDecl, index); + } + if (ip.write) { + QString val = "v"; + QString type = ip.type.rustType; + if (ip.type.isComplex()) { + val = val + ".convert()"; + type = ip.type.name == "QString" ? "QStringIn" : ip.type.name; + } + if (ip.optional) { + val = "Some(" + val + ")"; + } + r << QString(R"( +#[no_mangle] +pub unsafe extern "C" fn %2_set_data_%3(ptr: *mut %1%4, v: %6) -> bool { + (&mut *ptr).set_%3(%5, %7) +} +)").arg(o.name, lcname, snakeCase(ip.name), indexDecl, index, type, val); + } + if (ip.write && ip.optional) { + r << QString(R"( +#[no_mangle] +pub unsafe extern "C" fn %2_set_data_%3_none(ptr: *mut %1, row: c_int%4) -> bool { + (&mut *ptr).set_%3(%5row as usize, None) +} +)").arg(o.name, lcname, snakeCase(ip.name), indexDecl, index); + } + } + } + if (o.type == ObjectType::UniformTree) { + r << QString(R"( +#[no_mangle] +pub unsafe extern "C" fn %2_index(ptr: *const %1, row: c_int, parent: usize) -> usize { + (&*ptr).index(parent, row as usize) +} +#[no_mangle] +pub unsafe extern "C" fn %2_parent(ptr: *const %1, parent: usize) -> QModelIndex { + (&*ptr).parent(parent) +} +)").arg(o.name, lcname); + + } +} + +QString rustFile(const QDir rustdir, const QString& module) { + QDir src(rustdir.absoluteFilePath("src")); + QString path = src.absoluteFilePath(module + ".rs"); + return path; +} + +void writeRustInterface(const Configuration& conf) { + DifferentFileWriter w(rustFile(conf.rustdir, conf.interfaceModule)); + QTextStream r(&w.buffer); + r << QString(R"(/* generated by rust_qt_binding_generator */ +#![allow(unknown_lints)] +#![allow(mutex_atomic, needless_pass_by_value)] +#![allow(unused_imports)] +use libc::{c_int, c_void}; +use types::*; +use std::sync::{Arc, Mutex}; +use std::ptr::null; + +use %1::*; +)").arg(conf.implementationModule); + + for (auto object: conf.objects) { + writeRustInterfaceObject(r, object); + } +} + +void writeRustImplementationObject(QTextStream& r, const Object& o) { + const QString lcname(snakeCase(o.name)); + if (o.type != ObjectType::Object) { + r << "#[derive (Default, Clone)]\n"; + r << QString("struct %1Item {\n").arg(o.name); + for (auto ip: o.itemProperties) { + const QString lc(snakeCase(ip.name)); + r << QString(" %1: %2,\n").arg(lc, ip.type.rustType); + } + r << "}\n\n"; + } + QString modelStruct = ""; + r << QString("pub struct %1 {\n emit: %1Emitter,\n").arg((o.name)); + if (o.type == ObjectType::List) { + modelStruct = ", model: " + o.name + "List"; + r << QString(" model: %1List,\n").arg(o.name); + } else if (o.type == ObjectType::UniformTree) { + modelStruct = ", model: " + o.name + "UniformTree"; + r << QString(" model: %1UniformTree,\n").arg(o.name); + } + for (const Property& p: o.properties) { + const QString lc(snakeCase(p.name)); + r << QString(" %1: %2,\n").arg(lc, rustType(p)); + } + if (o.type != ObjectType::Object) { + r << QString(" list: Vec<%1Item>,\n").arg(o.name); + } + r << "}\n\n"; + r << QString(R"(impl %1Trait for %1 { + fn create(emit: %1Emitter%2) -> %1 { + %1 { + emit: emit, +)").arg(o.name, modelStruct); + if (o.type != ObjectType::Object) { + r << QString(" model: model,\n"); + } + for (const Property& p: o.properties) { + const QString lc(snakeCase(p.name)); + r << QString(" %1: %2,\n").arg(lc, rustTypeInit(p)); + } + if (o.type != ObjectType::Object) { + r << QString(" list: vec![%1Item::default(); 10],\n") + .arg(o.name); + } + r << QString(R"( } + } + fn emit(&self) -> &%1Emitter { + &self.emit + } +)").arg(o.name); + for (const Property& p: o.properties) { + const QString lc(snakeCase(p.name)); + r << QString(" fn get_%1(&self) -> %2 {\n").arg(lc, rustType(p)); + if (p.type.isComplex()) { + r << QString(" self.%1.clone()\n").arg(lc); + } else { + r << QString(" self.%1\n").arg(lc); + } + r << " }\n"; + if (p.write) { + r << QString(R"( fn set_%1(&mut self, value: %2) { + self.%1 = value; + self.emit.%1_changed(); + } +)").arg(lc, rustType(p)); + } + } + if (o.type != ObjectType::Object) { + QString index; + if (o.type == ObjectType::UniformTree) { + index = ", item: usize"; + } + r << " fn row_count(&self" << index << ") -> usize {\n self.list.len()\n }\n"; + for (auto ip: o.itemProperties) { + const QString lc(snakeCase(ip.name)); + r << QString(" fn %1(&self, item: usize) -> %2 {\n") + .arg(lc, rustType(ip)); + r << " self.list[item]." << lc << ".clone()\n"; + r << " }\n"; + if (ip.write) { + r << QString(" fn set_%1(&mut self, item: usize, v: %2) -> bool {\n") + .arg(snakeCase(ip.name), rustType(ip)); + r << " self.list[item]." << lc << " = v;\n"; + r << " true\n"; + r << " }\n"; + } + } + } + if (o.type == ObjectType::UniformTree) { + r << R"( fn index(&self, item: usize, row: usize) -> usize { + 0 + } + fn parent(&self, item: usize) -> QModelIndex { + QModelIndex::create(0, 0) + } +)"; + } + r << "}\n"; +} + +void writeRustImplementation(const Configuration& conf) { + DifferentFileWriter w(rustFile(conf.rustdir, conf.implementationModule), + conf.overwriteImplementation); + QTextStream r(&w.buffer); + r << QString(R"(#![allow(unused_imports)] +#![allow(unused_variables)] +#![allow(dead_code)] +use types::*; +use %1::*; + +)").arg(conf.interfaceModule); + + for (auto object: conf.objects) { + writeRustImplementationObject(r, object); + } +} + +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 */ +#![allow(dead_code)] +use std::slice; +use libc::{c_int, uint8_t, uint16_t}; + +#[repr(C)] +pub struct COption { + data: T, + some: bool, +} + +impl From> for COption where T: Default { + fn from(t: Option) -> COption { + if let Some(v) = t { + COption { + data: v, + some: true + } + } else { + COption { + data: T::default(), + some: false + } + } + } +} + +#[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(), + } + } +} + +#[repr(C)] +pub struct QModelIndex { + row: c_int, + internal_id: usize, +} + +impl QModelIndex { + pub fn invalid() -> QModelIndex { + QModelIndex { + row: -1, + internal_id: 0, + } + } + pub fn create(row: c_int, id: usize) -> QModelIndex { + QModelIndex { + row: row, + internal_id: id, + } + } +} + +#[repr(C)] +pub enum SortOrder { + Ascending = 0, + Descending = 1 +} + +)"); +} diff --git a/src/rust.h b/src/rust.h new file mode 100644 index 0000000..f8f3f77 --- /dev/null +++ b/src/rust.h @@ -0,0 +1,4 @@ +class Configuration; +void writeRustInterface(const Configuration& conf); +void writeRustTypes(const Configuration& conf); +void writeRustImplementation(const Configuration& conf); diff --git a/src/structs.h b/src/structs.h new file mode 100644 index 0000000..a36b777 --- /dev/null +++ b/src/structs.h @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include + +enum class ObjectType { + Object, + List, + UniformTree +}; + +enum class BindingType { + Bool, + Int, + UInt, + ULongLong, + QString, + QByteArray +}; + +struct BindingTypeProperties { + QString name; + QString cppSetType; + QString cSetType; + QString rustType; + QString rustTypeInit; + bool isComplex() const { + return name.startsWith("Q"); + } +}; + +struct Property { + QString name; + BindingTypeProperties type; + bool write; + bool optional; +}; + +struct ItemProperty { + QString name; + BindingTypeProperties type; + bool write; + bool optional; + QList> roles; +}; + +struct Object { + QString name; + ObjectType type; + QList properties; + QList itemProperties; + int columnCount; +}; + +struct Configuration { + QFileInfo hFile; + QFileInfo cppFile; + QDir rustdir; + QString interfaceModule; + QString implementationModule; + QString typesModule; + QList objects; + bool overwriteImplementation; +}; + diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 76686ed..b16a35c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,5 +1,5 @@ -SET(GENERATOR "${CMAKE_BINARY_DIR}/rust_qt_binding_generator/rust_qt_binding_generator") +SET(GENERATOR "${CMAKE_BINARY_DIR}/src/rust_qt_binding_generator") include_directories("${CMAKE_CURRENT_BINARY_DIR}") add_custom_target("clean-rust") @@ -17,7 +17,7 @@ function(rust_test NAME DIRECTORY) # "${SRC}/${NAME}_rust.cpp" COMMAND "${GENERATOR}" --overwrite-implementation "${SRC}/${NAME}.json" MAIN_DEPENDENCY "${NAME}.json" - DEPENDS "${GENERATOR}" + DEPENDS rust_qt_binding_generator ) add_custom_command( diff --git a/tests/rust_list/src/implementation.rs b/tests/rust_list/src/implementation.rs index ac4da5d..9f89df3 100644 --- a/tests/rust_list/src/implementation.rs +++ b/tests/rust_list/src/implementation.rs @@ -1,8 +1,6 @@ #![allow(unused_imports)] #![allow(unused_variables)] #![allow(dead_code)] -use libc::c_int; -use libc::c_uint; use types::*; use interface::*; @@ -28,14 +26,14 @@ impl PersonsTrait for Persons { fn emit(&self) -> &PersonsEmitter { &self.emit } - fn row_count(&self) -> c_int { - self.list.len() as c_int + fn row_count(&self) -> usize { + self.list.len() } - fn user_name(&self, row: c_int) -> String { - self.list[row as usize].user_name.clone() + fn user_name(&self, item: usize) -> String { + self.list[item].user_name.clone() } - fn set_user_name(&mut self, row: c_int, v: String) -> bool { - self.list[row as usize].user_name = v; + fn set_user_name(&mut self, item: usize, v: String) -> bool { + self.list[item].user_name = v; true } } diff --git a/tests/rust_list/src/interface.rs b/tests/rust_list/src/interface.rs index 3b2d463..e79d97d 100644 --- a/tests/rust_list/src/interface.rs +++ b/tests/rust_list/src/interface.rs @@ -2,7 +2,7 @@ #![allow(unknown_lints)] #![allow(mutex_atomic, needless_pass_by_value)] #![allow(unused_imports)] -use libc::{c_int, c_uint, c_void}; +use libc::{c_int, c_void}; use types::*; use std::sync::{Arc, Mutex}; use std::ptr::null; @@ -35,9 +35,9 @@ pub struct PersonsList { qobject: *const PersonsQObject, begin_reset_model: fn(*const PersonsQObject), end_reset_model: fn(*const PersonsQObject), - begin_insert_rows: fn(*const PersonsQObject, c_int, c_int), + begin_insert_rows: fn(*const PersonsQObject, usize, usize), end_insert_rows: fn(*const PersonsQObject), - begin_remove_rows: fn(*const PersonsQObject, c_int, c_int), + begin_remove_rows: fn(*const PersonsQObject, usize, usize), end_remove_rows: fn(*const PersonsQObject), } @@ -48,13 +48,13 @@ impl PersonsList { pub fn end_reset_model(&self) { (self.end_reset_model)(self.qobject); } - pub fn begin_insert_rows(&self, first: c_int, last: c_int) { + pub fn begin_insert_rows(&self, first: usize, last: usize) { (self.begin_insert_rows)(self.qobject, first, last); } pub fn end_insert_rows(&self) { (self.end_insert_rows)(self.qobject); } - pub fn begin_remove_rows(&self, first: c_int, last: c_int) { + pub fn begin_remove_rows(&self, first: usize, last: usize) { (self.begin_remove_rows)(self.qobject, first, last); } pub fn end_remove_rows(&self) { @@ -65,12 +65,12 @@ impl PersonsList { pub trait PersonsTrait { fn create(emit: PersonsEmitter, model: PersonsList) -> Self; fn emit(&self) -> &PersonsEmitter; - fn row_count(&self) -> c_int; + fn row_count(&self) -> usize; fn can_fetch_more(&self) -> bool { false } fn fetch_more(&mut self) {} - fn sort(&mut self, c_int, SortOrder) {} - fn user_name(&self, row: c_int) -> String; - fn set_user_name(&mut self, row: c_int, String) -> bool; + fn sort(&mut self, u8, SortOrder) {} + fn user_name(&self, item: usize) -> String; + fn set_user_name(&mut self, item: usize, String) -> bool; } #[no_mangle] @@ -79,12 +79,12 @@ pub extern "C" fn persons_new(qobject: *const PersonsQObject, begin_reset_model: fn(*const PersonsQObject), end_reset_model: fn(*const PersonsQObject), begin_insert_rows: fn(*const PersonsQObject, - c_int, - c_int), + usize, + usize), end_insert_rows: fn(*const PersonsQObject), begin_remove_rows: fn(*const PersonsQObject, - c_int, - c_int), + usize, + usize), end_remove_rows: fn(*const PersonsQObject)) -> *mut Persons { let emit = PersonsEmitter { @@ -111,7 +111,7 @@ pub unsafe extern "C" fn persons_free(ptr: *mut Persons) { #[no_mangle] pub unsafe extern "C" fn persons_row_count(ptr: *const Persons) -> c_int { - (&*ptr).row_count() + (&*ptr).row_count() as c_int } #[no_mangle] pub unsafe extern "C" fn persons_can_fetch_more(ptr: *const Persons) -> bool { @@ -122,20 +122,19 @@ pub unsafe extern "C" fn persons_fetch_more(ptr: *mut Persons) { (&mut *ptr).fetch_more() } #[no_mangle] -pub unsafe extern "C" fn persons_sort(ptr: *mut Persons, column: c_int, order: SortOrder) { +pub unsafe extern "C" fn persons_sort(ptr: *mut Persons, column: u8, order: SortOrder) { (&mut *ptr).sort(column, order) } #[no_mangle] -pub unsafe extern "C" fn persons_data_user_name(ptr: *const Persons, - row: c_int, +pub unsafe extern "C" fn persons_data_user_name(ptr: *const Persons, row: c_int, d: *mut c_void, set: fn(*mut c_void, QString)) { - let data = (&*ptr).user_name(row); + let data = (&*ptr).user_name(row as usize); set(d, QString::from(&data)); } #[no_mangle] pub unsafe extern "C" fn persons_set_data_user_name(ptr: *mut Persons, row: c_int, v: QStringIn) -> bool { - (&mut *ptr).set_user_name(row, v.convert()) + (&mut *ptr).set_user_name(row as usize, v.convert()) } diff --git a/tests/rust_object/src/implementation.rs b/tests/rust_object/src/implementation.rs index 2042eb6..64f9e9a 100644 --- a/tests/rust_object/src/implementation.rs +++ b/tests/rust_object/src/implementation.rs @@ -1,8 +1,6 @@ #![allow(unused_imports)] #![allow(unused_variables)] #![allow(dead_code)] -use libc::c_int; -use libc::c_uint; use types::*; use interface::*; diff --git a/tests/rust_object/src/interface.rs b/tests/rust_object/src/interface.rs index ea8a402..dc9bd44 100644 --- a/tests/rust_object/src/interface.rs +++ b/tests/rust_object/src/interface.rs @@ -2,7 +2,7 @@ #![allow(unknown_lints)] #![allow(mutex_atomic, needless_pass_by_value)] #![allow(unused_imports)] -use libc::{c_int, c_uint, c_void}; +use libc::{c_int, c_void}; use types::*; use std::sync::{Arc, Mutex}; use std::ptr::null; diff --git a/tests/rust_object_types/src/implementation.rs b/tests/rust_object_types/src/implementation.rs index 0493ec4..1bef454 100644 --- a/tests/rust_object_types/src/implementation.rs +++ b/tests/rust_object_types/src/implementation.rs @@ -1,8 +1,6 @@ #![allow(unused_imports)] #![allow(unused_variables)] #![allow(dead_code)] -use libc::c_int; -use libc::c_uint; use types::*; use interface::*; diff --git a/tests/rust_object_types/src/interface.rs b/tests/rust_object_types/src/interface.rs index c01604e..8ed8b20 100644 --- a/tests/rust_object_types/src/interface.rs +++ b/tests/rust_object_types/src/interface.rs @@ -2,7 +2,7 @@ #![allow(unknown_lints)] #![allow(mutex_atomic, needless_pass_by_value)] #![allow(unused_imports)] -use libc::{c_int, c_uint, c_void}; +use libc::{c_int, c_void}; use types::*; use std::sync::{Arc, Mutex}; use std::ptr::null; diff --git a/tests/rust_tree/src/implementation.rs b/tests/rust_tree/src/implementation.rs index 60ba144..868996e 100644 --- a/tests/rust_tree/src/implementation.rs +++ b/tests/rust_tree/src/implementation.rs @@ -1,8 +1,6 @@ #![allow(unused_imports)] #![allow(unused_variables)] #![allow(dead_code)] -use libc::c_int; -use libc::c_uint; use types::*; use interface::*; @@ -28,20 +26,20 @@ impl PersonsTrait for Persons { fn emit(&self) -> &PersonsEmitter { &self.emit } - fn row_count(&self, row: c_int, parent: usize) -> c_int { - self.list.len() as c_int + fn row_count(&self, item: usize) -> usize { + self.list.len() } - fn user_name(&self, row: c_int, parent: usize) -> String { - self.list[row as usize].user_name.clone() + fn user_name(&self, item: usize) -> String { + self.list[item].user_name.clone() } - fn set_user_name(&mut self, row: c_int, parent: usize, v: String) -> bool { - self.list[row as usize].user_name = v; + fn set_user_name(&mut self, item: usize, v: String) -> bool { + self.list[item].user_name = v; true } - fn index(&self, row: c_int, parent: usize) -> usize { + fn index(&self, item: usize, row: usize) -> usize { 0 } - fn parent(&self, parent: usize) -> QModelIndex { + fn parent(&self, item: usize) -> QModelIndex { QModelIndex::create(0, 0) } } diff --git a/tests/rust_tree/src/interface.rs b/tests/rust_tree/src/interface.rs index 0df9f2e..78a304d 100644 --- a/tests/rust_tree/src/interface.rs +++ b/tests/rust_tree/src/interface.rs @@ -2,7 +2,7 @@ #![allow(unknown_lints)] #![allow(mutex_atomic, needless_pass_by_value)] #![allow(unused_imports)] -use libc::{c_int, c_uint, c_void}; +use libc::{c_int, c_void}; use types::*; use std::sync::{Arc, Mutex}; use std::ptr::null; @@ -14,7 +14,7 @@ pub struct PersonsQObject {} #[derive (Clone)] pub struct PersonsEmitter { qobject: Arc>, - new_data_ready: fn(*const PersonsQObject, row: c_int, parent: usize), + new_data_ready: fn(*const PersonsQObject, item: usize), } unsafe impl Send for PersonsEmitter {} @@ -23,10 +23,10 @@ impl PersonsEmitter { fn clear(&self) { *self.qobject.lock().unwrap() = null(); } - pub fn new_data_ready(&self, row: c_int, parent: usize) { + pub fn new_data_ready(&self, item: usize) { let ptr = *self.qobject.lock().unwrap(); if !ptr.is_null() { - (self.new_data_ready)(ptr, row, parent); + (self.new_data_ready)(ptr, item); } } } @@ -35,9 +35,9 @@ pub struct PersonsUniformTree { qobject: *const PersonsQObject, begin_reset_model: fn(*const PersonsQObject), end_reset_model: fn(*const PersonsQObject), - begin_insert_rows: fn(*const PersonsQObject,row: c_int, parent: usize, c_int, c_int), + begin_insert_rows: fn(*const PersonsQObject, item: usize, usize, usize), end_insert_rows: fn(*const PersonsQObject), - begin_remove_rows: fn(*const PersonsQObject,row: c_int, parent: usize, c_int, c_int), + begin_remove_rows: fn(*const PersonsQObject, item: usize, usize, usize), end_remove_rows: fn(*const PersonsQObject), } @@ -48,14 +48,14 @@ impl PersonsUniformTree { pub fn end_reset_model(&self) { (self.end_reset_model)(self.qobject); } - pub fn begin_insert_rows(&self,row: c_int, parent: usize, first: c_int, last: c_int) { - (self.begin_insert_rows)(self.qobject,row, parent, first, last); + pub fn begin_insert_rows(&self, item: usize, first: usize, last: usize) { + (self.begin_insert_rows)(self.qobject, item, first, last); } pub fn end_insert_rows(&self) { (self.end_insert_rows)(self.qobject); } - pub fn begin_remove_rows(&self,row: c_int, parent: usize, first: c_int, last: c_int) { - (self.begin_remove_rows)(self.qobject,row, parent, first, last); + pub fn begin_remove_rows(&self, item: usize, first: usize, last: usize) { + (self.begin_remove_rows)(self.qobject, item, first, last); } pub fn end_remove_rows(&self) { (self.end_remove_rows)(self.qobject); @@ -65,28 +65,28 @@ impl PersonsUniformTree { pub trait PersonsTrait { fn create(emit: PersonsEmitter, model: PersonsUniformTree) -> Self; fn emit(&self) -> &PersonsEmitter; - fn row_count(&self, row: c_int, parent: usize) -> c_int; - fn can_fetch_more(&self, c_int, usize) -> bool { false } - fn fetch_more(&mut self, c_int, usize) {} - fn sort(&mut self, c_int, SortOrder) {} - fn user_name(&self, row: c_int, parent: usize) -> String; - fn set_user_name(&mut self, row: c_int, parent: usize, String) -> bool; - fn index(&self, row: c_int, parent: usize) -> usize; - fn parent(&self, parent: usize) -> QModelIndex; + fn row_count(&self, item: usize) -> usize; + fn can_fetch_more(&self, item: usize) -> bool { false } + fn fetch_more(&mut self, item: usize) {} + fn sort(&mut self, u8, SortOrder) {} + fn user_name(&self, item: usize) -> String; + fn set_user_name(&mut self, item: usize, String) -> bool; + fn index(&self, item: usize, row: usize) -> usize; + fn parent(&self, item: usize) -> QModelIndex; } #[no_mangle] pub extern "C" fn persons_new(qobject: *const PersonsQObject, - new_data_ready: fn(*const PersonsQObject, row: c_int, parent: usize), + new_data_ready: fn(*const PersonsQObject, item: usize), begin_reset_model: fn(*const PersonsQObject), end_reset_model: fn(*const PersonsQObject), - begin_insert_rows: fn(*const PersonsQObject,row: c_int, parent: usize, - c_int, - c_int), + begin_insert_rows: fn(*const PersonsQObject, item: usize, + usize, + usize), end_insert_rows: fn(*const PersonsQObject), - begin_remove_rows: fn(*const PersonsQObject,row: c_int, parent: usize, - c_int, - c_int), + begin_remove_rows: fn(*const PersonsQObject, item: usize, + usize, + usize), end_remove_rows: fn(*const PersonsQObject)) -> *mut Persons { let emit = PersonsEmitter { @@ -112,39 +112,38 @@ pub unsafe extern "C" fn persons_free(ptr: *mut Persons) { } #[no_mangle] -pub unsafe extern "C" fn persons_row_count(ptr: *const Persons, row: c_int, parent: usize) -> c_int { - (&*ptr).row_count(row, parent) +pub unsafe extern "C" fn persons_row_count(ptr: *const Persons, row: c_int, item: usize) -> c_int { + (&*ptr).row_count((&*ptr).index(item, row as usize)) as c_int } #[no_mangle] -pub unsafe extern "C" fn persons_can_fetch_more(ptr: *const Persons, row: c_int, parent: usize) -> bool { - (&*ptr).can_fetch_more(row, parent) +pub unsafe extern "C" fn persons_can_fetch_more(ptr: *const Persons, row: c_int, item: usize) -> bool { + (&*ptr).can_fetch_more((&*ptr).index(item, row as usize)) } #[no_mangle] -pub unsafe extern "C" fn persons_fetch_more(ptr: *mut Persons, row: c_int, parent: usize) { - (&mut *ptr).fetch_more(row, parent) +pub unsafe extern "C" fn persons_fetch_more(ptr: *mut Persons, row: c_int, item: usize) { + (&mut *ptr).fetch_more((&*ptr).index(item, row as usize)) } #[no_mangle] -pub unsafe extern "C" fn persons_sort(ptr: *mut Persons, column: c_int, order: SortOrder) { +pub unsafe extern "C" fn persons_sort(ptr: *mut Persons, column: u8, order: SortOrder) { (&mut *ptr).sort(column, order) } #[no_mangle] -pub unsafe extern "C" fn persons_data_user_name(ptr: *const Persons, - row: c_int, parent: usize, +pub unsafe extern "C" fn persons_data_user_name(ptr: *const Persons, row: c_int, item: usize, d: *mut c_void, set: fn(*mut c_void, QString)) { - let data = (&*ptr).user_name(row, parent); + let data = (&*ptr).user_name((&*ptr).index(item, row as usize)); set(d, QString::from(&data)); } #[no_mangle] -pub unsafe extern "C" fn persons_set_data_user_name(ptr: *mut Persons, row: c_int, parent: usize, v: QStringIn) -> bool { - (&mut *ptr).set_user_name(row, parent, v.convert()) +pub unsafe extern "C" fn persons_set_data_user_name(ptr: *mut Persons, row: c_int, item: usize, v: QStringIn) -> bool { + (&mut *ptr).set_user_name((&*ptr).index(item, row as usize), v.convert()) } #[no_mangle] pub unsafe extern "C" fn persons_index(ptr: *const Persons, row: c_int, parent: usize) -> usize { - (&*ptr).index(row, parent) + (&*ptr).index(parent, row as usize) } #[no_mangle] pub unsafe extern "C" fn persons_parent(ptr: *const Persons, parent: usize) -> QModelIndex { diff --git a/tests/test_list_rust.cpp b/tests/test_list_rust.cpp index 35cf9b5..25d84c0 100644 --- a/tests/test_list_rust.cpp +++ b/tests/test_list_rust.cpp @@ -55,55 +55,10 @@ void set_qbytearray(QByteArray* v, qbytearray_t* val) { *v = *val; } -extern "C" { - Persons::Private* persons_new(Persons*, - void (*)(const Persons*), - void (*)(Persons*), - void (*)(Persons*), - void (*)(Persons*, int, int), - void (*)(Persons*), - void (*)(Persons*, int, int), - void (*)(Persons*)); - void persons_free(Persons::Private*); -}; -Persons::Persons(QObject *parent): - QAbstractItemModel(parent), - d(persons_new(this, - [](const Persons* o) { - emit o->newDataReady(QModelIndex()); - }, - [](Persons* o) { - o->beginResetModel(); - }, - [](Persons* o) { - o->endResetModel(); - }, - [](Persons* o, int first, int last) { - o->beginInsertRows(QModelIndex(), first, last); - }, - [](Persons* o) { - o->endInsertRows(); - }, - [](Persons* o, int first, int last) { - o->beginRemoveRows(QModelIndex(), first, last); - }, - [](Persons* o) { - o->endRemoveRows(); - } - )) { - connect(this, &Persons::newDataReady, this, [this](const QModelIndex& i) { - fetchMore(i); - }, Qt::QueuedConnection); -} - - -Persons::~Persons() { - persons_free(d); -} extern "C" { void persons_data_user_name(const Persons::Private*, int, QString*, qstring_set); bool persons_set_data_user_name(Persons::Private*, int, qstring_t); - void persons_sort(Persons::Private*, int column, Qt::SortOrder order = Qt::AscendingOrder); + void persons_sort(Persons::Private*, unsigned char column, Qt::SortOrder order = Qt::AscendingOrder); int persons_row_count(const Persons::Private*); bool persons_can_fetch_more(const Persons::Private*); @@ -169,9 +124,9 @@ QVariant Persons::data(const QModelIndex &index, int role) const switch (index.column()) { case 0: switch (role) { - case 256: - case 0: - case 2: + case Qt::DisplayRole: + case Qt::EditRole: + case Qt::UserRole + 0: persons_data_user_name(d, index.row(), &s, set_qstring); if (!s.isNull()) v.setValue(s); break; @@ -182,14 +137,14 @@ QVariant Persons::data(const QModelIndex &index, int role) const } QHash Persons::roleNames() const { QHash names = QAbstractItemModel::roleNames(); - names.insert(256, "userName"); + names.insert(Qt::UserRole + 0, "userName"); return names; } bool Persons::setData(const QModelIndex &index, const QVariant &value, int role) { bool set = false; if (index.column() == 0) { - if (role == 256 || role == 0 || role == 2) { + if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole + 0) { set = persons_set_data_user_name(d, index.row(), value.value()); } } @@ -198,3 +153,48 @@ bool Persons::setData(const QModelIndex &index, const QVariant &value, int role) } return set; } +extern "C" { + Persons::Private* persons_new(Persons*, + void (*)(const Persons*), + void (*)(Persons*), + void (*)(Persons*), + void (*)(Persons*, int, int), + void (*)(Persons*), + void (*)(Persons*, int, int), + void (*)(Persons*)); + void persons_free(Persons::Private*); +}; +Persons::Persons(QObject *parent): + QAbstractItemModel(parent), + d(persons_new(this, + [](const Persons* o) { + emit o->newDataReady(QModelIndex()); + }, + [](Persons* o) { + o->beginResetModel(); + }, + [](Persons* o) { + o->endResetModel(); + }, + [](Persons* o, int first, int last) { + o->beginInsertRows(QModelIndex(), first, last); + }, + [](Persons* o) { + o->endInsertRows(); + }, + [](Persons* o, int first, int last) { + o->beginRemoveRows(QModelIndex(), first, last); + }, + [](Persons* o) { + o->endRemoveRows(); + } + )) { + connect(this, &Persons::newDataReady, this, [this](const QModelIndex& i) { + fetchMore(i); + }, Qt::QueuedConnection); +} + + +Persons::~Persons() { + persons_free(d); +} diff --git a/tests/test_tree_rust.cpp b/tests/test_tree_rust.cpp index 05be20d..f0279b1 100644 --- a/tests/test_tree_rust.cpp +++ b/tests/test_tree_rust.cpp @@ -55,55 +55,10 @@ void set_qbytearray(QByteArray* v, qbytearray_t* val) { *v = *val; } -extern "C" { - Persons::Private* persons_new(Persons*, - void (*)(const Persons*, int, quintptr), - void (*)(Persons*), - void (*)(Persons*), - void (*)(Persons*, int, quintptr, int, int), - void (*)(Persons*), - void (*)(Persons*, int, quintptr, int, int), - void (*)(Persons*)); - void persons_free(Persons::Private*); -}; -Persons::Persons(QObject *parent): - QAbstractItemModel(parent), - d(persons_new(this, - [](const Persons* o, int row, quintptr id) { - emit o->newDataReady(o->createIndex(row, 0, id)); - }, - [](Persons* o) { - o->beginResetModel(); - }, - [](Persons* o) { - o->endResetModel(); - }, - [](Persons* o, int row, quintptr id, int first, int last) { - o->beginInsertRows(o->createIndex(row, 0, id), first, last); - }, - [](Persons* o) { - o->endInsertRows(); - }, - [](Persons* o, int row, quintptr id, int first, int last) { - o->beginRemoveRows(o->createIndex(row, 0, id), first, last); - }, - [](Persons* o) { - o->endRemoveRows(); - } - )) { - connect(this, &Persons::newDataReady, this, [this](const QModelIndex& i) { - fetchMore(i); - }, Qt::QueuedConnection); -} - - -Persons::~Persons() { - persons_free(d); -} extern "C" { void persons_data_user_name(const Persons::Private*, int, quintptr, QString*, qstring_set); bool persons_set_data_user_name(Persons::Private*, int, quintptr, qstring_t); - void persons_sort(Persons::Private*, int column, Qt::SortOrder order = Qt::AscendingOrder); + void persons_sort(Persons::Private*, unsigned char column, Qt::SortOrder order = Qt::AscendingOrder); int persons_row_count(const Persons::Private*, int, quintptr); bool persons_can_fetch_more(const Persons::Private*, int, quintptr); @@ -183,9 +138,9 @@ QVariant Persons::data(const QModelIndex &index, int role) const switch (index.column()) { case 0: switch (role) { - case 256: - case 0: - case 2: + case Qt::DisplayRole: + case Qt::EditRole: + case Qt::UserRole + 0: persons_data_user_name(d, index.row(), index.internalId(), &s, set_qstring); if (!s.isNull()) v.setValue(s); break; @@ -196,14 +151,14 @@ QVariant Persons::data(const QModelIndex &index, int role) const } QHash Persons::roleNames() const { QHash names = QAbstractItemModel::roleNames(); - names.insert(256, "userName"); + names.insert(Qt::UserRole + 0, "userName"); return names; } bool Persons::setData(const QModelIndex &index, const QVariant &value, int role) { bool set = false; if (index.column() == 0) { - if (role == 256 || role == 0 || role == 2) { + if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole + 0) { set = persons_set_data_user_name(d, index.row(), index.internalId(), value.value()); } } @@ -212,3 +167,51 @@ bool Persons::setData(const QModelIndex &index, const QVariant &value, int role) } return set; } +extern "C" { + Persons::Private* persons_new(Persons*, + void (*)(const Persons*, quintptr), + void (*)(Persons*), + void (*)(Persons*), + void (*)(Persons*, quintptr, int, int), + void (*)(Persons*), + void (*)(Persons*, quintptr, int, int), + void (*)(Persons*)); + void persons_free(Persons::Private*); +}; +Persons::Persons(QObject *parent): + QAbstractItemModel(parent), + d(persons_new(this, + [](const Persons* o, quintptr id) { + auto i = persons_parent(o->d, id); + emit o->newDataReady(o->createIndex(i.row, 0, i.id)); + }, + [](Persons* o) { + o->beginResetModel(); + }, + [](Persons* o) { + o->endResetModel(); + }, + [](Persons* o, quintptr id, int first, int last) { + auto i = persons_parent(o->d, id); + o->beginInsertRows(o->createIndex(i.row, 0, i.id), first, last); + }, + [](Persons* o) { + o->endInsertRows(); + }, + [](Persons* o, quintptr id, int first, int last) { + auto i = persons_parent(o->d, id); + o->beginRemoveRows(o->createIndex(i.row, 0, i.id), first, last); + }, + [](Persons* o) { + o->endRemoveRows(); + } + )) { + connect(this, &Persons::newDataReady, this, [this](const QModelIndex& i) { + fetchMore(i); + }, Qt::QueuedConnection); +} + + +Persons::~Persons() { + persons_free(d); +}