Prep: Control Flow — 01r¶
Session: Fri Aug 28, 1h30 · Exercises: 01r_control_flow · Prep time: ~30 min · Lecture: Rust I: Values, Types, and Control Flow
What you will build¶
Thursday's functions computed one thing and handed it back; Friday's have to decide, repeat, and do arithmetic near the edge of a number. You will write a few small usize functions on your laptop that are the kernel's page-allocator arithmetic with the pointers removed: keep an address inside the board's 128 MiB of RAM (0x8000_0000..0x8800_0000), walk a range one 4 KiB page at a time, and move an address up to a page boundary, both plainly and in a form that reports failure instead of wrapping.
Concepts you need¶
- Expressions vs statements — a block's value is its last expression; a trailing semicolon makes it
()— Lecture §4 · Lecture Key Concepts ifas an expression — no truthiness, braces required, every branch the same type — Lecture §6- Three loops and half-open ranges —
a..bexcludesb; RAM isKERNBASE..PHYSTOP— Lecture §7 · Cheatsheet: Physical memory map breakwith a value — onlyloopcan, because its every exit is abreak— Lecture §7- Integer overflow — debug panics, release wraps; the same bug either way — Lecture §8 · Lecture Problem 4
wrapping_*,checked_*,saturating_*— say what you mean — Lecture §8 Saying what you meanOption, just enough —checked_addreturnsOption<usize>; take it apart withmatch— Lecture §8 Option · Rust for Systems §4Option<T>
Read before class¶
| What | Time |
|---|---|
Lecture §4, §6, §7 (expressions, if, the three loops) |
12 min |
Lecture §8 (overflow, the explicit methods, Option) |
10 min |
| Lecture Practice Problem 4, on paper, before opening the solution | 5 min |
| Cheatsheet: Constants you must not misremember | 3 min |
Mental model¶
Find the largest power of two that fits in a u8:
let mut p: u8 = 1;
let top = loop {
match p.checked_mul(2) {
Some(next) => p = next, // still fits: keep doubling
None => break p, // the loop's value: 128
}
};
loop has no exit except break, so it can hand back a value; checked_mul returns an Option<u8>, and the None arm is the exit. With plain p * 2 the stopping rule vanishes: the eighth doubling is 256, not a u8. Under cargo test that line panics with attempt to multiply with overflow; a release build wraps it to 0, and 0 * 2 never overflows, so the loop never ends.
Check yourself¶
fn cap(x: u32) -> u32 { if x > 9 { 9 } else { x }; }— what does the compiler say, and why?Answer
error[E0308]: mismatched types, expectedu32, found(). The semicolon discards theifexpression's value, so the body is(). Delete it and theifbecomes the tail expression.- The allocator's loop tests
p + PGSIZE <= stop, notp < stop. What changes whenstopis not page-aligned?Answer
p < stopwould hand out a final page that runs paststop. The allocator deals in whole pages, so the test asks "does the whole page fit?", the same half-open convention asKERNBASE..PHYSTOP. let m = usize::MAX; m + 1— what happens underoslings run, and under--release? What would you write instead?Answer
Debug: a panic,attempt to add with overflow. Release: silently0.wrapping_add(1)when wrapping is the intent (a counter, a ring index);checked_add(1)when the caller must handleNone;saturating_add(1)when clamping is sane. Plain+is for arithmetic you can prove cannot overflow.
What "done" looks like¶
oslings run is green, then oslings submit before you leave. Not green? Submit anyway (substantial credit), then finish by Monday 11:59 pm and submit again.
If you finish early¶
Rustlings: the 03_if and 04_primitive_types groups, then a peek ahead at 12_options. 100 Exercises To Learn Rust: Chapter 2, "A Basic Calculator" (if/else, panics, while and for, overflow, the wrapping/checked/saturating methods).