Pre-implementation feedback for Qt with Rust

I fully agree here.

I think that focusing on Core, Gui and Widgets is the first thing to do (as you say, many of the other things there are already Rust versions of so it doesn't make much sense to try to bring them over unless its for a specific way to integrate with the rest of the Qt code)

Signals/Slots is (like I wrote in my first post) likely the most challenging part to get right. I think it will require a bunch of experimentation to find the right boundary as you pointed out.

In my project, methods overloading and default parameters are mapped to a method with a trait argument, and the trait is implemented on tuples of valid argument types. So if we have method(int x, float y = 0, double z = 0) in C++, in Rust we can call it as method(1i32), method((1i32, 1f32)) and method((1i32, 1f32, 1f64)). Double parentheses are a bit ugly, but it's very easy to use.

Take a look at qml-rust. While not a Qt wrapper (it's a rust wrapper to DOtherSide, a QML wrapper for C), it does support signals and slots. That might give you some ideas on how to achieve this.

Thanks! Will do

In my experience, any non-trivial Qt project quickly reaches the point where it needs subclassing. The usual reason is event handling -- mouse and keyboard events, for example, don't send signals, so if you want to handle mouse events directly you need a subclass.

The model/view framework also requires subclassing (if you want to create your own models or views).

You could probably handle a lot of these use cases with callbacks, though.

A couple relevant links regarding signals and slots:

Reimplementing moc as a Clang plugin

Verdigris, a header-only C++ library for near-zero-cost abstractions that were historically provided by moc

I strongly suspect that, by a combination of the two (and using macros 1.1 to implement a custom #[derive]), you could do something like this:

#[derive(QtMoc)]
trait Foo {
    #[slot] fn frob(&mut self, x: u32);
    #[signal] fn was_frobbed(&self) -> u32;
}

So for example, you could have the #[derive] generate a const trait method (corresponding to the constexpr function in Verdigris for the same purpose) that generates the QMetaObject.

As this actually is a good example of using Macros 1.1 in a way that would need to add items within the item being modified, I hope you don't mind if I link to this from the relevant ticket on the Rust repo.

(Also, if done this way, supertraits could possibly take on some of the roles Qt uses inheritance for? Unsure.)

That is a a pretty cool idea indeed!

Also unsure about inheritance. I hope it's possible to make most things in Qt without the inheritance (and rely more on slots/signals + composition to have custom types but I'm not sure if it would work in practice.)

Oh no! I was actually already working on a Qt binding sometime during summer.

I got singals & slots partially working via lambdas - it's possible in my code to connect existing signals to lambdas, but not define own signals, but that should also be possible the same way QML does it.
I got subclassing basically working as well via trait objects.
I also had some preliminary support for function overloadign too, via tuples+traits.

I generated the binding dynamically from Qt Doc metadata.

Cool. Maybe you have so idea on the work going on over here then :slight_smile: https://github.com/rust-qt/cpp_to_rust I'm sure that @Riateche would like the input as well :slight_smile:

They seem to be much farther along, although they might benefit from my subclassing imeplemetation. I'll have a look...

Inheritance is really necessary in Qt. You just can't do certain things without it. I've got a plan for it too, though.

I don't like the idea of messing with moc. I think I can make all signal/slot magic work on C++ side where moc is working in a regular fashion. Something like generating a QObject subclass with signals and slots of every possible argument types and allowing to inherit that type in Rust. I'll sum it up in the issue tracker soon.

I've just got from the nightmare of making the project work on MSVC. I wasn't expecting to have so much trouble, but now it seems to work at last. I'll set up Appveyor and then I'll be able to move on to more pleasant things.

Parsing Qt Doc metadata... I was on that road early in my project. But it turns out Qt doc is not as good as it seems. It has a lot of inaccuracy and it lacks some crucial information, such as template arguments.

1 Like

If we could avoid using Moc (but still have similar functionality) I'm all for that.

That's pretty much what I've done. You want to see the code?

I made a simple example of using rustcxx and Qt's QML that supports signals and slots:

Yes, it will be interesting to see the code. I think I will review all existing implementations and try to get the best from each of them.

1 Like

I've written my plans about signals and slots here:

https://github.com/rust-qt/cpp_to_rust/issues/7#issuecomment-249437950

Noticed! Going to read in details. Thanks!

My daily job is actually working with Qt(components like a CacheManager) and on Qt(the code itself - we deliver it to other projects) - so I might be able to help here.
I will look in the weekend on all the mentioned implementations and maybe give some feedback.
moc is not that awful(and for signal/slots you basically need to implement moc for Rust), you could get some inspiration from it or from Verdigris(same developer).

One way to make it easier would be to "start" the Rust code from within Qt because of the Event Loop(QCoreApplication and in general every QThread has its own Event Loop, without it you can't have signal/slots).

To be sincere though, the only thing I am interested from Qt is QML. The rest is available in the Rust ecosystem(maybe not all, although I cannot think of the top of my head what is missing except for the GUI stuff, Qt Service Framework and the State Machine Framework). The nice thing with Rust though is that the dependencies are A Lot smaller. Although, Qt now can get a little bit smaller too.

For perspective, I'd like to provide a counterpoint to your QML comment.

There are two things I'm interested in when I look at ways to use Rust with Qt:

  1. Offloading as much of my "risk burnout by writing automated tests" to Rust's type system as possible. (The C++ API is more valuable to me than QML on this front)

  2. Making portable GUIs that fit into my desktop as natively as possible. (Last I checked, QML's support for native widgets was still too immature to be acceptable)

Because the latter is non-negotiable and the former isn't very negotiable either, I've been sticking with PyQt for my GUI applications since it wraps the C++ side of the APIs while still giving me "abort the signal handler with a traceback and let the event loop keep spinning instead of segfaulting" behaviour as the best available runner-up to a good, solid Rust API.

Qt is one of the best libraries for GUI. Rust needs a good GUI library, and it doesn't look like someone is going to write a Rust library as good as Qt any time soon. So there is no choice but to wrap Qt. Some parts of Qt are not all that interesting, like QtNetwork. But they are convenient because they integrate with Qt's types, event loop, etc. So I'm going to wrap all of them.

There is already a QML wrapper for Rust. But I don't see how QML can replace other parts of Qt.