Skip to main content

Rust

We use rustfmt to format our code. This tool is part of the Rust toolchain and will format your code according to the Rust style guide. We also use clippy to catch common mistakes and improve the quality of our code.

This document covers some additional guidelines that are not enforced by rustfmt or clippy. And will generally allow you to write more idiomatic Rust code.

Avoid panics

Panics are highly discouraged in the Bitwarden codebase outside of tests. Errors should be handled gracefully and returned to the caller. clippy will forbid you from using unwrap. While expect is allowed, it should be used sparingly and should always provide a helpful message indicating why it can never occur.

Some scenarios where expect are allowed are:

  • Calling libraries that guarantee that the allowed inputs never results in Err or None.
  • Operating on slices or arrays where the index is guaranteed to be within bounds.

Discourage match

Rust often provide good alternatives to doing match on Option and Result.

if let

Use if let when you only care about one arm of a match.

// Bad
match result {
Ok(value) => outer.append(value),
_ => (),
}

// Good
if let Ok(value) = result {
outer.append(value);
}

Options

We use clippy to enforce general guidelines for working with Option. Generally reach for methods like:

map

Use map when you want to transform the value inside the Option.

// Bad
match Some(0) {
Some(x) => Some(x + 1),
None => None,
};

// Good
Some(0).map(|x| x + 1);

and_then

Use and_then when you want to chain multiple operations that return an Option.

func(x: i32) -> Option<i32>;

// Bad
match Some(0) {
Some(x) => func(x + 1),
None => None,
};

// Good
Some(0).and_then(|x| func(x + 1));

unwrap_or

Use unwrap_or when you want to provide a default value.

// Bad
match Some(0) {
Some(x) => x,
None => 1,
};

// Good
Some(0).unwrap_or(1);

ok_or

Use ok_or when you want to convert an Option to a Result.

// Bad
match Some(0) {
Some(x) => x,
None => Err("error"),
};

// Good
foo.ok_or("error");

Results

When working with Result it might be tempting to use match to get the value out of the result. Instead, use the ? operator to propagate the error.

map_err

Use map_err when you want to transform the error inside the Result.

// Bad
match result {
Ok(value) => value,
Err(_) => return Err("Another error"),
}

// Good
do_something().map_err(|e| "Another error")?