Rust From the Ground Up

The Rust CLI Programming book by Matthew Provost

New! Updated for the 2021 Edition of Rust

Rust is not just another programming language: it represents a new paradigm for building modern systems. Previous generations of languages are all based on early processor architectures and decade-old assumptions. Rust is a modern language built for modern architectures, bringing a new approach to building software: focusing on performance, reliability, and security from the ground up. Experienced programmers will recognize much of the syntax, but old patterns won’t translate to new solutions.

Rust provides a unique platform not only to master a new technology, but also to understand the new foundations of software for modern systems. Every chapter in Rust From the Ground Up takes a practical, “show, don’t tell” approach: examining the original BSD sources for a well-known Unix CLI program and introducing enough Rust to build a fully functional copy. This book flattens Rust's learning curve, demonstrating how to build powerful applications which handle realistic conditions such as edge cases and errors. After reading this book, you will have gained the confidence and intuition to understand Rust and the new approaches to modern software rooted in real world examples.


Rust's most distinctive feature is its ownership system, which guarantees memory safety. It's possible to disable certain safety checks by designating a section of Rust code as unsafe (usually for performance reasons), but all of the code in this book is safe.


Its ownership system makes Rust particularly well suited for replacing existing programs written in the C language, which is notorious for producing programs with bugs caused by its lack of memory safety. Apple, Microsoft, and Google have reported that at least 70% of the security vulnerabilities in their C/C++ codebases are caused by memory safety bugs.

Borrow Checker

The Rust compiler's borrow checker has a reputation as being difficult to work with. The borrow checker validates the ownership and lifetimes of values in memory at compile time, without a garbage collector. New Rust programmers often feel like they are "fighting the borrow checker" until they build intuition about how ownership works.


Understanding ownership is hard, and sometimes the easiest way to get a Rust program to compile is by copying a value in memory, or using reference counting. This book tackles ownership head on, demonstrating clear strategies for resolving common issues with the borrow checker, enabling the reader to become productive and to write fully functional programs in Rust, without overwhelming them with more advanced concepts such as lifetimes.

Real World Code

The goal of this book is to teach a programmer with no Rust experience how to write production quality, idiomatic Rust code that safely handles real world edge cases and errors. There are no linked list exercises, made up examples (like FizzBuzz), demos (Mandelbrot), or sample code. Every chapter demonstrates how to write a real program by examining the original C source code for a classic BSD Unix CLI utility and incrementally building a fully functional version in Rust.

No C Required

Rust's syntax is designed to be familiar to programmers accustomed to languages such as C, C++, or Java, with curly braces {} around blocks of code, comments starting with // or surrounded by /* and */, and statements terminated with ;. But this book doesn't require specific experience in C programming; each chapter explains the syntax and functions used in the read-only C examples.


Each chapter rewrites a C program in stylish, idiomatic Rust. Instead of mechanical, line by line translations, the book emphasizes a functional programming style, heavily focusing on iterators and avoiding mutable state. For example, rewriting the head program (which prints the first 10 lines from each filename argument):


#include <stdio.h>
#include <stdlib.h>

main(int argc, char *argv[])
    FILE    *fp;
    int     ch;
    long    cnt, linecnt = 10;

    for (argv++; *argv; ++argv) {
        if ((fp = fopen(*argv, "r")) != NULL) {
            for (cnt = linecnt; cnt && !feof(fp); --cnt) {
                while ((ch = getc(fp)) != EOF) {
                    if (putchar(ch) == '\n') {

use std::env::args;
use std::fs::File;
use std::io::{BufRead, BufReader};

fn main() {
    let args = args().skip(1);
    let files = args.map(|arg| {
    let linecnt = 10;

    for file in files {
        for line in file.lines().take(linecnt).flatten() {
            println!("{}", line);

Table of Contents

  • Prelude
  • true and false
  • yes
  • head
  • wc
  • Posix cat
  • BSD cat
  • cut
  • rev
  • uniq