Open LeonMatthesKDAB opened 1 year ago
I also wonder with this if we have an existing C++ QObject if we should allow for tagging it to get the trait implemented on it ?
Eg if we have
unsafe extern "C++Qt" {
type MyQObject;
}
This won't have the QtObject
trait implemented on it, but instead we could use the same syntax as RustQt
to to do this
Eg
unsafe extern "C++Qt" {
#[qobject]
type MyQObject;
}
Hm, shouldn't all classes in "C++Qt"
be QObjects?
In that case we should just always implement the trait.
Though that brings up the question of whether all types within C++Qt are actually QObjects :thinking: Could they also be QGadgets? And would there be any use for it?
But maybe we should start requiring #[qobject]
on every type in "C++Qt" to make sure the behavior is the same in C++Qt as in RustQt.
Also another suggestion regarding naming, we could use AsX
here.
E.g. the trait could be named AsQObject
.
Q_GADGET
IIRC doesn't support Q_SIGNAL
but does support things like Q_PROPERTY
. As the only feature we effectively add with extern "C++Qt"
is signals then it could make sense to assume all are deriving from QObject
.
But I fear it's a slight inconsistency with extern "RustQt"
.
Maybe the #[qobject]
attribute ends up meaning
AsQObject
trait on this typeQ_OBJECT
macroQObject
unless there is a base_class
Note: We should potentially make use of Deref
as well to allow for upcasting to the base class.
Once https://doc.rust-lang.org/std/pin/struct.Pin.html#method.as_deref_mut is no longer nightly only, we could even use DerefMut
and upcast pointers easily that way.
Something along the lines of:
unsafe trait Inherits {
// note using an associated type only allows for single-inheritance!
type Base;
fn upcast_ptr(self: *mut Self) -> *mut Base;
fn upcast_mut(self: Pin<&mut Self>) -> Pin<&mut Base> {
// provided by the trait
}
}
// unsure whether this is possible, but would be awesome!
impl<T> Deref for T where T: Inherits {
type Target = <T as Inherits>::Base;
...
}
It would be nice if we could use From
and Into
traits. It will be consistent with how rust generally works.
Right, I was hoping we could even get away without explicit Into
calls by using Deref
, but we'll have to see how this pans out.
Rust is verbose and is one of its strong points. Automatic casting has caused problems for me in the past, which is why I would be against it. In my opinion, Rust's type inference powered object.into()
syntax gives the best of automatic casting and is clear when the cast actually happens.
We could move some of our "magic" methods into traits, which would make it a lot more obvious where they are coming from, and would allow us to e.g. "inherit" methods from QObject, reason about types, etc.
Then in C++, we could generate a generic cast to QObject, similar to how we do constructors.