Basics

Formatting Rust code

To format all the Rust code within a directory $DIR, run:

./mach lint -l rustfmt --fix $DIR

Using Cargo

Many Cargo commands can be run on individual crates. Change into the directory containing the crate’s Cargo.toml file, and then run the command with MOZ_TOPOBJDIR set appropriately. For example, to generate and view rustdocs for the xpcom crate, run these commands:

cd xpcom/rust/xpcom
MOZ_TOPOBJDIR=$OBJDIR cargo doc
cd -
firefox target/doc/xpcom/index.html 

where $OBJDIR is the path to the object directory.

Using static prefs

Static boolean/integer prefs can be easily accessed from Rust code. Add a rust: true field to the pref definition in modules/libpref/init/StaticPrefList.yaml, like this:

- name: my.lucky.pref
  type: RelaxedAtomicBool
  value: true
  mirror: always
  rust: true

The pref can then be accessed via the pref! macro, like this:

let my_lucky_pref = static_prefs::pref!("my.lucky.pref");

Helper crates

The following in-tree helper crates provide idiomatic support for some common patterns.

  • nserror reflects nsresult codes into Rust.

  • nsstring exposes bindings for XPCOM string types. You can use the same ns{A,C}String types as C++ for owned strings and pass them back and forth over the boundary. There is also ns{A,C}Str for dependent or borrowed strings.

  • xpcom provides multiple building blocks for a component’s implementation.

    • The RefPtr type is for managing reference-counted pointers.

    • XPCOM component getters are generated by xpcom/components/gen_static_components.py, and can be called like this:

      use xpcom::{interfaces::nsIPrefService, RefPtr};
      let pref_service: RefPtr<nsIPrefService> = xpcom::components::Preferences::service()?;
      
    • There is also a get_service function that works like do_GetService in C++, as an alternative.

    • A set of derive macros help with declaring interface implementations. The docs have details and examples.

  • moz_task wraps XPCOM’s threading functions in order to make it easy and safe to write threaded code. It has helpers for getting and creating threads, dispatching async runnables, and thread-safe handles.

  • storage is an interface to mozStorage, our wrapper for SQLite. It can wrap an existing storage connection, and prepare and execute statements. This crate wraps the synchronous connection API, and lets you execute statements asynchronously via moz_task.

  • storage_variant is for working with variants. It also provides a HashPropertyBag type that’s useful for passing hash maps over XPCOM to JS.

Unfortunately, rustdocs are not yet generated and hosted for crates within mozilla-central. Therefore, the crate links shown above link to files containing the relevant rustdocs source where possible. However, you can generate docs locally using the cargo doc command described above.