Discussion:
KDE Review: Rust Qt Binding Generator
Jos van den Oever
2017-09-03 16:14:49 UTC
Permalink
Dear KDE-ers,

A new project is up for review: Rust Qt Binding Generator.

The project is a command-line executable that creates Rust code and Qt code
from a binding description in JSON.

The code is currently at kde:scratch/vandenoever/rust_qt_binding_generator

If you want to use Rust code in your Qt project or if you would like to add a
Qt UI on your Rust code, this program will help you.

The binding can describe a Objects, Lists and Trees. Objects generate C
++ derived from QObject. Lists and Trees generate C++ classes derived from
QAbstractItemModel. On the Rust side, a trait is created. This trait is the
interface that the developer needs to fill with code.

The project comes with a demo application that shows Rust code powering a Qt
widgets project, a Qt Quick Controls project and a Qt Quick Controls 2
project. It shows a list, file system tree, a system process view and a chart.

That demo with the code for it is easiest way to appreciate what you can do
with rust_qt_binding_generator.

The idea of this binding generator is that you write each part in the most
appropriate language. Rust bindings for Qt are hard to get right and will
still have caveats for a while. With this generator, you write the UI in C++
or QML. The generated code has no dependencies apart from Qt Core and the Rust
crate libc.

A simple example: Hello World.

```json
{
"cppFile": "src/greeting.cpp",
"rust": {
"dir": "rust",
"interfaceModule": "interface",
"implementationModule": "implementation"
},
"objects": {
"Greeting": {
"type": "Object",
"properties": {
"message": {
"type": "QString"
}
}
}
}
}
```

Preparation: create a new CMake project with a Rust project in the folder
'rust'.

```
kwrite CMakeLists.txt
kwrite bindings.json
mkdir rust
(cd rust && cargo init --name rust --lib)
```

Create bindings with this command:

```bash
rust_qt_binding_generator binding.json
```

Add the files to the main Rust library module, `rust/src/lib.rs`

```rust
extern crate libc;

pub mod interface;
mod implementation;
```

And modify tell Cargo to build a static library in `rust/Cargo.tom`:

```
[package]
name = "rust"
version = "1.0.0"

[dependencies]
libc = "*"

[lib]
name = "rust"
crate-type = ["staticlib"]
```

Next step: put your code in rust/src/implementation.rs:

```rust
use interface::*;

pub struct Greeting {
emit: GreetingEmitter,
}

impl GreetingTrait for Greeting {
fn create(emit: GreetingEmitter) -> Greeting {
Greeting {
emit: emit,
}
}
fn emit(&self) -> &GreetingEmitter {
&self.emit
}
fn message(&self) -> &str {
"Hello world!"
}
}

```

The GreetingEmitter is generated struct that can emit signals such as
valueChanged(). It is not needed in this simple example, but the interface
requires it. You might have new values coming in of which you'd need to notify
the UI.

The demo has more advanced examples. List and Tree let you implement
QAbstractItemModel with Rust code but the API is quite different.

There is no QAbstractItemModel::data and QAbstractItemModel::setData to
implement. Instead, you define properties for each list or tree item and have
to implement functions like

```rust
fn name(row: usize) -> &str {
if row == 0 {
return "Alice";
}
"Bob"
}
```

This project is not a typical C++ KDE project, but I hope it can be part of
KDE anyway.

Best regards,
Jos
Kevin Ottens
2017-09-04 05:46:28 UTC
Permalink
Hello,
Post by Jos van den Oever
[...]
The idea of this binding generator is that you write each part in the most
appropriate language. Rust bindings for Qt are hard to get right and will
still have caveats for a while. With this generator, you write the UI in C++
or QML. The generated code has no dependencies apart from Qt Core and the
Rust crate libc.
So what's the intent with this one? Is it a stop gap measure until cpp_to_rust
is more complete?
https://github.com/rust-qt/cpp_to_rust

Are you contributing to it as well? (I started patching it locally but still
need to clean up my work for upstream contribution)
Post by Jos van den Oever
[...]
This project is not a typical C++ KDE project, but I hope it can be part of
KDE anyway.
Of course take the above more as curiosity and wondering how that will fit
regarding the larger Rust ecosystem. I don't see a problem with things like
this to be part of KDE.

Regards.
--
Kévin Ottens, http://ervin.ipsquad.net

KDAB - proud supporter of KDE, http://www.kdab.com
Jos van den Oever
2017-09-04 07:43:46 UTC
Permalink
Post by Kevin Ottens
Post by Jos van den Oever
[...]
The idea of this binding generator is that you write each part in the most
appropriate language. Rust bindings for Qt are hard to get right and will
still have caveats for a while. With this generator, you write the UI in
C++ or QML. The generated code has no dependencies apart from Qt Core and
the Rust crate libc.
So what's the intent with this one? Is it a stop gap measure until
cpp_to_rust is more complete?
https://github.com/rust-qt/cpp_to_rust
cpp_to_rust is an ambitious project. cpp_to_rust lets you call Qt libraries
from a Rust project. This means that the qt_core, qt_gui etc crates have to
take care of thread-safety and ownership. Qt has quite a few ways of dealing
with ownership. A QObject is responsible for destroying and deallocating its
children. QString is value type with a reference-counted memory block inside.

I spent time on another binding project and sent patches to it, but it was not
active anymore. Then I realized that it is early for depending on a project
that tries to wrap Qt as a Rust crate.

If you'd like to use Rust in an existing KDE project, you'd not take that
approach either. You'd call new Rust code from your Qt code. cpp_to_rust
focusses the other way around.

The interesting part of writing Qt code is custom implementations of QObject
and QAbstractItemModel that you pass to Qt elements. QComboBox, QTableView,
QListView all take QAbstractItemModel implementations.

So the binding generator, which I'm fine to call a stop gap measure, focusses
on that part. You implement QObject and QAIM with Rust code that does not feel
like Qt, but feels like Rust code.

For example, here is an implementation of a QAbstractItemModel that is used as
model in QtChart and (Q)TableView in the demo. It does not look like a QAIM at
all.

https://cgit.kde.org/scratch/vandenoever/rust_qt_binding_generator.git/tree/
demo/rust/src/implementation/time_series.rs

Of course, it's a bit simple, because it's static data.

When cpp_to_rust has a stable release and is easy to use from exisiting C++/
CMake projects, this project can be ported to use that. The code that
generates Qt implementations could then be a Rust macro.
Post by Kevin Ottens
Are you contributing to it as well? (I started patching it locally but still
need to clean up my work for upstream contribution)
No, I contributed to a previous binding project. cpp_to_rust is an attractive
idea because it allows you to code only in Rust. Enticing as the idea is, I
wanted something that works now. In addition, I like the idea of separating UI
and logic.
Post by Kevin Ottens
Post by Jos van den Oever
[...]
This project is not a typical C++ KDE project, but I hope it can be part of
KDE anyway.
Of course take the above more as curiosity and wondering how that will fit
regarding the larger Rust ecosystem. I don't see a problem with things like
this to be part of KDE.
Cool. Thanks for taking a look.

Cheers,
Jos
Kevin Ottens
2017-09-04 09:42:59 UTC
Permalink
Hello,
Post by Jos van den Oever
Post by Kevin Ottens
Post by Jos van den Oever
[...]
The idea of this binding generator is that you write each part in the
most appropriate language. Rust bindings for Qt are hard to get right
and will still have caveats for a while. With this generator, you write
the UI in C++ or QML. The generated code has no dependencies apart from
Qt Core and the Rust crate libc.
So what's the intent with this one? Is it a stop gap measure until
cpp_to_rust is more complete?
https://github.com/rust-qt/cpp_to_rust
cpp_to_rust is an ambitious project. cpp_to_rust lets you call Qt libraries
from a Rust project. This means that the qt_core, qt_gui etc crates have to
take care of thread-safety and ownership. Qt has quite a few ways of dealing
with ownership. A QObject is responsible for destroying and deallocating
its children. QString is value type with a reference-counted memory block
inside.
I spent time on another binding project and sent patches to it, but it was
not active anymore. Then I realized that it is early for depending on a
project that tries to wrap Qt as a Rust crate.
If you'd like to use Rust in an existing KDE project, you'd not take that
approach either. You'd call new Rust code from your Qt code. cpp_to_rust
focusses the other way around.
The interesting part of writing Qt code is custom implementations of QObject
and QAbstractItemModel that you pass to Qt elements. QComboBox, QTableView,
QListView all take QAbstractItemModel implementations.
So the binding generator, which I'm fine to call a stop gap measure,
Note that I didn't mean that to diminish your work, I was really wondering if
your intent was to see your binding generator as something temporary or
something with longer term plans.

Looks like it's longer term which sounds good.
Post by Jos van den Oever
focusses on that part. You implement QObject and QAIM with Rust code that
does not feel like Qt, but feels like Rust code.
For example, here is an implementation of a QAbstractItemModel that is used
as model in QtChart and (Q)TableView in the demo. It does not look like a
QAIM at all.
https://cgit.kde.org/scratch/vandenoever/rust_qt_binding_generator.git/tree/
demo/rust/src/implementation/time_series.rs
Of course, it's a bit simple, because it's static data.
When cpp_to_rust has a stable release and is easy to use from exisiting C++/
CMake projects, this project can be ported to use that. The code that
generates Qt implementations could then be a Rust macro.
Thanks a lot for the extra insights. Makes sense.
Post by Jos van den Oever
Post by Kevin Ottens
Are you contributing to it as well? (I started patching it locally but
still need to clean up my work for upstream contribution)
No, I contributed to a previous binding project. cpp_to_rust is an
attractive idea because it allows you to code only in Rust. Enticing as the
idea is, I wanted something that works now. In addition, I like the idea of
separating UI and logic.
Sure, it always make sense to separate them, I don't perceive this as an
argument for different languages though.
Post by Jos van den Oever
Post by Kevin Ottens
Post by Jos van den Oever
[...]
This project is not a typical C++ KDE project, but I hope it can be part
of KDE anyway.
Of course take the above more as curiosity and wondering how that will fit
regarding the larger Rust ecosystem. I don't see a problem with things
like this to be part of KDE.
Cool. Thanks for taking a look.
Interesting stuff anyway, looking forward to it having stable releases. :-)

Regards.
--
Kévin Ottens, http://ervin.ipsquad.net

KDAB - proud supporter of KDE, http://www.kdab.com
Jos van den Oever
2017-09-04 20:24:41 UTC
Permalink
Post by Kevin Ottens
Are you contributing to it as well? (I started patching it locally but still
need to clean up my work for upstream contribution)
I wrote a small Hello World application just now, but it's quite hard. The
most important things needed to write useful Qt software, inheritance and
signals/slots, are not working yet. Or I'm doing it totally wrong somehow.

https://github.com/rust-qt/cpp_to_rust/issues/57

It would be awesome to call Qt from Rust, but that's a lot of complicated
bindings that make your executable very large. The approach I'm taking is to
instead create a small amount of bindings specific for your project which have
a nice Qt side and a nice Rust side.

Cheers,
Jos
Jos van den Oever
2017-09-05 17:03:13 UTC
Permalink
Since today, the project has a top level git repo:

https://cgit.kde.org/rust-qt-binding-generator.git/
https://phabricator.kde.org/source/rust-qt-binding-generator/ (with logo!)

To celebrate, I added (shoddy) Kirigami qmls to the demo application. [1]
They're slight modifications of the QQC2 QML files that were already there.
Ideas for making that more worthy of Kirigami are welcome.

So, the project can now accept patches via https://phabricator.kde.org/
differential/

Cheers,
Jos

[1] https://cgit.kde.org/rust-qt-binding-generator.git/commit/?
id=ddab2e57f65534a0c9766914fb85a90bfe1d24cc
Post by Jos van den Oever
Dear KDE-ers,
A new project is up for review: Rust Qt Binding Generator.
The project is a command-line executable that creates Rust code and Qt code
from a binding description in JSON.
The code is currently at kde:scratch/vandenoever/rust_qt_binding_generator
If you want to use Rust code in your Qt project or if you would like to add
a Qt UI on your Rust code, this program will help you.
The binding can describe a Objects, Lists and Trees. Objects generate C
++ derived from QObject. Lists and Trees generate C++ classes derived from
QAbstractItemModel. On the Rust side, a trait is created. This trait is the
interface that the developer needs to fill with code.
The project comes with a demo application that shows Rust code powering a Qt
widgets project, a Qt Quick Controls project and a Qt Quick Controls 2
project. It shows a list, file system tree, a system process view and a chart.
That demo with the code for it is easiest way to appreciate what you can do
with rust_qt_binding_generator.
The idea of this binding generator is that you write each part in the most
appropriate language. Rust bindings for Qt are hard to get right and will
still have caveats for a while. With this generator, you write the UI in C++
or QML. The generated code has no dependencies apart from Qt Core and the
Rust crate libc.
A simple example: Hello World.
```json
{
"cppFile": "src/greeting.cpp",
"rust": {
"dir": "rust",
"interfaceModule": "interface",
"implementationModule": "implementation"
},
"objects": {
"Greeting": {
"type": "Object",
"properties": {
"message": {
"type": "QString"
}
}
}
}
}
```
Preparation: create a new CMake project with a Rust project in the folder
'rust'.
```
kwrite CMakeLists.txt
kwrite bindings.json
mkdir rust
(cd rust && cargo init --name rust --lib)
```
```bash
rust_qt_binding_generator binding.json
```
Add the files to the main Rust library module, `rust/src/lib.rs`
```rust
extern crate libc;
pub mod interface;
mod implementation;
```
```
[package]
name = "rust"
version = "1.0.0"
[dependencies]
libc = "*"
[lib]
name = "rust"
crate-type = ["staticlib"]
```
```rust
use interface::*;
pub struct Greeting {
emit: GreetingEmitter,
}
impl GreetingTrait for Greeting {
fn create(emit: GreetingEmitter) -> Greeting {
Greeting {
emit: emit,
}
}
fn emit(&self) -> &GreetingEmitter {
&self.emit
}
fn message(&self) -> &str {
"Hello world!"
}
}
```
The GreetingEmitter is generated struct that can emit signals such as
valueChanged(). It is not needed in this simple example, but the interface
requires it. You might have new values coming in of which you'd need to
notify the UI.
The demo has more advanced examples. List and Tree let you implement
QAbstractItemModel with Rust code but the API is quite different.
There is no QAbstractItemModel::data and QAbstractItemModel::setData to
implement. Instead, you define properties for each list or tree item and
have to implement functions like
```rust
fn name(row: usize) -> &str {
if row == 0 {
return "Alice";
}
"Bob"
}
```
This project is not a typical C++ KDE project, but I hope it can be part of
KDE anyway.
Best regards,
Jos
Friedrich W. H. Kossebau
2017-12-21 15:17:02 UTC
Permalink
Post by Jos van den Oever
Dear KDE-ers,
A new project is up for review: Rust Qt Binding Generator.
The project is a command-line executable that creates Rust code and Qt code
from a binding description in JSON.
The code is currently at kde:scratch/vandenoever/rust_qt_binding_generator
If you want to use Rust code in your Qt project or if you would like to add
a Qt UI on your Rust code, this program will help you.
The binding can describe a Objects, Lists and Trees. Objects generate C
++ derived from QObject. Lists and Trees generate C++ classes derived from
QAbstractItemModel. On the Rust side, a trait is created. This trait is the
interface that the developer needs to fill with code.
The project comes with a demo application that shows Rust code powering a Qt
widgets project, a Qt Quick Controls project and a Qt Quick Controls 2
project. It shows a list, file system tree, a system process view and a chart.
That demo with the code for it is easiest way to appreciate what you can do
with rust_qt_binding_generator.
The idea of this binding generator is that you write each part in the most
appropriate language. Rust bindings for Qt are hard to get right and will
still have caveats for a while. With this generator, you write the UI in C++
or QML. The generated code has no dependencies apart from Qt Core and the
Rust crate libc.
A simple example: Hello World.
```json
{
"cppFile": "src/greeting.cpp",
"rust": {
"dir": "rust",
"interfaceModule": "interface",
"implementationModule": "implementation"
},
"objects": {
"Greeting": {
"type": "Object",
"properties": {
"message": {
"type": "QString"
}
}
}
}
}
```
Preparation: create a new CMake project with a Rust project in the folder
'rust'.
```
kwrite CMakeLists.txt
kwrite bindings.json
mkdir rust
(cd rust && cargo init --name rust --lib)
```
```bash
rust_qt_binding_generator binding.json
```
Add the files to the main Rust library module, `rust/src/lib.rs`
```rust
extern crate libc;
pub mod interface;
mod implementation;
```
```
[package]
name = "rust"
version = "1.0.0"
[dependencies]
libc = "*"
[lib]
name = "rust"
crate-type = ["staticlib"]
```
```rust
use interface::*;
pub struct Greeting {
emit: GreetingEmitter,
}
impl GreetingTrait for Greeting {
fn create(emit: GreetingEmitter) -> Greeting {
Greeting {
emit: emit,
}
}
fn emit(&self) -> &GreetingEmitter {
&self.emit
}
fn message(&self) -> &str {
"Hello world!"
}
}
```
The GreetingEmitter is generated struct that can emit signals such as
valueChanged(). It is not needed in this simple example, but the interface
requires it. You might have new values coming in of which you'd need to
notify the UI.
The demo has more advanced examples. List and Tree let you implement
QAbstractItemModel with Rust code but the API is quite different.
There is no QAbstractItemModel::data and QAbstractItemModel::setData to
implement. Instead, you define properties for each list or tree item and
have to implement functions like
```rust
fn name(row: usize) -> &str {
if row == 0 {
return "Alice";
}
"Bob"
}
```
This project is not a typical C++ KDE project, but I hope it can be part of
KDE anyway.
3 months passed and this is still in kdereview. Time to move it on or bounce
it back, to playground or even outside of KDE spheres.

I would like us to accept it though, extragear/sdk seems the best fit.

Before though this should be addressed at least:
https://phabricator.kde.org/D9357 (Some fixes for CMakeLists.txt)
https://phabricator.kde.org/D9458 (Fix i18n message catalog naming, add
catalog for generator app)

One could also argue about the name of the generator binary,
"rust_qt_binding_generator" is quite verbose. Perhaps "rqtbindgen",
"rustqtbindgen" or similar would be following existing naming (cmp. e.g.
"cbindgen" Rust crate for similar purpose).

Cheers
Friedrich

Loading...