Bits and Droids logo
Mail icon

The connector deserves a first-class upgrade from C++ to Rust

2/4/2024 | by Bits and Droids

The flight connector was my very first project in C++. As a young, aspiring junior developer, I was set on mastering the art of C++. This language gave me complete control and let my app work at blazingly fast speeds. What more could a young developer want?

Before I warn my younger self, I want to mention that working with C++ has taught me heaps about memory management, low-level coding, and algorithms. The language certainly still has a special place in my heart.

Make it stop

With great control comes great responsibility. Where many other languages try to protect you from stupid mistakes, C++ doesn’t out of the box. If you want to shoot off your leg, C++ will let you, leaving you wondering what you did to deserve this. Since the connector originated from an era where I wasn’t as competent as I am today, I can assure you there are many parts where I’ve shot off multiple limbs. This makes it very tiresome and time-consuming to work on old code blocks. Working on the connector became increasingly tiresome and felt like a chore.

Editing the output sets is a great example of this. When editing a set, I created a new array that contained all the outputs. Press checkboxes, and the code stores the outputs in the specified array at memory location x. After you were done editing your set, I made sure to call a function to clear the array, which reported the array contained 0 elements. All is well, right? Apparently, the clear function would not clean up the memory but indicate that the array was now empty and the memory could be freed at a later moment. For some magic reason, another function at another point of the application would create an array of the same type at the exact same memory location. Accessing the array would be out of nowhere, including all the old elements that were supposed to be freed. Debugging this kind of issue is really time-consuming. Notice how I blame higher powers and magic for the bug, but in all honestly, the problem was me. I didn’t properly clean my data, and C++ let me do whatever I wanted.

Besides that, the framework I’ve picked added complexity that prevented others from contributing to the connector. You needed to understand C++ and simultaneously be or become familiar with the Qt Framework to contribute. Flight simulation is quite a niche, C++ is quite a niche, and Qt is a niche. Finally, none of these technologies are really hip or sexy. This really narrows down the pool of potential people who can but, most importantly, want to contribute.

All things combined, working on the connector wasn’t fun anymore.

Cpp venn diagram
Potential pool of developers

Rust takes the sky

In the last few months, I’ve fallen in love with Rust. Rust is a programming language that gives you great control/speed like C++ does but protects your code from your biggest enemy, yourself. For the past week, I’ve been working on a proof of concept to see if Rust could be a fitting replacement for the flight connector. In order to create a GUI (user interface), I’m using the Tauri framework. Tauri lets you create desktop apps with Rust and a web interface. Looking at the connector, this means that Rust would handle the communication with mfs2020, while a webpage handles the visual application. Luckily, there already is a library(these are called crates in Rust) that makes it possible to communicate with SimConnect(the API of mfs2020 and probably of mfs2024). In order to make it suitable for the connector, I’ve contributed to the simconnect-rust crate by Sequel32. I could send data to and from the sim within a couple of hours of work.

How will Rust protect us from ourselves? Rust has quite a unique way of memory management. At a very basic level, Rust has a borrow checker that ensures every value only has a single owner. Another part of the code might borrow the value, but there will never be two owners simultaneously. This ensures that we cannot reference memory that might have already been cleared by another pointer (as we did in the C++ example). If the value goes out of scope and has no owners, the value is removed from existence. This new paradigm can make switching from a more high-level language to Rust feel daunting. Luckily, the Rust compiler has one of the best development experiences regarding error messages. If you make a mistake, the Rust compiler will tell you exactly where the error originated and why it failed and, in most instances, provide a link to further documentation. You’re still able to circumvent all the safety checks and shoot yourself in the foot, but you need to explicitly declare that the code you are writing is unsafe. If you spot these unsafe code blocks, your Spidey sense could indicate where the bug originated.

Let’s recreate the connector

Working on the UI has been a breath of fresh air as well. Qt’s implementation for desktop applications is a mix of C++ and custom css implementations. But somehow, they managed to create a development experience that drives you to madness. I’ve used React in the new connector since it’s still one of the biggest web frameworks (and I’ve used it in my other projects).

My first goal was to recreate the output menu in React. Recreating the menu was the final nail in the coffin for Qt. Working on the connector has become fun again. Making changes used to require recompiling the application, waiting for it to load, and eventually, concluding that you have to repeat the same process over and over again. I can change the code of the new connector and see the result immediately in the application.

Outputmenu reworked
A reworked version of the output menu

Even though I might be biased, I declare Rust to be a lot sexier and hip than C++. Tauri splits the application into two units (the frontend/interface and the backend). This broadens the potential pool of developers who can and want to contribute to the connector. You no longer have to be an expert in low-level languages to make a difference.

Rust venn diagram
The new potential pool of developers

Now what?

My personal goal will be to start migrating the core functionality from the C++ connector to Rust. What belongs to the core:

  • Send data to the sim from a microcontroller
  • Receive data from the sim
  • Send this data to a microcontroller
  • Create bundles
  • Create presets (i.e., run bundles x,y, and z on launch and swap when a new preset is selected)

All other features will be prioritized afterward.

If you are excited about these changes or want to contribute, visit the Github FlightConnector-Rust repo.