Splits

OS in Rust

Homework

  • Homeworks are due on the Friday after the week they correspond to lecture.
  • So 9 days after the corresponding lab.

Citation

Requirements

Preamble

Unsafe

  • Here is an unsafe function named dangerous that doesn’t do anything in its body:
    unsafe fn dangerous() {}

    unsafe {
        dangerous();
    }
  • We must call the dangerous function within a separate unsafe block.
  • If we try to call dangerous without the unsafe block, we’ll get an error.

Creating a Safe Abstraction over Unsafe Code

  • Just because a function contains unsafe code doesn’t mean we need to mark the entire function as unsafe.
    • This blew my mind.
  • In fact, wrapping unsafe code in a safe function is a common abstraction.
  • As an example, let’s study the split_at_mut function from the standard library, which requires some unsafe code.

No Safe Way

People scared of Portland refer to Safeway I shop at as the “Unsafeway” which I think is hilarious

  • We’ll explore how we might implement it.
  • This safe method is defined on mutable slices:
    • It takes one slice and makes it two by splitting the slice at the index given as an argument.
  • Here’s an example.
    let mut v = vec![1, 2, 3, 4, 5, 6];

    let r = &mut v[..];

    let (a, b) = r.split_at_mut(3);
  • There’s no safe way to do this.

This won’t work

fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
    let len = values.len();

    assert!(mid <= len);

    (&mut values[..mid], &mut values[mid..])
}
  • It explodes:

Enter the Borrow Checker

  • Rust’s borrow checker can’t understand that we’re borrowing different parts of the slice
    • It only knows that we’re borrowing from the same slice twice.
  • Borrowing different parts of a slice is fundamentally okay because the two slices aren’t overlapping, but…
    • rustc isn’t smart enough to know this.
  • When we know code is okay, but Rust doesn’t, it’s time to reach for unsafe code.
fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {

    let ptr = values.as_mut_ptr();
    let mid = std::cmp::min(values.len(), mid);

    unsafe {
        (
            std::slice::from_raw_parts_mut(ptr, mid),
            std::slice::from_raw_parts_mut(ptr.add(mid), values.len() - mid),
        )
    }
}

Deliverable

  • Create a crate which:
    • Contains an unsafe split_at_mut that you have written in lib.rs
    • Contains a usage of split_at_mut in main.rs
    • Abstracts all unsafe blocks to lib.rs but successfully calls unsafe code from main.rs
    • You may use the exact provided code but most put it together in a way that actually works with cargo r
    • You should be able to explain the difference between my code and the Rustbook code if you consult both.