Rust Lessons

Learn Rust by staring at code.

Lesson 1: CWD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85


use std::env;           // (1) Imports `env` module; compile-time resolves
use std::ffi::OsString;  // (2) `OsString` - platform-native string, byte-based
use std::io::{self, Write}; // (3) Imports `io` module, `Write` trait for streams
use std::process;       // (4) Imports `process` module for program control

fn report_error(msg: &str, exit_code: i32,   // (5) `&str` - slice, immutable view into UTF-8 data
                show_error: bool) -> ! {      // (6) `bool` - single byte, conditional jumps at ASM level
    eprintln!("Error: {}", msg);          // (7) Macro `eprintln!` -> stderr, buffered output likely
                                        //     may involve mutex locks internally for sync.

    if show_error {                      // (8) `if` statement; CPU branch instruction, predicate eval
        let error = io::Error::last_os_error(); // (9) Syscall `last_os_error()` retrieves thread-local
                                            //     errno, potential context switch into kernel.
        eprintln!("System error: {} (code {})", // (10) Formatting via macros - alloc on stack? or heap?
                  error,
                  error.raw_os_error().unwrap_or(-1)); // (11) `.unwrap_or()` avoids panic, returns -1 on None
                                                    //      loss of error info if None ever occurs.
    }

    process::exit(exit_code);            // (12) `process::exit()` - system call `exit()`, process term.
                                        //      OS cleans resources; memory, file descriptors.
}

fn main() {                             // (13) `main` entry point, symbol resolved by linker at build.
    let args: Vec<OsString> = env::args_os().collect(); // (14) `env::args_os()` - syscall to get OS args as bytes
                                                    //      allocates `Vec` on heap, dynamic size.
                                                    //      `OsString` avoids UTF-8 validation overhead.
    let target_dir = if args.len() < 2 {       // (15) `args.len()` - reads `Vec` length from heap metadata
                                            //      integer compare instruction by CPU.
        // Default to user profile directory
        match env::var_os("USERPROFILE") {  // (16) `env::var_os()` - syscall `getenv` or similar for env var
                                            //      OS-specific call, kernel interaction, perf varies.
            Some(path) => path,             // (17) `Some(path)` - pattern match, compiler generates code
                                            //      for case analysis, avoids null pointer checks.
            None => report_error("Home directory not found.", // (18) `None` branch in `match`, jump to error path.
                                   1, false),      //      string literal in RODATA section of executable.
        }
    } else {                                 // (19) `else` branch, another conditional jump at ASM level.
        args[1].clone()                       // (20) `args[1]` - Vec index access, bound check potentially
                                            //      `clone()` triggers allocation if OsString not Copy.
                                            //      heap allocation possible for new OsString.
    };

    // Convert OsString to &str for error checking
    let target_str = target_dir.to_str().unwrap_or_else(|| { // (21) `to_str()` UTF-8 validation, creates &str slice
                                                            //      if valid, else `None`. Overhead for UTF-8.
        report_error("Invalid target directory encoding.", // (22) Closure for error handling on invalid UTF-8.
                       1, false)                     //      Closure compiled as separate anonymous function.
    });

    if target_str.is_empty() {               // (23) `target_str.is_empty()` - string slice metadata check
                                            //      very cheap, just a size comparison instruction.
        report_error("Invalid target directory.", // (24) String literal again in read-only memory.
                       1, false);             //      no heap allocation for string literal itself.
    }

    if let Err(e) = env::set_current_dir(&target_dir) { // (25) `env::set_current_dir()` - syscall `chdir()`, changes CWD
                                                        //      kernel operation, potential perf impact.
                                                        //      `&target_dir` - borrow, no ownership transfer.
        eprintln!("Failed to change directory to '{}'", // (26) Format string for error message, heap allocation?
                  target_str);                //      `target_str` is borrowed &str, no copy.
        report_error(&format!("{}", e), 1, true);    // (27) `format!("{}", e)` - creates new String on heap
                                                    //      alloc/dealloc overhead if error path taken often.
                                                    //      `&format!()` - borrow to report_error.
    }

    println!("Current directory is {}", target_str); // (28) `println!` macro, stdout, buffered output.
                                                    //      similar internals to `eprintln!`.
}