diff --git a/demo/rust/src/interface.rs b/demo/rust/src/interface.rs index 538557c..d851e39 100644 --- a/demo/rust/src/interface.rs +++ b/demo/rust/src/interface.rs @@ -1,7 +1,7 @@ /* generated by rust_qt_binding_generator */ #![allow(unknown_lints)] #![allow(mutex_atomic, needless_pass_by_value)] -use libc::{c_char, c_ushort, c_int, c_void, uint8_t, uint16_t}; +use libc::{c_char, c_ushort, c_int, c_void}; use std::slice; use std::char::decode_utf16; @@ -388,8 +388,8 @@ pub trait FibonacciListTrait { fn new(emit: FibonacciListEmitter, model: FibonacciListList) -> Self; fn emit(&self) -> &FibonacciListEmitter; fn row_count(&self) -> usize; - fn insert_rows(&mut self, row: usize, count: usize) -> bool { false } - fn remove_rows(&mut self, row: usize, count: usize) -> bool { false } + fn insert_rows(&mut self, _row: usize, _count: usize) -> bool { false } + fn remove_rows(&mut self, _row: usize, _count: usize) -> bool { false } fn can_fetch_more(&self) -> bool { false } @@ -619,6 +619,7 @@ pub extern "C" fn file_system_tree_path_set(ptr: *mut FileSystemTree, v: *const set_string_from_utf16(&mut s, v, len); o.set_path(Some(s)); } + #[no_mangle] pub extern "C" fn file_system_tree_path_set_none(ptr: *mut FileSystemTree) { let o = unsafe { &mut *ptr }; @@ -1074,8 +1075,8 @@ pub trait TimeSeriesTrait { fn new(emit: TimeSeriesEmitter, model: TimeSeriesList) -> Self; fn emit(&self) -> &TimeSeriesEmitter; fn row_count(&self) -> usize; - fn insert_rows(&mut self, row: usize, count: usize) -> bool { false } - fn remove_rows(&mut self, row: usize, count: usize) -> bool { false } + fn insert_rows(&mut self, _row: usize, _count: usize) -> bool { false } + fn remove_rows(&mut self, _row: usize, _count: usize) -> bool { false } fn can_fetch_more(&self) -> bool { false } diff --git a/src/cpp.cpp b/src/cpp.cpp index 7091886..509b5c8 100644 --- a/src/cpp.cpp +++ b/src/cpp.cpp @@ -516,8 +516,12 @@ private: )"; for (auto p: o.properties) { bool obj = p.type.type == BindingType::Object; + auto t = p.type.name; + if (p.optional && !p.type.isComplex()) { + t = "QVariant"; + } h << QString(" Q_PROPERTY(%1 %2 READ %2 %3NOTIFY %2Changed FINAL)") - .arg(p.type.name + (obj ?"*" :""), + .arg(t + (obj ?"*" :""), p.name, p.write ? writeProperty(p.name) :"") << endl; @@ -532,9 +536,15 @@ public: h << " const " << p.type.name << "* " << p.name << "() const;" << endl; h << " " << p.type.name << "* " << p.name << "();" << endl; } else { - h << " " << p.type.name << " " << p.name << "() const;" << endl; + auto t = p.type.name; + auto t2 = p.type.cppSetType; + if (p.optional && !p.type.isComplex()) { + t = "QVariant"; + t2 = "const QVariant&"; + } + h << " " << t << " " << p.name << "() const;" << endl; if (p.write) { - h << " void set" << upperInitial(p.name) << "(" << p.type.cppSetType << " v);" << endl; + h << " void set" << upperInitial(p.name) << "(" << t2 << " v);" << endl; } } } @@ -730,6 +740,9 @@ void writeObjectCDecl(QTextStream& cpp, const Object& o, const Configuration& co } else if (p.type.isComplex()) { cpp << QString(" void %2_get(const %1::Private*, %3);") .arg(o.name, base, cGetType(p.type)) << endl; + } else if (p.optional) { + cpp << QString(" option_%3 %2_get(const %1::Private*);") + .arg(o.name, base, p.type.name) << endl; } else { cpp << QString(" %3 %2_get(const %1::Private*);") .arg(o.name, base, p.type.name) << endl; @@ -868,20 +881,39 @@ void writeCppObject(QTextStream& cpp, const Object& o, const Configuration& conf cpp << " " << base << "_get(m_d, &v, set_" << p.type.name.toLower() << ");\n"; cpp << " return v;\n}\n"; + } else if (p.optional) { + cpp << QString("QVariant %1::%2() const\n{\n").arg(o.name, p.name); + cpp << " QVariant v;\n"; + cpp << QString(" auto r = %1_get(m_d);\n").arg(base); + cpp << " if (r.some) {\n"; + cpp << " v.setValue(r.value);\n"; + cpp << " }\n"; + cpp << " return r;\n"; + cpp << "}\n"; } else { cpp << QString("%3 %1::%2() const\n{\n").arg(o.name, p.name, p.type.name); cpp << QString(" return %1_get(m_d);\n}\n").arg(base); } if (p.write) { - cpp << "void " << o.name << "::set" << upperInitial(p.name) << "(" << p.type.cppSetType << " v) {" << endl; + auto t = p.type.cppSetType; + if (p.optional && !p.type.isComplex()) { + t = "const QVariant&"; + } + cpp << "void " << o.name << "::set" << upperInitial(p.name) << "(" << t << " v) {" << endl; if (p.optional) { - cpp << QString(" if (v.isNull()) {") << endl; + if (p.type.isComplex()) { + cpp << " if (v.isNull()) {" << endl; + } else { + cpp << QString(" if (v.isNull() || !v.canConvert<%1>()) {").arg(p.type.name) << endl; + } cpp << QString(" %1_set_none(m_d);").arg(base) << endl; cpp << QString(" } else {") << endl; if (p.type.name == "QString") { cpp << QString(" %1_set(m_d, reinterpret_cast(v.data()), v.size());").arg(base) << endl; } else if (p.type.name == "QByteArray") { cpp << QString(" %1_set(m_d, v.data(), v.size());").arg(base) << endl; + } else if (p.optional) { + cpp << QString(" %1_set(m_d, v.value<%2>());").arg(base, p.type.name) << endl; } else { cpp << QString(" %1_set(m_d, v);").arg(base) << endl; } diff --git a/src/rust.cpp b/src/rust.cpp index e0b0ad8..cca4e91 100644 --- a/src/rust.cpp +++ b/src/rust.cpp @@ -353,8 +353,8 @@ pub trait %1Trait { } if (o.type == ObjectType::List) { r << R"( fn row_count(&self) -> usize; - fn insert_rows(&mut self, row: usize, count: usize) -> bool { false } - fn remove_rows(&mut self, row: usize, count: usize) -> bool { false } + fn insert_rows(&mut self, _row: usize, _count: usize) -> bool { false } + fn remove_rows(&mut self, _row: usize, _count: usize) -> bool { false } fn can_fetch_more(&self) -> bool { false } @@ -470,11 +470,6 @@ pub extern "C" fn %2_set(ptr: *mut %1, v: *const c_ushort, len: c_int) { set_string_from_utf16(&mut s, v, len); o.set_%3(Some(s)); } -#[no_mangle] -pub extern "C" fn %2_set_none(ptr: *mut %1) { - let o = unsafe { &mut *ptr }; - o.set_%3(None); -} )").arg(o.name, base, snakeCase(p.name)); } else if (p.write) { r << QString(R"( @@ -484,13 +479,26 @@ pub extern "C" fn %2_set(ptr: *mut %1, v: *const c_char, len: c_int) { let v = unsafe { slice::from_raw_parts(v as *const u8, len as usize) }; o.set_%3(Some(v.into())); } -#[no_mangle] -pub extern "C" fn %2_set_none(ptr: *mut %1) { - let o = unsafe { &mut *ptr }; - o.set_%3(None); -} )").arg(o.name, base, snakeCase(p.name)); } + } else if (p.optional) { + r << QString(R"( +#[no_mangle] +pub unsafe extern "C" fn %2_get(ptr: *const %1) -> COption<%4> { + match (&*ptr).%3() { + Some(value) => COption { data: value, some: true }, + None => COption { data: %4::default(), some: false} + } +} +)").arg(o.name, base, snakeCase(p.name), p.type.rustType); + if (p.write) { + r << QString(R"( +#[no_mangle] +pub unsafe extern "C" fn %2_set(ptr: *mut %1, v: %4) { + (&mut *ptr).set_%3(Some(v)); +} +)").arg(o.name, base, snakeCase(p.name), p.type.rustType); + } } else { r << QString(R"( #[no_mangle] @@ -507,6 +515,15 @@ pub unsafe extern "C" fn %2_set(ptr: *mut %1, v: %4) { )").arg(o.name, base, snakeCase(p.name), rustType(p)); } } + if (p.write && p.optional) { + r << QString(R"( +#[no_mangle] +pub extern "C" fn %2_set_none(ptr: *mut %1) { + let o = unsafe { &mut *ptr }; + o.set_%3(None); +} +)").arg(o.name, base, snakeCase(p.name)); + } } for (const Function& f: o.functions) { writeFunction(r, f, lcname, o); @@ -828,7 +845,7 @@ void writeRustInterface(const Configuration& conf) { r << QString(R"(/* generated by rust_qt_binding_generator */ #![allow(unknown_lints)] #![allow(mutex_atomic, needless_pass_by_value)] -use libc::{c_char, c_ushort, c_int, c_void, uint8_t, uint16_t}; +use libc::{c_char, c_ushort, c_int, c_void}; use std::slice; use std::char::decode_utf16; diff --git a/src/structs.h b/src/structs.h index 4b9a3aa..daf0de6 100644 --- a/src/structs.h +++ b/src/structs.h @@ -155,6 +155,11 @@ struct Configuration { QList optionalTypes() const { QList ops; for (auto o: objects) { + for (auto ip: o.properties) { + if (ip.optional && !ops.contains(ip.type.name)) { + ops.append(ip.type.name); + } + } for (auto ip: o.itemProperties) { if (ip.optional && !ops.contains(ip.type.name)) { ops.append(ip.type.name); diff --git a/tests/rust_functions/src/interface.rs b/tests/rust_functions/src/interface.rs index 94861e4..735e9c6 100644 --- a/tests/rust_functions/src/interface.rs +++ b/tests/rust_functions/src/interface.rs @@ -1,7 +1,7 @@ /* generated by rust_qt_binding_generator */ #![allow(unknown_lints)] #![allow(mutex_atomic, needless_pass_by_value)] -use libc::{c_char, c_ushort, c_int, c_void, uint8_t, uint16_t}; +use libc::{c_char, c_ushort, c_int, c_void}; use std::slice; use std::char::decode_utf16; diff --git a/tests/rust_list/src/interface.rs b/tests/rust_list/src/interface.rs index 0cb3d18..d491b93 100644 --- a/tests/rust_list/src/interface.rs +++ b/tests/rust_list/src/interface.rs @@ -1,7 +1,7 @@ /* generated by rust_qt_binding_generator */ #![allow(unknown_lints)] #![allow(mutex_atomic, needless_pass_by_value)] -use libc::{c_char, c_ushort, c_int, c_void, uint8_t, uint16_t}; +use libc::{c_char, c_ushort, c_int, c_void}; use std::slice; use std::char::decode_utf16; @@ -123,8 +123,8 @@ pub trait PersonsTrait { fn new(emit: PersonsEmitter, model: PersonsList) -> Self; fn emit(&self) -> &PersonsEmitter; fn row_count(&self) -> usize; - fn insert_rows(&mut self, row: usize, count: usize) -> bool { false } - fn remove_rows(&mut self, row: usize, count: usize) -> bool { false } + fn insert_rows(&mut self, _row: usize, _count: usize) -> bool { false } + fn remove_rows(&mut self, _row: usize, _count: usize) -> bool { false } fn can_fetch_more(&self) -> bool { false } diff --git a/tests/rust_list_types/src/implementation.rs b/tests/rust_list_types/src/implementation.rs index f591a85..9a3850e 100644 --- a/tests/rust_list_types/src/implementation.rs +++ b/tests/rust_list_types/src/implementation.rs @@ -6,6 +6,7 @@ use interface::*; #[derive(Default, Clone)] struct ListItem { boolean: bool, + optional_boolean: Option, i8: i8, u8: u8, i16: i16, @@ -49,6 +50,13 @@ impl ListTrait for List { self.list[item].boolean = v; true } + fn optional_boolean(&self, item: usize) -> Option { + self.list[item].optional_boolean + } + fn set_optional_boolean(&mut self, item: usize, v: Option) -> bool { + self.list[item].optional_boolean = v; + true + } fn i8(&self, item: usize) -> i8 { self.list[item].i8 } diff --git a/tests/rust_list_types/src/interface.rs b/tests/rust_list_types/src/interface.rs index 63e8ea9..bf56aad 100644 --- a/tests/rust_list_types/src/interface.rs +++ b/tests/rust_list_types/src/interface.rs @@ -1,7 +1,7 @@ /* generated by rust_qt_binding_generator */ #![allow(unknown_lints)] #![allow(mutex_atomic, needless_pass_by_value)] -use libc::{c_char, c_ushort, c_int, c_void, uint8_t, uint16_t}; +use libc::{c_char, c_ushort, c_int, c_void}; use std::slice; use std::char::decode_utf16; @@ -126,8 +126,8 @@ pub trait ListTrait { fn new(emit: ListEmitter, model: ListList) -> Self; fn emit(&self) -> &ListEmitter; fn row_count(&self) -> usize; - fn insert_rows(&mut self, row: usize, count: usize) -> bool { false } - fn remove_rows(&mut self, row: usize, count: usize) -> bool { false } + fn insert_rows(&mut self, _row: usize, _count: usize) -> bool { false } + fn remove_rows(&mut self, _row: usize, _count: usize) -> bool { false } fn can_fetch_more(&self) -> bool { false } @@ -149,6 +149,8 @@ pub trait ListTrait { fn set_i64(&mut self, item: usize, i64) -> bool; fn i8(&self, item: usize) -> i8; fn set_i8(&mut self, item: usize, i8) -> bool; + fn optional_boolean(&self, item: usize) -> Option; + fn set_optional_boolean(&mut self, item: usize, Option) -> bool; fn optional_bytearray(&self, item: usize) -> Option<&[u8]>; fn set_optional_bytearray(&mut self, item: usize, Option>) -> bool; fn optional_string(&self, item: usize) -> Option<&str>; @@ -351,6 +353,25 @@ pub unsafe extern "C" fn list_set_data_i8( (&mut *ptr).set_i8(row as usize, v) } +#[no_mangle] +pub extern "C" fn list_data_optional_boolean(ptr: *const List, row: c_int) -> COption { + let o = unsafe { &*ptr }; + o.optional_boolean(row as usize).into() +} + +#[no_mangle] +pub unsafe extern "C" fn list_set_data_optional_boolean( + ptr: *mut List, row: c_int, + v: bool, +) -> bool { + (&mut *ptr).set_optional_boolean(row as usize, Some(v)) +} + +#[no_mangle] +pub unsafe extern "C" fn list_set_data_optional_boolean_none(ptr: *mut List, row: c_int) -> bool { + (&mut *ptr).set_optional_boolean(row as usize, None) +} + #[no_mangle] pub extern "C" fn list_data_optional_bytearray( ptr: *const List, row: c_int, diff --git a/tests/rust_object/src/interface.rs b/tests/rust_object/src/interface.rs index 6c3b2ee..9f5e603 100644 --- a/tests/rust_object/src/interface.rs +++ b/tests/rust_object/src/interface.rs @@ -1,7 +1,7 @@ /* generated by rust_qt_binding_generator */ #![allow(unknown_lints)] #![allow(mutex_atomic, needless_pass_by_value)] -use libc::{c_char, c_ushort, c_int, c_void, uint8_t, uint16_t}; +use libc::{c_char, c_ushort, c_int, c_void}; use std::slice; use std::char::decode_utf16; diff --git a/tests/rust_object_types/src/implementation.rs b/tests/rust_object_types/src/implementation.rs index b70c0d9..269f62d 100644 --- a/tests/rust_object_types/src/implementation.rs +++ b/tests/rust_object_types/src/implementation.rs @@ -6,6 +6,7 @@ use interface::*; pub struct Object { emit: ObjectEmitter, boolean: bool, + optional_boolean: Option, i8: i8, u8: u8, i16: i16, @@ -14,6 +15,7 @@ pub struct Object { u32: u32, i64: i64, u64: u64, + optional_u64: Option, f32: f32, f64: f64, bytearray: Vec, @@ -27,6 +29,7 @@ impl ObjectTrait for Object { Object { emit, boolean: false, + optional_boolean: None, i8: 0, u8: 0, i16: 0, @@ -35,6 +38,7 @@ impl ObjectTrait for Object { u32: 0, i64: 0, u64: 0, + optional_u64: None, f32: 0., f64: 0., bytearray: Vec::new(), @@ -53,6 +57,13 @@ impl ObjectTrait for Object { self.boolean = value; self.emit.boolean_changed(); } + fn optional_boolean(&self) -> Option { + self.optional_boolean + } + fn set_optional_boolean(&mut self, b: Option) { + self.optional_boolean = b; + self.emit.optional_boolean_changed(); + } fn i8(&self) -> i8 { self.i8 } @@ -109,6 +120,13 @@ impl ObjectTrait for Object { self.u64 = value; self.emit.u64_changed(); } + fn optional_u64(&self) -> Option { + self.optional_u64 + } + fn set_optional_u64(&mut self, v: Option) { + self.optional_u64 = v; + self.emit.optional_u64_changed(); + } fn f32(&self) -> f32 { self.f32 } @@ -123,14 +141,6 @@ impl ObjectTrait for Object { self.f64 = value; self.emit.f64_changed(); } - /* - fn optional_boolean(&self) -> Option { - self.optional_boolean - } - fn set_optional_boolean(&mut self, b: Option) { - self.optional_boolean = b; - } - */ fn bytearray(&self) -> &[u8] { &self.bytearray } diff --git a/tests/rust_object_types/src/interface.rs b/tests/rust_object_types/src/interface.rs index ab06e6a..688cd6c 100644 --- a/tests/rust_object_types/src/interface.rs +++ b/tests/rust_object_types/src/interface.rs @@ -1,7 +1,7 @@ /* generated by rust_qt_binding_generator */ #![allow(unknown_lints)] #![allow(mutex_atomic, needless_pass_by_value)] -use libc::{c_char, c_ushort, c_int, c_void, uint8_t, uint16_t}; +use libc::{c_char, c_ushort, c_int, c_void}; use std::slice; use std::char::decode_utf16; @@ -65,8 +65,10 @@ pub struct ObjectEmitter { i32_changed: fn(*const ObjectQObject), i64_changed: fn(*const ObjectQObject), i8_changed: fn(*const ObjectQObject), + optional_boolean_changed: fn(*const ObjectQObject), optional_bytearray_changed: fn(*const ObjectQObject), optional_string_changed: fn(*const ObjectQObject), + optional_u64_changed: fn(*const ObjectQObject), string_changed: fn(*const ObjectQObject), u16_changed: fn(*const ObjectQObject), u32_changed: fn(*const ObjectQObject), @@ -128,6 +130,12 @@ impl ObjectEmitter { (self.i8_changed)(ptr); } } + pub fn optional_boolean_changed(&self) { + let ptr = *self.qobject.lock().unwrap(); + if !ptr.is_null() { + (self.optional_boolean_changed)(ptr); + } + } pub fn optional_bytearray_changed(&self) { let ptr = *self.qobject.lock().unwrap(); if !ptr.is_null() { @@ -140,6 +148,12 @@ impl ObjectEmitter { (self.optional_string_changed)(ptr); } } + pub fn optional_u64_changed(&self) { + let ptr = *self.qobject.lock().unwrap(); + if !ptr.is_null() { + (self.optional_u64_changed)(ptr); + } + } pub fn string_changed(&self) { let ptr = *self.qobject.lock().unwrap(); if !ptr.is_null() { @@ -191,10 +205,14 @@ pub trait ObjectTrait { fn set_i64(&mut self, value: i64); fn i8(&self) -> i8; fn set_i8(&mut self, value: i8); + fn optional_boolean(&self) -> Option; + fn set_optional_boolean(&mut self, value: Option); fn optional_bytearray(&self) -> Option<&[u8]>; fn set_optional_bytearray(&mut self, value: Option>); fn optional_string(&self) -> Option<&str>; fn set_optional_string(&mut self, value: Option); + fn optional_u64(&self) -> Option; + fn set_optional_u64(&mut self, value: Option); fn string(&self) -> &str; fn set_string(&mut self, value: String); fn u16(&self) -> u16; @@ -218,8 +236,10 @@ pub extern "C" fn object_new( i32_changed: fn(*const ObjectQObject), i64_changed: fn(*const ObjectQObject), i8_changed: fn(*const ObjectQObject), + optional_boolean_changed: fn(*const ObjectQObject), optional_bytearray_changed: fn(*const ObjectQObject), optional_string_changed: fn(*const ObjectQObject), + optional_u64_changed: fn(*const ObjectQObject), string_changed: fn(*const ObjectQObject), u16_changed: fn(*const ObjectQObject), u32_changed: fn(*const ObjectQObject), @@ -236,8 +256,10 @@ pub extern "C" fn object_new( i32_changed: i32_changed, i64_changed: i64_changed, i8_changed: i8_changed, + optional_boolean_changed: optional_boolean_changed, optional_bytearray_changed: optional_bytearray_changed, optional_string_changed: optional_string_changed, + optional_u64_changed: optional_u64_changed, string_changed: string_changed, u16_changed: u16_changed, u32_changed: u32_changed, @@ -342,6 +364,25 @@ pub unsafe extern "C" fn object_i8_set(ptr: *mut Object, v: i8) { (&mut *ptr).set_i8(v); } +#[no_mangle] +pub unsafe extern "C" fn object_optional_boolean_get(ptr: *const Object) -> COption { + match (&*ptr).optional_boolean() { + Some(value) => COption { data: value, some: true }, + None => COption { data: bool::default(), some: false} + } +} + +#[no_mangle] +pub unsafe extern "C" fn object_optional_boolean_set(ptr: *mut Object, v: bool) { + (&mut *ptr).set_optional_boolean(Some(v)); +} + +#[no_mangle] +pub extern "C" fn object_optional_boolean_set_none(ptr: *mut Object) { + let o = unsafe { &mut *ptr }; + o.set_optional_boolean(None); +} + #[no_mangle] pub extern "C" fn object_optional_bytearray_get( ptr: *const Object, @@ -362,6 +403,7 @@ pub extern "C" fn object_optional_bytearray_set(ptr: *mut Object, v: *const c_ch let v = unsafe { slice::from_raw_parts(v as *const u8, len as usize) }; o.set_optional_bytearray(Some(v.into())); } + #[no_mangle] pub extern "C" fn object_optional_bytearray_set_none(ptr: *mut Object) { let o = unsafe { &mut *ptr }; @@ -389,12 +431,32 @@ pub extern "C" fn object_optional_string_set(ptr: *mut Object, v: *const c_ushor set_string_from_utf16(&mut s, v, len); o.set_optional_string(Some(s)); } + #[no_mangle] pub extern "C" fn object_optional_string_set_none(ptr: *mut Object) { let o = unsafe { &mut *ptr }; o.set_optional_string(None); } +#[no_mangle] +pub unsafe extern "C" fn object_optional_u64_get(ptr: *const Object) -> COption { + match (&*ptr).optional_u64() { + Some(value) => COption { data: value, some: true }, + None => COption { data: u64::default(), some: false} + } +} + +#[no_mangle] +pub unsafe extern "C" fn object_optional_u64_set(ptr: *mut Object, v: u64) { + (&mut *ptr).set_optional_u64(Some(v)); +} + +#[no_mangle] +pub extern "C" fn object_optional_u64_set_none(ptr: *mut Object) { + let o = unsafe { &mut *ptr }; + o.set_optional_u64(None); +} + #[no_mangle] pub extern "C" fn object_string_get( ptr: *const Object, diff --git a/tests/rust_objects/src/interface.rs b/tests/rust_objects/src/interface.rs index f0d4552..d8e6ef5 100644 --- a/tests/rust_objects/src/interface.rs +++ b/tests/rust_objects/src/interface.rs @@ -1,7 +1,7 @@ /* generated by rust_qt_binding_generator */ #![allow(unknown_lints)] #![allow(mutex_atomic, needless_pass_by_value)] -use libc::{c_char, c_ushort, c_int, c_void, uint8_t, uint16_t}; +use libc::{c_char, c_ushort, c_int, c_void}; use std::slice; use std::char::decode_utf16; diff --git a/tests/rust_tree/src/interface.rs b/tests/rust_tree/src/interface.rs index 9ca9c83..55f9ddc 100644 --- a/tests/rust_tree/src/interface.rs +++ b/tests/rust_tree/src/interface.rs @@ -1,7 +1,7 @@ /* generated by rust_qt_binding_generator */ #![allow(unknown_lints)] #![allow(mutex_atomic, needless_pass_by_value)] -use libc::{c_char, c_ushort, c_int, c_void, uint8_t, uint16_t}; +use libc::{c_char, c_ushort, c_int, c_void}; use std::slice; use std::char::decode_utf16; diff --git a/tests/test_list_types.cpp b/tests/test_list_types.cpp index 451a4ac..a289ad5 100644 --- a/tests/test_list_types.cpp +++ b/tests/test_list_types.cpp @@ -30,6 +30,7 @@ private slots: void testStringGetter(); void testStringSetter(); void testBool(); + void testOptionalBool(); void testInt8(); void testUint8(); void testInt16(); @@ -53,6 +54,26 @@ void testSetter(const V v, Set set, Get get) List list; QSignalSpy spy(&list, &List::dataChanged); + // WHEN + const QVariant vv = QVariant::fromValue(v); + QVERIFY(!vv.isNull()); + bool ok = (list.*set)(0, vv); + QVERIFY(ok); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(spy.count(), 1); + QCOMPARE((list.*get)(0), vv); +} + +template +void testOptionalSetter(const V v, Set set, Get get) +{ + // GIVEN + List list; + QSignalSpy spy(&list, &List::dataChanged); + QVERIFY((list.*get)(0).isNull()); + // WHEN QVariant vv = QVariant::fromValue(v); if (vv.isNull()) { @@ -90,6 +111,28 @@ void testDataSetter(const char* roleName, const V v) // WHEN int role = getRoleFromName(list, roleName); auto index = list.index(1, 0); + const QVariant vv = QVariant::fromValue(v); + QVERIFY(!vv.isNull()); + bool ok = list.setData(index, vv, role); + QVERIFY(ok); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(spy.count(), 1); + QCOMPARE(list.data(index, role), vv); +} + +template +void testOptionalDataSetter(const char* roleName, const V v) +{ + // GIVEN + List list; + QSignalSpy spy(&list, &List::dataChanged); + int role = getRoleFromName(list, roleName); + auto index = list.index(1, 0); + QVERIFY(list.data(index, role).isNull()); + + // WHEN QVariant vv = QVariant::fromValue(v); if (vv.isNull()) { vv = QVariant(); @@ -107,7 +150,14 @@ template void test(const V v, Set set, Get get, const char* roleName) { testSetter(v, set, get); - //testDataSetter(roleName, v); + testDataSetter(roleName, v); +} + +template +void testOptional(const V v, Set set, Get get, const char* roleName) +{ + testOptionalSetter(v, set, get); + testOptionalDataSetter(roleName, v); } void TestRustListTypes::testConstructor() @@ -121,6 +171,14 @@ void TestRustListTypes::testBool() test(false, &List::setBoolean, &List::boolean, "boolean"); } +void TestRustListTypes::testOptionalBool() +{ + testOptional(true, &List::setOptionalBoolean, &List::optionalBoolean, + "optionalBoolean"); + testOptional(false, &List::setOptionalBoolean, &List::optionalBoolean, + "optionalBoolean"); +} + void TestRustListTypes::testInt8() { test(0, &List::setI8, &List::i8, "i8"); @@ -210,14 +268,14 @@ void TestRustListTypes::testString() void TestRustListTypes::testOptionalString() { - test(QString(), &List::setOptionalString, &List::optionalString, + testOptional(QString(), &List::setOptionalString, &List::optionalString, "optionalString"); - test(QString(""), &List::setOptionalString, &List::optionalString, - "optionalString"); - test(QString("Konqi"), &List::setOptionalString, &List::optionalString, - "optionalString"); - test(QString("$𐐷𤭢"), &List::setOptionalString, &List::optionalString, + testOptional(QString(""), &List::setOptionalString, &List::optionalString, "optionalString"); + testOptional(QString("Konqi"), &List::setOptionalString, + &List::optionalString, "optionalString"); + testOptional(QString("$𐐷𤭢"), &List::setOptionalString, + &List::optionalString, "optionalString"); } void TestRustListTypes::testByteArray() @@ -231,16 +289,15 @@ void TestRustListTypes::testByteArray() void TestRustListTypes::testOptionalByteArray() { - test(QByteArray(), &List::setOptionalBytearray, &List::optionalBytearray, - "optionalBytearray"); + testOptional(QByteArray(), &List::setOptionalBytearray, + &List::optionalBytearray, "optionalBytearray"); const char data[10] = {0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9}; - test(QByteArray(data, 0), &List::setOptionalBytearray, + testOptional(QByteArray(data, 0), &List::setOptionalBytearray, &List::optionalBytearray, "optionalBytearray"); - test(QByteArray(data, 10), &List::setOptionalBytearray, + testOptional(QByteArray(data, 10), &List::setOptionalBytearray, &List::optionalBytearray, "optionalBytearray"); } - void TestRustListTypes::testStringGetter() { List list; diff --git a/tests/test_list_types.json b/tests/test_list_types.json index 6f4b2a5..441911c 100644 --- a/tests/test_list_types.json +++ b/tests/test_list_types.json @@ -13,6 +13,11 @@ "type": "bool", "write": true }, + "optionalBoolean": { + "optional": true, + "type": "bool", + "write": true + }, "i8": { "type": "qint8", "write": true diff --git a/tests/test_list_types_rust.cpp b/tests/test_list_types_rust.cpp index 50b79a6..3e5cae0 100644 --- a/tests/test_list_types_rust.cpp +++ b/tests/test_list_types_rust.cpp @@ -3,6 +3,19 @@ namespace { + struct option_bool { + public: + bool value; + bool some; + operator QVariant() const { + if (some) { + return QVariant::fromValue(value); + } + return QVariant(); + } + }; + static_assert(std::is_pod::value, "option_bool must be a POD type."); + struct option_quintptr { public: quintptr value; @@ -53,6 +66,9 @@ extern "C" { bool list_set_data_i64(List::Private*, int, qint64); qint8 list_data_i8(const List::Private*, int); bool list_set_data_i8(List::Private*, int, qint8); + option_bool list_data_optional_boolean(const List::Private*, int); + bool list_set_data_optional_boolean(List::Private*, int, bool); + bool list_set_data_optional_boolean_none(List::Private*, int); void list_data_optional_bytearray(const List::Private*, int, QByteArray*, qbytearray_set); bool list_set_data_optional_bytearray(List::Private*, int, const char* s, int len); bool list_set_data_optional_bytearray_none(List::Private*, int); @@ -311,6 +327,31 @@ bool List::setI8(int row, const QVariant& value) return set; } +QVariant List::optionalBoolean(int row) const +{ + QVariant v; + v = list_data_optional_boolean(m_d, row); + return v; +} + +bool List::setOptionalBoolean(int row, const QVariant& value) +{ + bool set = false; + if (!value.isValid()) { + set = list_set_data_optional_boolean_none(m_d, row); + } else { + if (!value.canConvert(qMetaTypeId())) { + return false; + } + set = list_set_data_optional_boolean(m_d, row, value.value()); + } + if (set) { + QModelIndex index = createIndex(row, 0, row); + emit dataChanged(index, index); + } + return set; +} + QVariant List::optionalBytearray(int row) const { QVariant v; @@ -498,20 +539,22 @@ QVariant List::data(const QModelIndex &index, int role) const case Qt::UserRole + 7: return i8(index.row()); case Qt::UserRole + 8: - return optionalBytearray(index.row()); + return optionalBoolean(index.row()); case Qt::UserRole + 9: + return optionalBytearray(index.row()); + case Qt::UserRole + 10: return optionalString(index.row()); case Qt::DisplayRole: case Qt::EditRole: - case Qt::UserRole + 10: - return string(index.row()); case Qt::UserRole + 11: - return u16(index.row()); + return string(index.row()); case Qt::UserRole + 12: - return u32(index.row()); + return u16(index.row()); case Qt::UserRole + 13: - return u64(index.row()); + return u32(index.row()); case Qt::UserRole + 14: + return u64(index.row()); + case Qt::UserRole + 15: return u8(index.row()); } } @@ -528,13 +571,14 @@ QHash List::roleNames() const { names.insert(Qt::UserRole + 5, "i32"); names.insert(Qt::UserRole + 6, "i64"); names.insert(Qt::UserRole + 7, "i8"); - names.insert(Qt::UserRole + 8, "optionalBytearray"); - names.insert(Qt::UserRole + 9, "optionalString"); - names.insert(Qt::UserRole + 10, "string"); - names.insert(Qt::UserRole + 11, "u16"); - names.insert(Qt::UserRole + 12, "u32"); - names.insert(Qt::UserRole + 13, "u64"); - names.insert(Qt::UserRole + 14, "u8"); + names.insert(Qt::UserRole + 8, "optionalBoolean"); + names.insert(Qt::UserRole + 9, "optionalBytearray"); + names.insert(Qt::UserRole + 10, "optionalString"); + names.insert(Qt::UserRole + 11, "string"); + names.insert(Qt::UserRole + 12, "u16"); + names.insert(Qt::UserRole + 13, "u32"); + names.insert(Qt::UserRole + 14, "u64"); + names.insert(Qt::UserRole + 15, "u8"); return names; } QVariant List::headerData(int section, Qt::Orientation orientation, int role) const @@ -582,24 +626,27 @@ bool List::setData(const QModelIndex &index, const QVariant &value, int role) return setI8(index.row(), value); } if (role == Qt::UserRole + 8) { - return setOptionalBytearray(index.row(), value); + return setOptionalBoolean(index.row(), value); } if (role == Qt::UserRole + 9) { + return setOptionalBytearray(index.row(), value); + } + if (role == Qt::UserRole + 10) { return setOptionalString(index.row(), value); } - if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole + 10) { + if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole + 11) { return setString(index.row(), value); } - if (role == Qt::UserRole + 11) { + if (role == Qt::UserRole + 12) { return setU16(index.row(), value); } - if (role == Qt::UserRole + 12) { + if (role == Qt::UserRole + 13) { return setU32(index.row(), value); } - if (role == Qt::UserRole + 13) { + if (role == Qt::UserRole + 14) { return setU64(index.row(), value); } - if (role == Qt::UserRole + 14) { + if (role == Qt::UserRole + 15) { return setU8(index.row(), value); } } diff --git a/tests/test_list_types_rust.h b/tests/test_list_types_rust.h index 1c84341..84b865a 100644 --- a/tests/test_list_types_rust.h +++ b/tests/test_list_types_rust.h @@ -52,6 +52,8 @@ public: Q_INVOKABLE bool setI64(int row, const QVariant& value); Q_INVOKABLE QVariant i8(int row) const; Q_INVOKABLE bool setI8(int row, const QVariant& value); + Q_INVOKABLE QVariant optionalBoolean(int row) const; + Q_INVOKABLE bool setOptionalBoolean(int row, const QVariant& value); Q_INVOKABLE QVariant optionalBytearray(int row) const; Q_INVOKABLE bool setOptionalBytearray(int row, const QVariant& value); Q_INVOKABLE QVariant optionalString(int row) const; diff --git a/tests/test_object_types.cpp b/tests/test_object_types.cpp index 682a6bb..8278f36 100644 --- a/tests/test_object_types.cpp +++ b/tests/test_object_types.cpp @@ -8,6 +8,7 @@ class TestRustObjectTypes : public QObject Q_OBJECT private slots: void testBool(); + void testOptionalBool(); void testInt8(); void testUint8(); void testInt16(); @@ -16,6 +17,7 @@ private slots: void testUint32(); void testInt64(); void testUint64(); + void testOptionalUint64(); void testFloat(); void testDouble(); void testString(); @@ -48,6 +50,16 @@ void TestRustObjectTypes::testBool() &Object::boolean, &Object::booleanChanged); } +void TestRustObjectTypes::testOptionalBool() +{ + testSetter(QVariant(), &Object::setOptionalBoolean, + &Object::optionalBoolean, &Object::optionalBooleanChanged); + testSetter(QVariant::fromValue(true), &Object::setOptionalBoolean, + &Object::optionalBoolean, &Object::optionalBooleanChanged); + testSetter(QVariant::fromValue(false), &Object::setOptionalBoolean, + &Object::optionalBoolean, &Object::optionalBooleanChanged); +} + void TestRustObjectTypes::testInt8() { testSetter(0, &Object::setI8, @@ -144,6 +156,22 @@ void TestRustObjectTypes::testUint64() &Object::u64, &Object::u64Changed); } +void TestRustObjectTypes::testOptionalUint64() +{ + testSetter(QVariant(), &Object::setOptionalU64, + &Object::optionalU64, &Object::optionalU64Changed); + testSetter(QVariant::fromValue(0), &Object::setOptionalU64, + &Object::optionalU64, &Object::optionalU64Changed); + testSetter(QVariant::fromValue(1), &Object::setOptionalU64, + &Object::optionalU64, &Object::optionalU64Changed); + testSetter(QVariant::fromValue(std::numeric_limits::min()), + &Object::setOptionalU64, &Object::optionalU64, + &Object::optionalU64Changed); + testSetter(QVariant::fromValue(std::numeric_limits::max()), + &Object::setOptionalU64, &Object::optionalU64, + &Object::optionalU64Changed); +} + void TestRustObjectTypes::testFloat() { testSetter(0, &Object::setF32, diff --git a/tests/test_object_types.json b/tests/test_object_types.json index 656d149..ebb368c 100644 --- a/tests/test_object_types.json +++ b/tests/test_object_types.json @@ -13,6 +13,11 @@ "type": "bool", "write": true }, + "optionalBoolean": { + "optional": true, + "type": "bool", + "write": true + }, "i8": { "type": "qint8", "write": true @@ -45,6 +50,11 @@ "type": "quint64", "write": true }, + "optionalU64": { + "optional": true, + "type": "quint64", + "write": true + }, "f32": { "type": "float", "write": true diff --git a/tests/test_object_types_rust.cpp b/tests/test_object_types_rust.cpp index 4544677..afee15d 100644 --- a/tests/test_object_types_rust.cpp +++ b/tests/test_object_types_rust.cpp @@ -3,6 +3,32 @@ namespace { + struct option_bool { + public: + bool value; + bool some; + operator QVariant() const { + if (some) { + return QVariant::fromValue(value); + } + return QVariant(); + } + }; + static_assert(std::is_pod::value, "option_bool must be a POD type."); + + struct option_quint64 { + public: + quint64 value; + bool some; + operator QVariant() const { + if (some) { + return QVariant::fromValue(value); + } + return QVariant(); + } + }; + static_assert(std::is_pod::value, "option_quint64 must be a POD type."); + typedef void (*qstring_set)(QString* val, const char* utf8, int nbytes); void set_qstring(QString* val, const char* utf8, int nbytes) { *val = QString::fromUtf8(utf8, nbytes); @@ -49,6 +75,10 @@ namespace { { emit o->i8Changed(); } + inline void objectOptionalBooleanChanged(Object* o) + { + emit o->optionalBooleanChanged(); + } inline void objectOptionalBytearrayChanged(Object* o) { emit o->optionalBytearrayChanged(); @@ -57,6 +87,10 @@ namespace { { emit o->optionalStringChanged(); } + inline void objectOptionalU64Changed(Object* o) + { + emit o->optionalU64Changed(); + } inline void objectStringChanged(Object* o) { emit o->stringChanged(); @@ -79,7 +113,7 @@ namespace { } } extern "C" { - Object::Private* object_new(Object*, void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*)); + Object::Private* object_new(Object*, void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*)); void object_free(Object::Private*); bool object_boolean_get(const Object::Private*); void object_boolean_set(Object::Private*, bool); @@ -97,12 +131,18 @@ extern "C" { void object_i64_set(Object::Private*, qint64); qint8 object_i8_get(const Object::Private*); void object_i8_set(Object::Private*, qint8); + option_bool object_optional_boolean_get(const Object::Private*); + void object_optional_boolean_set(Object::Private*, bool); + void object_optional_boolean_set_none(Object::Private*); void object_optional_bytearray_get(const Object::Private*, QByteArray*, qbytearray_set); void object_optional_bytearray_set(Object::Private*, const char* bytes, int len); void object_optional_bytearray_set_none(Object::Private*); void object_optional_string_get(const Object::Private*, QString*, qstring_set); void object_optional_string_set(Object::Private*, const ushort *str, int len); void object_optional_string_set_none(Object::Private*); + option_quint64 object_optional_u64_get(const Object::Private*); + void object_optional_u64_set(Object::Private*, quint64); + void object_optional_u64_set_none(Object::Private*); void object_string_get(const Object::Private*, QString*, qstring_set); void object_string_set(Object::Private*, const ushort *str, int len); quint16 object_u16_get(const Object::Private*); @@ -133,8 +173,10 @@ Object::Object(QObject *parent): objectI32Changed, objectI64Changed, objectI8Changed, + objectOptionalBooleanChanged, objectOptionalBytearrayChanged, objectOptionalStringChanged, + objectOptionalU64Changed, objectStringChanged, objectU16Changed, objectU32Changed, @@ -207,6 +249,22 @@ qint8 Object::i8() const void Object::setI8(qint8 v) { object_i8_set(m_d, v); } +QVariant Object::optionalBoolean() const +{ + QVariant v; + auto r = object_optional_boolean_get(m_d); + if (r.some) { + v.setValue(r.value); + } + return r; +} +void Object::setOptionalBoolean(const QVariant& v) { + if (v.isNull() || !v.canConvert()) { + object_optional_boolean_set_none(m_d); + } else { + object_optional_boolean_set(m_d, v.value()); + } +} QByteArray Object::optionalBytearray() const { QByteArray v; @@ -233,6 +291,22 @@ void Object::setOptionalString(const QString& v) { object_optional_string_set(m_d, reinterpret_cast(v.data()), v.size()); } } +QVariant Object::optionalU64() const +{ + QVariant v; + auto r = object_optional_u64_get(m_d); + if (r.some) { + v.setValue(r.value); + } + return r; +} +void Object::setOptionalU64(const QVariant& v) { + if (v.isNull() || !v.canConvert()) { + object_optional_u64_set_none(m_d); + } else { + object_optional_u64_set(m_d, v.value()); + } +} QString Object::string() const { QString v; diff --git a/tests/test_object_types_rust.h b/tests/test_object_types_rust.h index 18bf7c0..0dba40b 100644 --- a/tests/test_object_types_rust.h +++ b/tests/test_object_types_rust.h @@ -23,8 +23,10 @@ private: Q_PROPERTY(qint32 i32 READ i32 WRITE setI32 NOTIFY i32Changed FINAL) Q_PROPERTY(qint64 i64 READ i64 WRITE setI64 NOTIFY i64Changed FINAL) Q_PROPERTY(qint8 i8 READ i8 WRITE setI8 NOTIFY i8Changed FINAL) + Q_PROPERTY(QVariant optionalBoolean READ optionalBoolean WRITE setOptionalBoolean NOTIFY optionalBooleanChanged FINAL) Q_PROPERTY(QByteArray optionalBytearray READ optionalBytearray WRITE setOptionalBytearray NOTIFY optionalBytearrayChanged FINAL) Q_PROPERTY(QString optionalString READ optionalString WRITE setOptionalString NOTIFY optionalStringChanged FINAL) + Q_PROPERTY(QVariant optionalU64 READ optionalU64 WRITE setOptionalU64 NOTIFY optionalU64Changed FINAL) Q_PROPERTY(QString string READ string WRITE setString NOTIFY stringChanged FINAL) Q_PROPERTY(quint16 u16 READ u16 WRITE setU16 NOTIFY u16Changed FINAL) Q_PROPERTY(quint32 u32 READ u32 WRITE setU32 NOTIFY u32Changed FINAL) @@ -50,10 +52,14 @@ public: void setI64(qint64 v); qint8 i8() const; void setI8(qint8 v); + QVariant optionalBoolean() const; + void setOptionalBoolean(const QVariant& v); QByteArray optionalBytearray() const; void setOptionalBytearray(const QByteArray& v); QString optionalString() const; void setOptionalString(const QString& v); + QVariant optionalU64() const; + void setOptionalU64(const QVariant& v); QString string() const; void setString(const QString& v); quint16 u16() const; @@ -73,8 +79,10 @@ signals: void i32Changed(); void i64Changed(); void i8Changed(); + void optionalBooleanChanged(); void optionalBytearrayChanged(); void optionalStringChanged(); + void optionalU64Changed(); void stringChanged(); void u16Changed(); void u32Changed();