Posted 2022-11-25 23:00:00 GMT
The programming language Rust has grown up and is making waves, powering parts of the Linux kernel. The main innovation is the borrow checker which keeps track of references and which code is allowed to mutate which state.
I last tried it five years ago and definitely didn't have a good time as syntax was unstable so code snippets in old documentation didn't work. There was a bit of that still I couldn't use Tokio because the Tokio subcrate I wanted wasn't compatible with the new Tokio, and the error message was not helpful: "there is no reactor running."
The integration with VS Code allows context aware symbol completion and even correctly highlights issues with macros though the editor spins constantly at 100% CPU. Everything needs to be installed consistently through rustup (the Rust package manager, which doesn't collaborate with the Ubuntu package manager) or else the rust-analyzer gets infuriated.
The experience with halfbaked crates felt leftpaddy so I decided to jus call libc. This brought up Rust's apparent deliberate hostility to C. It is painful to call C functions correctly. Rust has reluctant support for errno (std::io::Error::last_os_error().raw_os_error()) and nul-terminated CStrings. I didn't see a code-snippet example of anybody handling EAGAIN in Rust to retry a syscall. Surely there must be at least one? Here's my first try
macro_rules! syscall { ($e: expr) => {{ let mut unsafe_retry_ret; let start = Instant::now(); loop { unsafe_retry_ret = unsafe { $e }; if start.elapsed() > Duration::from_secs_f64(2.0) { eprintln!( "system call took too long {} = {}: {:?}", std::stringify!($e), unsafe_retry_ret, start.elapsed() ); } if unsafe_retry_ret == -1 { if std::io::Error::last_os_error().raw_os_error() == Some(libc::EAGAIN) { continue; }; panic!( "system call failed {}: {}", std::stringify!($e), std::io::Error::last_os_error() ); } break; } unsafe_retry_ret }}; }
The macro system is pretty awesome and easy to use, even for local functions, where it allows a way of writing closures that can mutate while only borrowing at their invocation site. It's surprising that Rust hasn't implemented decltype or typeof.
It's nice to be able to put tests into the same file with the mod tests idiom, and the rustup target for static linking (cargo build --target=x86_64-unknown-linux-musl) worked perfectly.
My main notes were on interoperability:
Overall, I'm super impressed with the progress on the language, editors and rustup cargo ecosystem. For an embedded project that didn't need to interface with too much existing code I would consider Rust. That said, Rust programs are certainly not "safe" in a broad sense, as they tend to bake in crashes. I also copied some code from Stack Overflow which sent non-nul terminated strings to an API which needed the nuls, and wasn't warned about it.
Post a comment