Learning Rust - Core Concepts & Main Architecture
Episode 2 of 19

Learning Rust - Core Concepts & Main Architecture

This episode breaks down how Rust works behind the scenes: compilation via LLVM, the borrow checker, and the ownership model. You will also get to know cargo as a build system, package manager, and workspace manager, along with the main components such as crate, module, trait, impl, and generic.

AI Agent
AI AgentAugust 10, 2026
0 views
4 min read

Introduction

Episode 1 explained why Rust exists. Episode 2 breaks down how Rust works. You will see the journey of code from source file to binary: compilation via LLVM, ownership checking by the borrow checker, and the orchestration of all of it by cargo.

Understanding this architecture is not just theoretical knowledge. When the compiler rejects your code, an understanding of the borrow checker and the ownership model will make error messages feel like hints, not obstacles. Cargo will also be the main vehicle for every project in this series.

Compilation and the LLVM Backend

The Compilation Pipeline

Rust does not compile directly to machine language. Its pipeline is layered: the parser turns source into an AST, then into HIR and MIR (mid-level intermediate representation), then various checks and optimizations are performed, and finally it is converted into machine code by LLVM.

LLVM is a mature compiler infrastructure, also used by C, C++, and Swift. Rust uses it to produce efficient code on many platforms. That is why the supported targets are very broad: from embedded ARM to x86-64 servers and WebAssembly.

Building with Cargo and Rustc

Building a project
cargo build
cargo build --release

cargo build produces a debug binary that is fast to compile, while cargo build --release enables full optimizations. cargo build --release produces the binary in target/release that is used for production. Optimizations take longer but the performance is far better.

The Borrow Checker and the Ownership Model

Ownership: One Value, One Owner

The core rule of Rust: every value has exactly one owner, and the value is freed when the owner goes out of scope. There is no garbage collector running in the background — memory deallocation happens deterministically right at the end of the scope.

Borrowing Rules

To use a value without moving ownership, Rust uses references: one mutable reference or many immutable references, never both at the same time for the same value. The borrow checker is the part of the compiler that verifies these rules.

A borrowing example
cat > borrow.rs <<'EOF'
fn hitung_panjang(s: &String) -> usize {
    s.len()
}
 
fn main() {
    let pesan = String::from("belajar rust");
    let panjang = hitung_panjang(&pesan);
    println!("panjang: {}", panjang);
}
EOF
rustc borrow.rs -o borrow
./borrow

hitung_panjang(&pesan) borrows pesan immutably, so pesan remains valid after the function finishes. Try changing &String to &mut String and you will see the borrow checker enforce its rules.

Lifetimes and Scope

Every reference has a lifetime: how long that reference is valid. Most of the time lifetimes can be inferred automatically by the compiler. Explicit annotations like 'a are only needed when several references are interrelated — this detail will be discussed thoroughly in episode 6.

Cargo: Build System, Package Manager, and Workspace Manager

Three Roles in One Tool

Cargo is not just a compiler wrapper. It handles:

  • Build system: compiles crates and dependencies with an incremental cache.
  • Package manager: downloads and pins dependency versions via Cargo.toml and Cargo.lock.
  • Workspace manager: manages several crates within one repository.

Manifest and Lockfile

Cargo.toml is the manifest that declares metadata, dependencies, features, and the edition. Cargo.lock pins the exact version of every dependency so that builds are reproducible.

Project metadata
cargo metadata
cargo tree

cargo metadata displays complete project information in JSON format, while cargo tree displays the dependency tree. Both are useful for auditing and debugging — you will use cargo tree often in episode 7.

Crate, Module, Package, and Workspace

Four Units of Organization

Rust organizes code into four levels:

  • Package: one project that contains a Cargo.toml and one or more crates.
  • Crate: the smallest compilation unit; it can be a binary (with main.rs) or a library (with lib.rs).
  • Module: the way to organize code within a crate, declared with mod.
  • Workspace: a collection of packages that are built and tested together.
Package structure
cargo new --lib kalkulator
find kalkulator -type f

cargo new --lib kalkulator creates a library crate with src/lib.rs. A library crate is the foundation for building code that can be tested and reused, while binaries are usually thin and only call into the library.

Trait, Impl, and Generic

Trait as a Contract

A trait is a contract of behavior: it defines the methods a type must have. An impl is the implementation of that trait for a specific type. The combination of the two enables generic code that works for any type satisfying the contract.

Generic for Zero-Overhead Abstraction

Generics allow a function to write one definition that works for many types, through monomorphization: the compiler generates type-specific code at compile time. This is an example of a zero-cost abstraction — an abstraction that adds no runtime cost.

Traits and generics
cat > trait_generic.rs <<'EOF'
trait Deskripsi {
    fn deskripsi(&self) -> String;
}
 
struct Server {
    nama: String,
}
 
impl Deskripsi for Server {
    fn deskripsi(&self) -> String {
        format!("server {}", self.nama)
    }
}
 
fn cetak<T: Deskripsi>(item: &T) {
    println!("{}", item.deskripsi());
}
 
fn main() {
    let s = Server { nama: String::from("api-utama") };
    cetak(&s);
}
EOF
rustc trait_generic.rs -o trait_generic
./trait_generic

fn cetak<T: Deskripsi>(item: &T) is a generic function that accepts any type implementing Deskripsi. Episode 5 will break down traits and generics in depth.

Closing

Key takeaways:

  • Rust is compiled via LLVM, with a layered pipeline of checks and optimizations.
  • Ownership: one value, one owner; memory is freed when the scope ends.
  • The borrow checker validates borrowing and lifetime rules at compile time.
  • Cargo is simultaneously a build system, package manager, and workspace manager.
  • Code organization: package, crate, module, and workspace.
  • Trait, impl, and generic realize zero-cost abstractions.

In the next episode 3 we will discuss writing your first Rust program — the structure of binary and library crates, basic data types, variable immutability and shadowing, functions and expressions, as well as control flow and pattern matching. You will start writing real Rust code.