Coding Style

Lint

Any code in main should be free of rustc lint.

Formatting

Generally, most stable APIs and crates should be formatted with the Rust formatter. However, there are some idioms in Xous code that format quite poorly with the default Rust formatter options.

We are waiting on the stabilization of more rustfmt features to define a custom rustfmt.toml to address this before making formatting mandatory. It's been a few years waiting for this, though, so we might just bite the bullet and run rustfmt with +nightly and the features we need in rustfmt.toml, so that we can have a uniform style.

Trailing whitespaces are frowned upon.

Exception Handling

Background

A mistake was made early on in defining the Xous API where all errors were propagated, even for operations that are supposed to be infalliable or there is no sensible way to handle an error if it were to arise.

The subtlety is that some errors in Rust are more like assert statements. For example, a function that unpacks a message into a struct could fail. If such a failure is encountered, then you'd like to see a panic showing that exact line of code so you can fix the bug. There isn't a sensible alternative code path at run-time, because the root cause was likely a type mismatch error.

In most of the original code base, that error would be propagated up the call stack as an InternalError, until you get back to your main loop, at which point the main loop just throws up its hands and reports a panic but at a line of code several call frames away from the offending statement. Normally this problem can be fixed by reading the stack trace from a panic-unwind, but Xous does not have mature panic-unwind support and also the device's screen real estate is limited so a deep call stack cannot be displayed entirely on the screen.

Recommendation

We are in the process of refactoring code from going to a "propagate all errors" rule to a "panic on infalliable failures" rule. Infallible operations include most syscalls (except ones that are explicitly fallible) and helper methods meant to transform inter-process messages and buffers into types (note that this does not include methods that receive, for example, arbitrary messages over network).

A simple .unwrap() is probably sufficient to check the results of most infalliable operations, because the panic handler will print a panic on that line

unwrap() may even be preferable to a .expect("helpful error message") in most cases, because "helpful error message" takes memory to store, increases the binary size, and in most cases the line of code where the panic happened is the most informative part of the error message.

Any error that happen in fallible operations (timeouts, OOMs, disconnects, etc.) should be handled and/or passed up the stack.