# Rust

## What it is

Rust is a programming language for the work traditionally done in C and C++,
where a program manages its own memory and is often linked into software written
in other languages. Its compiler produces native machine code ahead of time.
Version 1.0 was announced on 15 May 2015 as a language combining low-level
control over performance with safety guarantees, reached without a garbage
collector or a runtime, which is what lets a Rust library stand in for a C one.

Memory is managed through ownership, a set of rules the compiler checks. Each
value has one owner at a time, and once the owner leaves its scope, the value is
dropped and its memory freed, at a point fixed when the program is compiled
rather than whenever a collector next looks. Code that needs a value without
taking it borrows a reference, and the borrowing rules allow, at any moment,
either one mutable reference or any number of immutable ones, and require every
reference to be valid. A program that breaks a rule does not compile. The same
rules exclude data races, so two threads writing to the same data without
synchronisation is a compile error rather than an intermittent fault.

Rust has no exceptions. A function that can fail in an expected way returns a
`Result`, holding either a value or an error, and in many cases the compiler
insists that the caller deal with the error before the code builds; a bug the
program cannot recover from, such as reading past the end of an array, goes
through the `panic!` macro instead.

Static analysis is conservative, so the compiler rejects some programs that
would have been fine, and some work, such as driving hardware or calling another
language, cannot be checked at all. For those cases there is `unsafe`, which
unlocks five extra abilities, among them dereferencing a raw pointer and calling
an unsafe function, which by default includes any function declared from C. It
does not switch off the borrow checker; it marks the lines where the programmer,
not the compiler, vouches for memory safety, so a memory bug can only live
inside an `unsafe` block. The Rust Book's advice is to keep those blocks small
and wrap them in a safe interface, which is how parts of the standard library
are built.

A new compiler is released every six weeks. Changes that would break existing
code wait for an edition, which arrives every three years or so. There are four,
2015, 2018, 2021 and 2024, and the newest became stable on 20 February 2025 with
Rust 1.85.0. Each package names its edition in `Cargo.toml`, every compiler
builds all the editions that came before it, and packages of different editions
link together, so a project moves up when it chooses. Cargo, the dependency
manager and build tool, is included with the language, rustfmt keeps the code
style consistent, and third-party libraries arrive as packages called crates.

## Why it matters

In C and C++, a pointer used after its memory has been freed, or two threads
writing the same data, compiles without complaint and fails later,
intermittently and often far from the cause. Rust turns those programs into
compile errors, and because the checks run at build time, the finished program
pays nothing for them.

With no garbage collector and no runtime to carry along, Rust code can sit
underneath software in other languages. Anything that can call C can call a Rust
core through a C interface, so one well-tested implementation can serve clients
on several platforms. The Rust Book lists command-line tools, web services,
embedded devices and major parts of the Firefox web browser among its production
uses.

The cost is paid up front. Code has to be shaped so that the compiler can see it
is safe, which often means deciding who owns a value instead of passing
references around freely, and the Book itself says that ownership takes time to
get used to. When the compiler refuses a program it cannot verify, the answer is
usually a different structure rather than a way around the check.

Stability is the other half of the bargain. Since 1.0, breaking changes have
been largely ruled out, so a change that could break old code arrives only
through an edition that a package opts into.

## What it looks like in practice

In the portfolio, Rust is the core underneath
[a native macOS messaging client](/portfolio/built-a-native-macos-messaging-client-in-swift-6-154/):
the protocol's well-tested core is written in Rust and exposes a C interface,
and the client, 11,141 lines of Swift across 53 files, links it as a static
archive compiled from a pinned upstream revision. Pinning matters because the C
interface is the contract: a moving core changes the contract without changing a
line of Swift. Everything the C interface returns carries an ownership rule, and
getting one wrong produces a leak or a crash with no compiler warning in
between, so a thin wrapper owns every pointer and every string that crosses the
boundary, and no layer above it sees a raw pointer.

Linking that core into an application means shipping everything it depends on,
which is the subject of
[a licence audit of 644 Rust crates](/portfolio/audited-644-rust-crates-for-licence-compatibility-163/).
Each crate declares its licence as an expression, and the audit checks every
expression in the full dependency graph against an allow list on every build,
reading OR as a choice between licences and AND as an obligation to honour both.
Anything unmatched fails the build. Because a check that has never failed looks
the same as one that cannot, it was made to fail twice on purpose: once by
rewriting a crate's licence to a term the list rejects, and once by moving the
pinned core revision without regenerating the audit. It reads declared metadata
only and is not legal advice.

This site has no Rust source of its own; it meets the language at one remove,
through Ruff, which is written in Rust and checks every Python script a commit
touches.

## Where it goes wrong

Most Rust trouble sits at the edges of what the compiler checks: arithmetic in
an optimised build, the boundary with another language, and code that arrives
with a dependency.

**Arithmetic wraps in a release build.** A counter that panicked with an
overflow during testing turns silently into a small number in production. In
debug builds Rust checks integer arithmetic for overflow and panics; a build
with `--release` leaves the check out and wraps around, so 256 in a `u8` becomes
0, and the Book treats relying on that wrap as an error. Where a value can
overflow, choose the behaviour explicitly: `checked_*` returns `None`,
`saturating_*` stops at the limit and `wrapping_*` wraps on purpose.

```rust
fn add_stock(on_hand: u8, delivered: u8) -> Option<u8> {
    // None when the sum does not fit, in debug and release alike
    on_hand.checked_add(delivered)
}
```

**Memory bugs come back at the C boundary.** A program whose Rust side builds
without a single warning leaks memory or crashes inside a foreign call.
Functions declared in an `extern` block are unsafe to call because the other
language enforces none of Rust's rules, so who frees each pointer is a
convention the compiler cannot see. Put one wrapper in charge of every pointer
and string that crosses, write each ownership rule down beside the call, and
expose only a safe interface above it.

**A panic reaches C and the process aborts.** A Rust function called from C
panics, and instead of an error the whole program stops. Since Rust 1.81,
released on 5 September 2024, a panic that tries to leave a function declared
with the plain `"C"` interface aborts the process. Turn failures into return
values before they reach the boundary, and declare a function with `"C-unwind"`
only where the code on the other side expects to unwind.

**A routine update changes the licence of the whole build.** A version bump
three levels down brings in a crate whose licence the product cannot accept, and
nothing in the build says so. Each crate declares its own licence, and the
obligations add up across the whole graph. Check every crate's expression
against an allow list on every build, fail on anything unmatched, and break the
check on purpose once to prove that it fires.

## Further reading

- [The Rust Programming Language](https://doc.rust-lang.org/book/) — the
  official book, from installation through ownership, error handling and unsafe
  code.
- [What Is Ownership?](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html)
  — the three ownership rules and how memory is freed without a garbage
  collector.
- [Unsafe Rust](https://doc.rust-lang.org/book/ch20-01-unsafe-rust.html) — the
  five unsafe abilities, raw pointers and calling C through `extern`.
- [The Manifest Format](https://doc.rust-lang.org/cargo/reference/manifest.html)
  — the `edition`, `rust-version` and `license` fields of `Cargo.toml`.
- [Announcing Rust 1.0](https://blog.rust-lang.org/2015/05/15/Rust-1.0/) — the
  original aims and the stability promise that began with 1.0.

<https://engineer.company/glossary/rust/>
