Store properties on the Rust side of the bridge #145
-
Aims
Possible Codestruct RustObj {
prop: Property<T>, // exposed as a Q_PROPERTY with READ, WRITE, NOTIFY
// has no constant_mut()
#[constant]
constant: Property<T>, // exposed as a Q_PROPERTY with READ, CONSTANT
#[qt-readonly]
readonly: Property<T>, // exposed as a Q_PROPERTY with READ, NOTIFY
// TODO: how do we handle nested objects now?
// we need to hold a pointer to the C++ obj, as we "own" it?
//
// MaybeUniquePtr allows for having a raw pointer that comes from QML engine
// this then means that the Rust side can't "take" this. But also has a UniquePtr
// which allows you to make objects on Rust
//
// Likely something from a future
nested: Property<MaybeUniquePtr<crate::module::NestedObjectCppObj>>,
// this would be "unsafe" but allows usage from QML
nested: Property<mut *crate::module::NestedObjectCppObj>,
#[qt-readonly] // const * const
// can QML take references? as then we could remove readonly
nested_readonly: Property<UniquePtr<something>>,
// Private Rust code, not exposed to Qt
state: PrivateObj,
}
impl RustObj {
#[invokable]
fn add(self: Pin<&mut Self>) { // note we need to use Pin here to prevent memory being swapped
let number = 1 + self.prop(); // Pin<&T>
self.set_prop(value); // (T)
// PropertyMut<T> (Pin of property, Pin self, drop trigger notify)
// deref to &mut T ... as we will trigger notify on drop
self.prop_mut().x = anothervalue;
*self.number_mut() /* &mut i32 */ = 1;
// we can use the PrivateObj like normal
self.state.private_method();
self.my_thing();
}
} Later discussions resulted in the secondary API of attributes rather than types. This route means that due to the Pin you never get &mut self so that you always need to go through the prop/set_prop/prop_mut. struct MyObject {
#[property(qt-readonly)]
prop: T
}
// generated by CXX-Qt:
impl MyObject {
fn prop(self: Pin<&self>) -> &T;
fn set_prop(self: Pin<&mut self>, value: T);
fn prop_mut<'a>(self: Pin<&'a mut self>) -> Property<T, 'a>;
} There are also discussions around how to handle nested objects. // Nested objects where you have pointers, might have segfaults when moving objects
// instead in rust do our own connections of the pointers with Arc.
// So then listen to the changes on the setter and then unsafe code to find the pointer
// to the database and then use the Arc so we have our own "safe" pointer that won't break
Database {
// database pool
}
Model {
database: database
}
Model {
database: database
}
Cat {
id: cat
friend: Cat {
}
}
Dog {
id: dog
friend: cat
} Problems
|
Beta Was this translation helpful? Give feedback.
Replies: 3 comments
-
A bit of explanation: Ideally we want to have everything in Rust, so that it's easier to interact with, and we don't have to define two separate structs. For this reason, we think we may only accept |
Beta Was this translation helpful? Give feedback.
-
Can we create handlers for change events in a sane way on the Rust side ? self.prop_connect(|pointer| {
// when prop changes
}); We need to make sure that self can't move into the closure, that it takes the fat pointer as an argument, and trigger where the changed signal is fired. Would we have one for each property ? or would there be a more generic solution for signals as well ? Note that doing this direct connection being called from the setter might have issues as it's not a queued event, a generic solution that listens for signal changes might be preferred. |
Beta Was this translation helpful? Give feedback.
-
Also see: #156 |
Beta Was this translation helpful? Give feedback.
Also see: #156