
Todo example in Rust - Ygg2
https://www.vandenoever.info/blog/2018/06/09/to-do-a-rust-gui.html
======
spystath
I've read about this project in the past and although it definitely is
interesting it's still a bit unclear to me if this is a way to use Qt through
Rust or the other way around. Reading through this example it seems like you
use QML to structure you UI which is straightforward enough but there are a
couple of qml crates which do pretty much the same thing without including an
extra binding generation step (or C++ at all).

Searching through the repo [0,1] it seems like you still need to write a
certain amount of C++ especially if you're using QtWidgets instead of QML. So
in my eyes this seems like a way to incorporate Rust code into a Qt project
rather than build a Qt interface for use in Rust, as the end program is
essentially a C++ program with some Rust bits.

From what I understand if you have a fair amount of existing Rust code to
reuse in a Qt GUI application this is probably the best way to get them to
talk together but it's a still a bit far from "Qt GUI for your Rust programs".
I get that the distinction between the two is a bit blurry but in any case you
still need to write a considerable amount of C++ especially if you opt for the
QtWidgets way.

Of course it is entirely possible that I've completely missed the point so in
that case please correct me.

[0] [https://github.com/KDE/rust-qt-binding-
generator/tree/master...](https://github.com/KDE/rust-qt-binding-
generator/tree/master/templates)

[1] [https://github.com/KDE/rust-qt-binding-
generator/tree/master...](https://github.com/KDE/rust-qt-binding-
generator/tree/master/examples)

~~~
oever
Rust Qt Binding Generator is for projects that contain Rust and QML or Rust
and Qt widgets. The GUI code will be in the native language for Qt: C++ or
QML. The data model underneath and any non-UI parts can be written in Rust.

This approach was chosen because it's hard to wrap Qt Widgets (let alone QML)
safely in a Rust API. Generating binding code is a very pragmatic approach
that works now. You do not need external libraries, just generate some code,
include it in your project and use qmake/cmake/... and cargo together.

I've explained this approach in a presentation at FOSDEM [0].

That being said, there might well come a better solution that manages to wrap
Qt and the mechanisms of deriving from Qt model classes in a Rust API. It may
even manage to require only Cargo as a build tool. In fact, only yesterday
Olivier Goffart presented a prototype that does just that. [1] And that
project has the exact same to-do application in its examples with only Rust
and QML (no JSON or C++).

Switching between those approaches should be very simple though. Especially
since Rust has static typing which makes refactoring a breeze.

[0]
[https://fosdem.org/2018/schedule/event/rust_qt_binding_gener...](https://fosdem.org/2018/schedule/event/rust_qt_binding_generator/)
[1] [https://woboq.com/blog/qmetaobject-from-
rust.html](https://woboq.com/blog/qmetaobject-from-rust.html)

~~~
ufo
What makes Qt hard to bind? Is it just because it is a large C++ project or is
there something particularly hard about Qt?

~~~
oever
There are quite some challenges. Qt, like most C++ programs can exhibit
undefined behavior. In Rust, no code is allowed to have undefined behavior
[0]. For safe functions, the compiler checks this. For unsafe functions, the
function documentation should state how to call the function to avoid
undefined behavior.

Qt is enormous. There are projects that generate bindings automatically. But
to know what is safe, you'd have to read the API docs and write the binding by
hand. Some parts of Qt might never be safe. For example, loading QML with
QQmlApplicationEngine::loadData is not safe because it runs possibly unsafe
QML code. So a binding to QQmlApplicationEngine::loadData should be marked
unsafe and its documentations should state: 'only load safe QML'.

Most current FFI examples in Rust go via C bindings. There's not a lot of work
on wrapping C++ libraries yet (that I'm aware of). C++ is vastly more complex
than C. So ensuring safety is harder.

In most Qt projects, there will be places in the code where you have to derive
from a Qt class. So the binding should have a way to do that.

The Qt ownership models is hierarchical. If an object has a parent, it will be
freed when the parent is freed. A Rust binding should translate that behavior
in a safe API.

Signals and slots in Qt are tricky to wrap in a safe API too.

In short, wrapping Qt in a Rust API is a humongous task. Rust Qt Binding
Generator takes a pragmatic approach and lets you combine Qt and Rust in one
project. It does so by generating a binding around your data model instead of
around the entire Qt API.

[0] [https://doc.rust-lang.org/reference/behavior-considered-
unde...](https://doc.rust-lang.org/reference/behavior-considered-
undefined.html)

------
jcelerier
note that a TodoMVC-like example can be reached in less than 150 lines of pure
QML : [https://github.com/jcelerier/TodoMVC-
QML/blob/master/Main.qm...](https://github.com/jcelerier/TodoMVC-
QML/blob/master/Main.qml)

~~~
oever
Nice! QML is really great for these things.

Author of the blog post here. I've started out the code in the post with a
pure QML version of course and then replaced the model with a Rust model since
the point of the blog is to show how to write the model in Rust.

I like your solution of using a DelegateModel to show All, Completed or Active
items. I went for a different approach:

    
    
            RowLayout {
                property bool show: filter.currentIndex === 0
    	                || (filter.currentIndex === 1 && !completed)
    	                || (filter.currentIndex === 2 && completed)
    	    visible: show

~~~
jcelerier
cool :)

Are you aware of Olivier Goffart's take on QML in Rust ?
[https://woboq.com/blog/qmetaobject-from-
rust.html](https://woboq.com/blog/qmetaobject-from-rust.html) ; it seems that
it could maybe be used instead of the custome code-gen you did.

That's a great time for Qt and Rust, no doubt :p

~~~
oever
Yes, I proofread his blog post and tested the code. :-)

Olivier's approach is very clever. Especially the method of extending Qt
classes.

------
desi_ninja
Looks like a good starter Rust project. I am learning Rust and every bit of
such blog helps. Just curious to see a .. syntax here: (row..row + count).
What does it mean?

~~~
steamer25
Dot dot is range notation: [https://doc.rust-lang.org/rust-by-
example/flow_control/for.h...](https://doc.rust-lang.org/rust-by-
example/flow_control/for.html)

Here's the reference for the drain() method on vectors which takes the range
argument: [https://doc.rust-lang.org/rust-by-
example/flow_control/for.h...](https://doc.rust-lang.org/rust-by-
example/flow_control/for.html)

Altogether, it sounds like (I haven't read the whole thing) it's supposed to
drain from the current row until the end, including every row in between.

~~~
oconnor663
A simpler example might be slicing a list:

    
    
        let strings = ["foo", "bar", "baz"];
        let slice = &strings[0..2];
        // prints "foo" and "bar"
        for s in slice {
            println!("{}", s);
        }
    

Or looping over numbers:

    
    
        // prints 0, 1, 2, 3, and 4
        for i in 0..5 {
            println!("{}", i);
        }

------
abrowne
I lack the knowledge to judge this on a technical level, although what do I
know about Rust and Qt/KDE make me excited. But I can definitely say that's a
great logo!

~~~
batisteo
Can somebody tell Alessandro Longo to at least take the official Rust logo.
The R is off.

