Over the past couple weekends, I built a digital audio synthesizer in rust. It is controlled via the keyboard, with the bottom two rows emulating piano keys. Since there are fewer keyboard buttons than piano keys, you can specify which octave to play via a command line argument. For some extra fun, you can also specify which waveform to synthesize (sine, square, triangle, or sawtooth). Lastly, it is polyphonic, meaning it supports playing multiple notes at the same time (keyboard hardware / firmware permitting). Here is a link to the code.
I’ve recently come back to an older project of mine (that powers this website), and as I did some maintenance work: upgrade to newer crates, upgrade to a newer rustc, I noticed that my build was taking too damn long!
For me, this is a big issue. Because I juggle a lot of things at any given time, and I have less and less time to just hyperfocus on an issue, I try to make my setup as productive as possible.
Microcontrollers (MCUs) are ubiquitous in modern electronics. These combination hardware/software devices are called embedded devices, and their software is usually programmed in C or C++. Rust is a modern language that’s recently become a viable alternative. This article explores Rust’s capabilities on embedded, and provides a starting point for writing firmware with it. It contains introductory information about embedded programming and Rust that you may already be familiar with; you may wish to scroll down and skip to the code examples.
I’ve seen good programmers struggle learning Rust, or even give up. I’ve had some difficulties myself.
Here are the mistakes I’ve seen which may make you fail at learning Rust. I hope this list will help you avoid them.
It’s that time again! Time for us to take a look at who the Rust community is composed of, how the Rust project is doing, and how we can improve the Rust programming experience. The Rust Community Team is pleased to announce our 2021 State of Rust Survey! Whether or not you use Rust today, we want to know your opinions. Your responses will help the project understand its strengths and weaknesses, and establish development priorities for the future.
I have not worked on Rust projects in quite a while, and don’t know if I ever will again. I feel many crate maintainers are way too perfectionist, for example, despite all the developer hours that went into this PR, it took the effort within years to be (halfway) merged.
There’s always a reason not to merge, isn’t there? It would be better done with a new nightly language feature, or the function signature should have a where clause, or the documentation is not perfect. There’s always a new nit to pick in the world of Rust crates, it seems. There’s always a new pseudo-problem to tackle. Eventually, developers give up, which suits these maintainers just fine: after all, their baby goes on unchanged, and should they find the feature necessary, or the bug bothersome, they can fix it much better than any outside contributor. (Or so they tell themselves.)
This book is an attempt to distil the Rust community’s collective knowledge of Rust macros. As such, both additions (in the form of pull requests) and requests (in the form of issues) are welcome.
Supply chains attacks are all the rage these days, whether to deliver RATs, cryptocurrencies miners, or credential stealers.
In Rust, packages are called crates and are (most of the time) hosted on a central repository: https://crates.io for better discoverability.
We are going to study 8 techniques to achieve Remote Code Execution (RCE) on developers’, CI/CD, or users’ machines. I voluntarily ignored perniciously backdoored algorithms such as cryptographic primitives or obfuscated code because this is a whole different topic.
The goal of this post is to raise awareness among developers about how easy it’s to carry these kinds of attacks and how pernicious they can be.
Of course, an attacker can combine these techniques to make them more effective and stealthy.
One of the most interesting emergent properties of the Rust language has been the desire and ability to push more and more information into the type system. Other programming languages allow this, but Rust’s combination of speed, safety, and extremely powerful compile-time computation through both types and macros, have lead to a large ecosystem of highly capable libraries that do much of their work before the program ever runs.
Recent developments in the type system are making it easier than ever for programmers to take advantage of that power, and things are only going to get more interesting.
As you know, Rust does not support optional function arguments nor keyword arguments, nor function overloading. To overcome this limitation rust developers frequently apply builder pattern. It requires some extra coding, but from the API ergonomics perspective, gives a similar effect as keyword arguments and optional arguments.
Performance is one of the top reasons developers choose Rust for their applications. In fact, it’s the first reason listed under the “Why Rust?” section on the rust-lang.org homepage, even before memory safety. This is for good reason too–many benchmarks show that software written in Rust is fast, sometimes even the fastest. This doesn’t mean that everything written in Rust is guaranteed to be fast, though. In fact, it’s surprisingly easy to write slow Rust code, especially when attempting to appease the borrow checker by cloning or
Arc-ing instead of borrowing, a strategy which is generally recommended to new Rust users. That’s why it’s important to profile and benchmark Rust code to see where any bottlenecks are and to fix them, just like you would in any other language. In this post, I’ll demonstrate some basic tools and techniques for doing so, based on my recent experience working to improve the performance of the
This is a follow-up to Error handling in Rust from a couple of days ago. The moment we want to use error propagation for different error types, we have to rely on trait objects with
Box<dyn Error>, which means we defer a lot of information from compile-time to runtime, for the sake of convenient error handling.
Which you might consider not convenient at all, because there’s some downcasting involved to get the original error back, and we rely on trait objects and dynamic dispatch to carry something like an error along our codebase. I’d rather have this information erased at compile time!