 We've got Jos van der Oever, who's going to talk about Rust with QT. Please give him a really warm welcome. Well, thank you very much. I'm happy to finally have made it into this room. It turned out you have to be a speaker and then it's easy to get in. So, I assume that most people here are firstly Rust developers, and maybe secondly also there's some cute guys here. So, who is a cute developer here? Just to, oh great, quite a few. Yeah. So, some of the stuff will look more familiar to you than most of the other stuff. So, yeah, for the people who don't know Qt so much, I've also added some code examples there. Since there are not so many cute developers, I think also this image here, who has ever seen this image before? Two people, yeah, I guess three even, right. So, this is like a logo which was on the top of the documentation of Qt 1 there about. So, it's like somewhere in the 90s. But considering that combining Rust and Qt is not so easy, I thought this sort of man looking a bit distraught would be a good opening image for this talk. But the good news is it's actually totally feasible to combine those two things and the Rust Qt binding generator will help you with that. To start us off, well, a takeaway. I think this talk would be good for Rust developers, for Qt developers, for people developing Qt because I think they can learn a lot from the Rust language. But also people who are interested in writing a native Rust UI, learning from what Qt has done over the past 20 years could also be very insightful. So, for them, I hope this talk is also one that has some nice messages. So, here are three applications. This is a tiny one that I blogged a while back and which was also on the Rust reddit. As a tutorial, this is basically a QML application. I'll explain later what QML is that is powered by Rust. And all that Rust does here is it has a thread and it gives some seconds every second there's an event and then this Rust logo rotates. The Rust Qt binding generator repository has a demo application which showcases all the different styles of widgets you have in Qt. So, this is just a different styling, but you can also use Qt Quick, which is a type of widget that is very much optimized for your graphics processor. And we also have Qt Quick controls too, which is more in line with what you see on mobile devices. And all of these things are bundled into one application here, but later on in this talk we'll mostly be talking about this demo application we're going to walk through how to write code like this to power a to-do application with Rust and Qt. So, back to the slides. The goal of this project was to find a way to write programs that combine Qt to Rust. But since I was doing it in the summer as a hobby, it should be a small effort to create this tool. But when it's finished, it should also be a small effort to actually use it. It should be easy to combine these two languages, even though C++ and Rust are so very different. It should be simple with minimal dependencies. And this is very important to me. The end result should be that you write good Qt code and good Rust code and not Rust with ugly Qt or Qt with ugly Rust. So, what is Qt and where is it used? These are logos from some of the projects that are using Qt. Here's one that Linda Storwald helps coding. If you'll see, you all know. The KDE community is basically built on Qt. The Plasma desktop uses Qt. You can write 3D applications with Qt. And there you have a sort of state machine to steer everything. So it's a very rich, very large set of libraries to write your user interface in. And therefore, it would be great if you could use it with Rust. Also in the embedded world, Qt is used a lot. Here's a picture from a promo video. And you see that they're pointing the Qt logo to lots of parts of the car. Not exactly sure what they mean by that, but I think the overall message is we have some low-power processors and display on it and we power it with Qt. So you can also put it on your fridge or on your thermostat, whatever. There are tons of bindings already for Qt, lots of different languages. And yeah, why do you normally have bindings? You want to use languages which is more familiar to you. Qt itself is written in C++. And maybe you're more familiar with one of the languages on top here. Or you have a large project. And maybe all the guys from the lots of logos before, those are existing projects, are interested in adding some Rust into their mix, into their projects. So you might want to combine existing code with it. And then you also need a library. The typical approach to do a binding is to take the Qt C++ base, build a binding on top, and then put the other language there. And that's not the approach I'm going to take here. And I'll explain later what we are going to do. Well, I guess you know these advantages by heart. Why is Rust so cool? It's very safe. One of my favorite things of Rust is the algebraic data types, also known as simply the enums. That's something that C++ simply doesn't have. I think it's great. The macros are very clever. Cargo is great. But all of these things are not really there in C++, at least not in the way that Qt uses them. It's a great library, but these innovations in Rust simply haven't made it into Qt yet. So if we're going to make an API of Rust on top of Qt, then we're leaving a lot of advantages on the table. So that's why I think that wrapping a Qt API in Rust would be like fitting a square peg in a round hole. That's not going to work. But there's a solution. What we could do is just shine a light differently on it. And well, here's the square. Here's round. Great. We just put some JSON in the middle. So yeah, how will that work? OK, so we're going to do the binding in two directions. First, you're going to write your data model in JSON. And I'll show you later how to do that. And then you generate bindings from that. And these bindings talk to your user interface and to Rust. And all the purple boxes here are stuff that you have to write. So if you came in here thinking, I'm going to write a user interface only in Rust, that's not what this talk is about. You still will have to either use QML, which is a very nice declarative language, or Qt, which is C++, on top of your Rust. But the advantage is, if you take this approach, then you have separated the logic of your application very well. And if you want, you could also put then a different UI on top like HTML. So this is the approach we're going to take. Now I need to explain a bit about the core principle of how Qt works. The basic thing in Qt is QObject. A QObject is a class. And you can give it signals and slots. And outside of Qt, people call these things events and listeners. And so you combine, build a loosely coupled system. And it's loosely coupled if one of the objects is destroyed, then the connection is broken. It's the same as what you have in JavaScript. Imagine. So it takes you to have memory manager because you have hierarchical ownership. You just say, when you create something, this is the parent. When you destroy it, the whole hierarchy is destroyed. And objects have properties. Now there's another important building block in Qt. And that's the Q abstract item model, long, complex name. But basically what it is, it's the way data is represented from your logic to the user interface. And it's used everywhere. So here is a table and a graph. And there's one data model underneath, which is an implementation of this model. And it's used in two places in a very different way. And here you see a table. I'm not sure if everybody in the back can see it here. But one of the cells in the table shows a percentage. And it's filled partially. And that's also a trick which is implemented on the UI level. But the data underneath is provided by this abstract item model. And you can also have trees. So this is used everywhere in Qt. But it's kind of hard to implement, even if you just do it in C++. So the tool that I'm presenting is focusing very strongly on making it easy to do this. So yeah, basically you can even forget about this. And just know that we're going to build a model which gives you all of that. OK, so how is it going to work? We write a model description in JSON. And then the tool would generate a binding.h and a binding.cpp file, which we use in our C++ code, and an interface RS, which will contain a trait, a Rust trait, which you have to implement. And then you combine your Rust code into a static library, which you link to your C++ application. And you're either imported with binding.h or if you're using QML with import Rust code. The Rust code is a name you can think of yourself. This is what I use in my examples. Briefly about QML, Qt modeling language. This is a very nice innovation, which was triggered when Nokia bought Qt. They wanted to make phones with very performant and easy to write user interfaces. So what they did is they came up with a declarative user interface language. And it can do 2D programs or 3D even. And it's used in lots of mobile applications. So it started off at Nokia, Mego phones. The Ubuntu phones are using it everywhere. Silfish, KDE Plasma desktop, KDE Plasma mobile. And you can also use it for iOS and Android apps, if you like that stuff, which apparently is the majority of the people. It's designed for efficiency on graphics cards. And that's actually, when we're talking about Rust, is not unlike WebRender, which has quite a lot of similarities in the way it's designed. OK, so now we're going to write a small application. So you understand a bit more of how all of this works together. This is a to-do application. And this application, there is a website called to-do-mvc.com, where the same specification is implemented in 20 or 30 different JavaScript frameworks. And I took that specification and implemented this with QML and Rust, just because I didn't really know what I should write. I thought, well, here's a specification already given. Let's just implement that. And I can look at the application here a bit. So what else should I need to do? Well, keep talking, I guess. And you can tick off stuff here. And you can just see the active parts, or only the completed ones. I can clear the stuff that's completed, go back to all. I can toggle here everything. So it has some basic functionality. And the UI part of it is about 150 lines of code. And the model beneath is fairly simple. So if you want to build this, how do we start? First, we need to write the binding, where we describe our model. Now, the object we call totals. And the type will be a list. We have a list of to-do items. What you can put here is either an object, which is only one item, or a list, or a tree. It will have properties. And the properties should be a count of a number of items and the active count, which is the number of items that still need to do. And every item in the list is either completed or not. So this is a Boolean field. And it has a text, a description. Probably some people here are thinking, why not just write a Rust macro? Well, maybe we'll do that at some point. But for now, it's just a JSON description. OK, that's checked off. Now we need to run the generator. So that's just one executable. You call it with the file. And this is set up like this so that you can integrate it with CMake, or with Cargo, and build RS. And this generates these three files that I mentioned. And then what I need to do is I need to write an implementation.rs, which is a Rust file. OK, now we're going to look inside the three generated files, and they're going to look a bit complicated, but you don't have to do that. It's just to show you a bit of how it goes, what goes on underneath. So this is a bit of C++. It's the class to do. And it implements abstract item model. It has a constructor, a destructor. It declares some properties. And it declares also some functions for setting and getting the values. So this is fairly simple. And there's an implementation along with it. So here is the foreign function interface that talks to Rust. So these functions are declared in the C++ part and should be implemented by Rust. You also won't have to do this, but this is the point where the two languages meet, where they connect up. And here is a bit of example code, which is typical for this data model. You have the class, and there's a function data. You give it an index and a role. And the role can be I would like to have a display, or a color, or in our case, the description, or if it's completed or not. That can also be your role. And then here's this big switch statement, which calls into the Rust code. So it calls to Rust and asks, get me the completed version for this index or the description for this index. And again, all of this is generated, so you don't have to worry about it. But how does it look on the Rust side? Well, on the Rust side, we have a trait called the to-do's trait. And it has a constructor, which you need to implement. And it has an emitter. The emitter is there so that you can emit signals when something has changed. So you can signal to the user interface that something has changed. For example, some item was added to the list. There's functions for inserting rows. And here are the functions to get the value if number 1, 2, 3, or 5 is completed or not. And you can set it to be completed, or you can get the description or set the description. So two items left. And this is the work that you will have to do when you write an application with Rust and Qt. So we need to implement the Rust part and the Qt part. So for the Rust part, we are implementing a list. The list has items. So we just have a struct with a Boolean and a string, so far so good. And then we have the object that contains the whole list of these items. And it also contains an account of how many items have not been finished yet. This is a cached value. And it has two objects to talk to the outside. Now we implement the trade. And this is also fairly simple. We need to get the value for the active count. And we just return the value also for the total count. We just return the length of the list. And when we want to know the description at a certain index, we just give back that value. So this is quite straightforward and simple. And this is the part which you will have to implement when you are writing a connection between Rust and Qt. So how do we do the last bit of it? And that's the QML part in our case. We have created this object. And this object, we want to expose to this Qt code. So we import the Rust code. We have called it version 1. Well, you can give it any number you like. The application window is basically something between brackets here. So this is QML. If in case you've never seen it, it's a fairly simple language. And here we have our object. So this object here is what we have implemented with Rust. And we give it an ID. So all of our to-do information is in this object. And we put it here. It's not a graphical thing, but we put it here so that we can access it from our graphical interface. And our main graphical interface is below here. That is a flickable list view. And it has a model. The model is the to-do model, which we have defined here. And we have a delegate. And the delegate is the UI item that we show for every item in the list. And that's defined here. So it's a component. It has a pane. And it has a checkbox. The checkbox is a checkbox checked or not. It's a declarative language. It is checked if the value of completed is true. So this is the information which is gotten from the Rust side. And this description is also gotten from the Rust side. But in here, it just looks very natural. You just write the name of the value you want. And it's automatically assigned to this text here, to the text of this label. Yeah, and that's it. So our application is done. So in conclusion, if you want to combine Rust and Qt, you should not, in my opinion, at least shoehorn the whole of Qt into a Rust API. But instead, you should wrap your Rust code in a Q object or a Q abstract item model, which you can then naturally use in your Qt or QML application. And by doing that, and you don't actually have to do it yourself because the Rust Qt binding generator does it for you, you get good Qt code and good Rust code. That's it. Yes, yes. OK, so the question is, how do you deal with different threads because Qt must have a user interface thread? Well, it does. If you have a Qt application, the main thread, the thread that you start, is the Qt thread. And if you want additional threads in your Rust code, you will simply start when you construct your object. You start a separate thread. And that is then alive as long as your object is kept alive by your Qt code. So you can do any type of number of threads. You can keep them running. And the signals you send to the user interface, those are thread safe. But you don't have to worry about that. It's automatically taken care of. What you need to know is that in Rust, you can just start as many threads as you want in the object that is generated for you. So in your implementation.rs, you can go wild with the threads you want. Yes. The question is, how do you deal with build systems? Do you take a lot of advantage of cargo or not? Basically, you're free to do whatever you like with your build system. All you need to do is call this binary to generate the code for you. And we have some templates that have CMake which call into cargo. But if you don't like that, if you would like to put everything in cargo, you're free to do that. But this project doesn't currently do it. But it's a matter of just calling that in build.rs in cargo. So it's not in the box. But you can do it. Yes? Yes. The question is, how do you do asynchronous work? Like with Hyper, for example, or other Tokyo things. That works perfectly fine. What you do is you, in your implementation.rs, you set up your Hyper or Tokyo loop. And that is running in your Rust thread, then, which you create yourself. And there, you set up everything for asynchronous IO. And Qt is not involved at all. Whenever you get asynchronous information, you can decide if it warrants a signal to the user interface. And then the user interface is updated. So it's thread safe. And it's kind of separate. Yes? What was the code that was instantiating the QMF scene and exposing all the C++ classes to QML? The question was, where is the code that exposes the Q object to the QML? Is that the question? And it's initiating the QML scene at work. The initiating the QML scene? Yes. Yes. OK, so the question is, how did you create the QML scene? And how did you tie the Rust stuff into QML? That was a 10 line C++ file, which you're right. It didn't show, but it's mainly always the same. You initiate your QML scene. You instantiate. Sorry, you register your Rust object into the QML scene, and then it's off to the races. That's not generated. You have to do it yourself. Yeah, but it's always the same. So you can copy the file from the template. Yeah, yeah. Yes? Right. Can you repeat the first part of the question? Yes? Yes. Right, yeah. The question, again, is how do you register the Rust Qt objects to the QML? And can I do it live as well? The answer is the same. You do what you normally do on the C++ side is you have a Q object. You instantiate it, and you register it to the QML scene. And yes, I'm pretty sure you can do it live, although I don't have an example which does that. Yes? Have you considered doing this with derives or something? Yeah, the question is the implementation looks pretty straightforward. Have you considered doing it with derive? And I assume that you mean derive on the Rust side, so basically a macro. I'm not entirely sure how derive is implemented, to be honest. It's basically just Rust code generating Rust code. OK, yeah. So could you implement this in Rust as an annotation on a class? You probably could. Yes, you probably could. I simply haven't done so because initially I wanted to be very hands-on on the code that was generated. In fact, all the demo codes and the testing codes, which is in the project, which is generated, is also committed so that whenever I change the generator that I have a sort of testing that the code is still the same. And if I would have done it with a derive, then it would be only there during the compile step. I would need to do some different things to actually check, but it's perfectly possible. Yes. Yes? Oh. Just on the outside? Yes, that's fine. Yeah. OK.