7.1 Rust on Edge Devices

Introduction
Section titled “Introduction”These next sections provide a hands-on introduction to Rust, focusing on its application in edge programming. We investigate how Rust’s safety, performance, and concurrency features make it ideal for resource-constrained environments such as on edge platforms. Through practical examples, you’ll explore topics such as memory safety, zero-cost abstractions, and building efficient, reliable edge applications, which is important for developers looking to harness Rust’s power for modern IoT and edge embedded systems.
We explore Rust’s distinctive approach to object-oriented programming (OOP). Unlike C++‘s class-based inheritance, Rust achieves similar goals of abstraction and code reuse through a powerful combination of structs and traits. This paradigm shift offers a more explicit and flexible way to define data structures and shared behaviours, crucial for modelling complex systems on resource-constrained edge devices without the overhead of traditional OOP hierarchies.
A significant portion of this section is dedicated to Rust’s foundational memory management model, including memory terminology, variables, memory regions, and a detailed introduction to ownership, borrowing, and lifetimes. These concepts are a little abstract at this point, but they are at the core of Rust’s compile-time memory safety guarantees, eliminating entire classes of bugs prevalent in C/C++ (such as dangling pointers, buffer overflows, and data races) without relying on a garbage collector. For edge programming, where predictable performance and minimal runtime overhead are vital, understanding how Rust statically enforces memory correctness is invaluable.
We then solidify our grasp of the language’s building blocks by examining Rust’s data types (both scalar and compound), functions, and control flow. You’ll see how Rust’s explicit type system, powerful pattern matching, and expression-oriented nature contribute to writing robust and readable code. These features are particularly beneficial in embedded and edge contexts, where clarity and deterministic behaviour are critical for debugging and maintaining systems with limited resources.
Finally, we’ll delve into custom data types, specifically structs (including classic, tuple, and unit structs) and enums. Rust’s enums are far more versatile than their C/C++ counterparts, as they can encapsulate diverse data for each variant, enabling elegant state management and robust error handling. This capability is essential for designing resilient software for edge devices that must respond reliably to various inputs and real-time conditions.
By mastering these fundamental concepts, you’ll gain the tools to leverage Rust’s unique strengths, enabling you to develop highly efficient, secure, and reliable applications for the next generation of edge devices.
Reference Materials
Section titled “Reference Materials”Here are some useful references for learning the Rust programming language:
- The Rust Programming Language Book (“The Book”) An excellent guide to learning Rust, covering its syntax, ownership model, and key features.
- Rust By Example An extensive collection of runnable examples that illustrate various Rust concepts and standard library features.
- Rustlings A series of small exercises to get you used to reading and writing Rust code. Ideal for hands-on learning and practice.
- The Rust Standard Library Documentation Comprehensive documentation of Rust’s standard library.
- The Rustonomicon A deep dive into Rust’s more advanced features, focusing on unsafe code and inner workings.
- C++ to Rust Phrasebook a book designed to help C++ programmers learn Rust.
Rust versus C/C++
Section titled “Rust versus C/C++”Edge programming traditionally leans heavily on C++ due to its performance and control over hardware. While C++ has long been a strong choice, Rust introduces significant advantages for modern edge development:
- Memory Safety Without Garbage Collection: Unlike C++, Rust provides guaranteed memory safety at compile time without relying on garbage collection. This eliminates common issues like null pointer dereferences, buffer overflows, and use-after-free errors, which is vital in resource-constrained edge environments where reliability is critical. In July 2019 Microsoft announced that over 70% of system-level Common Vulnerabilities and Exposures (CVEs) in the previous 12 years related to memory safety bugs1, making the case for the use of modern, safer system programming languages such as Rust .
- Concurrency Made Safe: Now that modern edge devices are commonly multi-core devices, they often need to manage multiple tasks concurrently, such as sensor data processing and communication. Rust’s ownership system ensures thread safety without introducing runtime overhead, reducing the risk of race conditions compared to C++‘s manual management of threads.
- Zero-Cost Abstractions: Rust offers high-level constructs like iterators and pattern matching, while still compiling down to efficient, low-level machine code. This matches C++‘s performance but with a cleaner, more intuitive syntax that reduces the likelihood of bugs.
- Modern Developer Tooling: Rust’s Cargo build system, integrated package management, and built-in testing frameworks streamline development compared to the fragmented tooling ecosystem often associated with C++. These tools enable faster prototyping and deployment on edge devices.
- Stronger Guarantees for Cross-Platform Compatibility: Edge applications frequently span diverse architectures and hardware. Rust’s explicit handling of data types and features like
no_std(for environments without a standard library) make it easier to write portable, architecture-agnostic code. - Growing Ecosystem for IoT and Embedded Systems: Rust’s growing community and ecosystem offer libraries and frameworks tailored for edge programming, such as
tokiofor async programming andembedded-halfor hardware abstraction.
By adopting Rust, developers can achieve the performance and control of C++ while significantly reducing development time and the risk of critical bugs, making it a compelling choice for edge programming.
🧩Knowledge Check
Section titled “🧩Knowledge Check”Match Rust Core Advantages
Table 1: Here’s a brief comparison table highlighting the key differences between Rust and C++ for edge programming.
| Feature | Rust | C++ |
|---|---|---|
| Memory Safety | Enforced at compile time with ownership, borrow checking, and no nulls or dangling pointers. Embedded systems do not typically have an MMU making memory safety even more important. | Manual memory management; prone to errors like null pointer dereferences and buffer overflows. |
| Concurrency | Built-in safety guarantees prevent race conditions without runtime overhead. | Manual thread management; prone to race conditions and data corruption. |
| Performance | Comparable to C++ with zero-cost abstractions. | High performance but requires manual optimisation. |
| Error Handling | Strong support with Result and Option types for clear and explicit error handling. | Relies on exceptions, which can be harder to trace and manage. |
| Tooling | Integrated tools like Cargo for building, testing, and dependency management. | A fragmented tooling ecosystem often requires multiple external tools. |
| Learning Curve | Steeper due to new concepts like ownership and borrowing. | Familiar to developers with a background in traditional OOP languages. |
| Cross-Platform Support | Strong support with precise control over data types and no_std for embedded systems. | Good support but requires careful management of platform-specific dependencies. |
| Community & Ecosystem | Rapidly growing, with libraries like embedded-hal and async frameworks like tokio. | Mature ecosystem with a wide range of established libraries and frameworks. |
| Code Clarity | Encourages cleaner, more maintainable code with strict compiler checks. | Allows more flexibility but can lead to harder-to-maintain codebases. |
| Safety Overhead | No runtime penalty for safety guarantees. |
Rust Playground
Section titled “Rust Playground”If you are anxious to get started you could try the Rust playground at https://play.rust-lang.org. It is an online platform for experimenting with and sharing Rust code. It provides a browser-based editor with the ability to write, compile, and execute Rust programs without requiring a local installation of the Rust toolchain.
- Code Editor: Write and modify Rust code directly in the browser.
- Compiler Options: Choose different Rust versions (e.g., stable, beta, nightly) and enable features like optimisation levels and warnings.
- Crate Integration: Import and use external crates by specifying dependencies in a virtual
Cargo.toml. (See the note below) - Execution and Output: Instantly compile and run the code, displaying results in a terminal-like output panel.
- Sharing and Collaboration: Share code snippets using generated links for easy collaboration.
For example, here is a test application that is linked below:
fn main() { println!("Derek says, hello!");}Click on RUN button on the top left and you should see the following output:
Standard Error Compiling playground v0.0.1 (/playground) Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.59s Running `target/debug/playground`Standard OutputDerek says, hello!A Nice Starting Example
Section titled “A Nice Starting Example”To give you a taste of what Rust looks like in practice, here is a small, elegant program that processes a list of sensor readings. It demonstrates Rust’s clean syntax, its powerful iterator system, and its explicit handling of types, all while maintaining the performance of C++.
fn main() { // An array of temperature readings from an edge sensor let readings = [18, 22, 25, 21, 19];
println!("Processing edge sensor data...");
// Calculate the average using a high-level iterator chain // Zero-cost abstraction as it compiles to efficient machine code let sum: i32 = readings.iter().sum(); let average = sum as f32 / readings.len() as f32;
println!("The average temperature is {:.1}°C", average);
if average > 20.0 { println!("Status: Optimal operating conditions."); } else { println!("Status: Power-saving mode recommended."); }}This program gives the output (Open in Rust Playground):
Processing edge sensor data...The average temperature is 21.0°CStatus: Optimal operating conditions.This example is more than just a “Hello World”; it is a real (though tiny) edge application. It highlights:
- Type Safety: Notice the explicit conversion using
as f32. Rust doesn’t allow silent precision loss, forcing you to be intentional about your data. It is really strict! - Expressive Iterators: The
readings.iter().sum()chain is highly readable but compiles down to a loop as fast as one you would write by hand in C. - Zero-Cost Abstractions: You can use high-level concepts like iterators without worrying about runtime performance penalties as the compiler handles the heavy lifting.
The Rust Edge Ecosystem
Section titled “The Rust Edge Ecosystem”Developing for the edge requires more than just a safe language; it requires an ecosystem that understands the constraints of limited memory, power, and diverse hardware peripherals. Rust’s ecosystem is structured to handle these demands through several key architectural pillars.
Bare-Metal Development with no_std
Section titled “Bare-Metal Development with no_std”In many edge applications, such as those running on a raw microcontroller like the ESP32 that we use in this module, there is no underlying operating system (like Linux or Windows) to provide services like memory allocation or file I/O. Rust handles this through the #![no_std] attribute. By opting out of the standard library (std), your code only uses the core library, which is platform-agnostic and does not require an OS. This results in incredibly small binaries and predictable performance, essential for “bare-metal” programming where you are interacting directly with the processor registers.
Hardware Abstraction with embedded-hal
Section titled “Hardware Abstraction with embedded-hal”One of the greatest challenges in embedded C/C++ is portability; code written for an STM32 I2C peripheral rarely works on an ESP32 without significant rewriting. The Rust community solves this with embedded-hal (Hardware Abstraction Layer).
embedded-hal defines a set of traits (which we will see are essentially interfaces) for common peripherals like GPIO, UART, I2C, and SPI.
- Silicon Providers (like Espressif for the ESP32) provide a crate that implements these traits for their specific hardware.
- Driver Developers write drivers (e.g., for a temperature sensor) that only depend on the traits, not the specific chip.
This means a sensor driver written for Rust can work across any microcontroller that supports
embedded-hal, allowing for a massive, reusable driver ecosystem.
Efficient Data with serde
Section titled “Efficient Data with serde”Edge devices are often data-gathering nodes. Serialising this data to send over a network (like MQTT or LoRaWAN) must be fast and memory-efficient. serde (Serialisation/Deserialisation) is the gold standard in Rust.
Unlike many C++ libraries that use heavy runtime reflection, serde uses Rust’s powerful macro system to generate serialisation code at compile-time. When combined with compact binary formats like Postcard (designed for no_std), you can serialise complex sensor data structures into a tiny byte array with zero runtime overhead. This is a perfect approach for the energy-conscious AIoT edge.
Example Hardware: The ESP32 Landscape
Section titled “Example Hardware: The ESP32 Landscape”The ESP32 serves as a perfect example of this ecosystem in action. Whether you are using the dual-core Xtensa variants or the newer RISC-V models (like the ESP32-C3), the community provides:
- Peripheral Access Crates (PACs): Low-level register definitions.
- Hardware Abstraction Layers (HALs): High-level,
embedded-halcompliant APIs. - Wifi/Bluetooth Stacks: Support for both bare-metal (
no_std) and Embedded Linux-like (std) environments.
This layered approach allows you to choose the level of abstraction that fits your specific edge use case from low-power sensor sleepers to high-throughput AI gateways.
🧩Knowledge Check
Section titled “🧩Knowledge Check”Match Rust Ecosystem & Syntax
References
Section titled “References”Footnotes
Section titled “Footnotes”© 2026 Derek Molloy, Dublin City University. All rights reserved.