 So once again, thank you for being around, for staying with us. We're going to keep talking in the same direction as before. So this time it's like Rust integration with C++. I have the pleasure to introduce, like, Olivier. I already got a sneak peek on this talk in Berlin, and it was like, it blew my mind, so I hope it's going to be the same here. So a round of applause, and let's start. Hello. So I'm Olivier Goffin. So I started Open Source with KDE as a student, and then that led me to be hired by Nokia to work on Qt. Qt, as we call it. And then since 2011, I work for my own company. We do consultancy mostly around Qt. So I don't know how familiar everybody here is with Qt because it's not really Rust, right? We're in the Rust room, and Qt is a C++ framework mainly for UI, amongst other things. So this is some C++ code, but it's a Qt object, and as you can see in red, there are those macros. They define some extensions to C++ in a way. So they are going to be read by a tool which will extract the properties, extract the signals, extract the slots, and put some metadata around the code so then it can be code by another feature of Qt, another QML. And so this is basically QML is describing user interfaces in some funny languages based on JavaScript. And here we have a... The model is basically a C++ object, and when we query... we can query properties from this C++ object, and we can call functions from this C++ object, from JavaScript, from this QML which embeds JavaScript. And so if I go back to the previous slide, so here we have a set status class, a set status text which is going to be implemented in C++. And the QML can call this because of the annotation we have and because the mock has extracted all the properties, and we can call C++. So that's a strength of QML, which is an easy way to represent user interface, and when we need performance, we can use C++. So when I was working for Nokia, one of the things I did was to work on QObject and making signal slots and mock working. And when I left, I still was involved in the Qt community, and I did a few things. For example, MockNG is to be the real mock, so the tools that parses the header that you write. The real mock is written by a handmade parser, and I thought maybe it can be better to use a lip-clang for that. So that's one of my side projects. And also, side project is VerDegree. So it's a C++ header library with macros and template programming. Can we generate all these metadata at compile time with funny macros? Yes, we can. So that's one of my projects. And then because I like making meta objects, so the Qt meta object is those meta data. I thought maybe can we do that from Rust directly? And so that's why I came here, and eventually one thing led to another, and I'm presenting this. But I was not the first trying to use Qt from Rust. There were several previous attempts at making Qt bindings for Rust. As far back as 2014, somebody tried to write a tool called CX2Rust, and he wrote this blog post trying to explain what his tool was doing, and the title was The Pains of Wapping C++ in Rust, on the example of Qt 5. The conclusion of his research was that creating automatically bindings from Rust to C++ doesn't work very well. There is too many... So I took this image from this square into the circle, which I myself stole from another tool. So there's too many concepts like overload, default parameters. How do you map that in Rust? The fact that in C++ you do not have lifetime, so when you have pointers, which sometimes you're lucky, you have smart pointers, but how do you map that to Rust, which needs to know about all of that? So you cannot take a C++ API and create all of that Rust API, idiomatic Rust API save. That's just not possible. But it's not possible to make it automatically, but still you can do it. So the manual way, which is how one would do it manually, is to write, for every time we want to call into C++, we write in C++ a C function, an extend C function in C++, which calls the C++ API we want. So we expose basically a C API for every of the functions we want to call. And so we only can use pointers and types that the FFI can understand. So no standard strings, for example, because there's a constructor and destructor, so that wouldn't work. And on the Rust side, we need to write this extend function. With the same name, we don't forget the nomangle here, and then the types need to match the Rust equivalent. So some of the things we can optimize, for example, creating this... Once we have created those extend C functions, we can automatically create this can. So there is this tool. It's called the bind gen, and it can automatically create those extend functions from a header file. So this works for C, but only for a small subset of C++. So you cannot, for example, have virtual functions, and even then, it's still not an idiomatic. So it's still a lot of manual work to create an idiomatic Rust API to wrap your C++ API. Another project. This is the Rust Qt Binding Generator. It's from Jose van der Rover, who is here in the audience. So this is a project also, which is hosted in KDE. And what you have to do here to use it is to create a JSON file, and in your JSON file, you describe basically your objects and all your functions and their parameters that they're taking. And so first you write these JSON files, and then there's a tool that generates C++ and Rust codes that then you can use from both C++ and Rust. So in the end, you still need to write a minimum of C++ codes to call this into the Qt API. And this is a good tool. But what I wanted to do really is to create that you have really idiomatic Rust code that you do not need to write any C++, you do not need to know anything about C++. So I didn't want to write manually on my call to... on my extensive function, and I found this create, Rust Cpp, whom I then later contributed to. And so there is two parts. There is a Cpp create, which is the runtime create, and there's also a Cpp build create, which is a build dependency. So you need to have a build.rs script. And so this allows basically to include C++ code directly into your Rust code. So you are in an unsafe context, of course, because it's still C++. But you can... So here, this thing would be a C++ code which is included into your Rust function. You also need to have a build.rs. So this is what cargo runs, compiles and runs at compile time. Before actually compiling your Rust code, it will run this little script. And so this little simple script will tell what will it do. It will parse the file, all your Rust code. It will extract all the Cpp and Cpp class macro, which are in your Rust code. And it will create a Cpp file with all this C++ code in a C++ file, which will then be compiled with a C++ compiler by the CC create. So this is doing automatically what... So this is basically creating your extend function, which you would have to write manually, but you write them in line in your Rust code, so you don't need to change context from one file to the other when you touch C++ file. And then at runtime, there is the Cpp create, which will just create the calls that calls into those functions. And so there is a... there is a procedural macro for that. It's a custom derive. It's behind the scenes, so you don't see that. But this generic code that also checks that the size and the alignment of everything you pass to C++ is correct. So this is an example for the QImage class. So QImage is a... So you have a QImage class in C++, and we have here this macro C++ class. And this is gonna declare a struct QImage in Rust, which represents a QImage in C++. And this macro will also use a procedural macro to declare a drop trait, so that when the struct in Rust is destroyed, it calls the C++ structure of the image, the clone trait, so when you copy the image, it implements the... it calls the C++ constructor on copy. And so this allows... and also it creates the struct of the same size of a QImage. So such that... when... such that basically it's just exposing QImage from C++ into Rust. And then you need to add some API around it, so you need to... you can implement... create an implementation for QImage, and then you have a... manually created... a idiomatic Rust API for QImage, so in every function, you use the C++ macro, which basically will allow to... to run C++ code, so basically just to forward your C++ function in C++. And so as we can see, we can... so this looks a bit like a capture and that's basically what it is, so you can pass some local parameter to the C++ and QString has been exposed the same way, so there is also a C++ class for QString, so you can have QString in Rust and they're mapped exactly to QString in C++. And so we can do the same with every function, and we can do a very small wrapper around those functions with a Rust-sounding name in a safe API and... with... Rust types and stuff like that. Another feature is when we have virtual... or classes that you should inherit in C++, so there's no... the closest thing to inheritance in C++ is re-implementing traits, so... in this case, normally in C++ you would inherit from the Q Abstract List Model class in C and you want to expose a trait... you want to expose a trait that does the same. So you're gonna create a trait and call it Q Abstract List Model, so it's a trait which has a few functions, and from the C++ code you're gonna override the virtual function in... so all of this code in C++ only, because it's wrapped in a C++ macro, so all of this code is C++ and when you re-implement your class in C++ you will call them into Rust using the Rust macro, so you can have a Rust macro inside C++ macro to call Rust from C++ and so you override the data function of Q Abstract List Model and you can then call the data function of your trait object and so this trait object is basically a wrapper around two pointers, the vTable and the pointer to the object, so... it's very simple, it just means that, well, this is opaque for C++ but when we pass it... when we pass Rust object to the Rust macro we tell the type system that this is basically a reference to a Q Abstract List Model a trait object and so this allows basically to create... so this thing you would write in your bindings, of course, and so the user of the binding it just re-implements the Q Abstract List Model trait and do not have to care about all of that and that's how we map inheritance to Rust so using this C++ create that's enough to create the QMet object RS create which wraps basically the most basic Qt classes so we can use the most basic Qt API that we need from Rust and in addition there is a... which was actually the reason why I did this is there is a custom derive, so it's a procedural macro for a QObject trait and this procedural macro will generate the meta object at compile time and so I didn't know much Rust at the time so I implemented that using some macro in the type but maybe this should be attribute in the future versions and so I have those macros that looks a bit like the Qt macros and that basically is annotating the code thing so name is a property it inherits from QObject in this case and we have a few methods and then we can register this type so I was creating here the struct creator then we can register this type to the Qt runtime engine and we can just load an eqml file and so this qml file is again JavaScript is the same as before and here we call basically a Rust function from the JavaScript and that's basically so that's basically the goal to have the user interface from Rust using qml in a safe way so there is still a lot to do and I'm not sure that everything is really safe so well it should there are points where there are always corner case which are indeed bugs but I would like to say that everything when it says safe it's really safe but so in conclusion what we've seen is that we've seen that creating if you want to wrap qml or if you want to wrap c++ from Rust there is always some manual work that is going to be translated a header file and make a Rust API out of that so there is always going to be manual work and the goal then is to make this manual work as easy as possible and in this case I believe the c++ create is the way to go because the c++ create you still have to write unsafe but you can just put the c++ code where you call it so you don't have to change context and so we've seen how to call c++ from Rust and I presented the qmet object create which allows to call to use qml and to expose your Rust object to qml so if there is any question I'd be happy to answer them so the question is if I understand correctly that when you write a qt API returns a pointer it's not always obvious who has the ownership of this pointer even for the developers and it's true that qt was written most of the API is a bit dated and was before smart pointers and that kind of things so yes you need to read the documentation to find out but it's the job of the bindings the people who are writing the bindings they should read the dog they should find out who has the ownership and then they should put the proper annotations on the proper lifetime on those results so when you call a function that returns a pointer you're gonna wrap it into some kind of box or anything and depending depending on what's the real meaning of this function so when you write the binding you should know about it and then you can add the right lifetime or put it into the right containers or smart pointer so there's another question there yes so the question was if it's prior to put no mangle so so in the C++ so this C++ CPP macro you do not have to do that because basically it's the macro itself who has this no mangle so as a user of the CPP macro you don't have to use no mangle if I go back I have a few slides so here basically what this thing here will be put in an extend C function which will have some names and then this macro will call the right function with a right no mangle you as the developer using this macro you don't have to take care about no mangle