Defining an unsafe function

/// Convert a nullable pointer to a reference.
///
/// Returns `None` when `p` is null, otherwise wraps `val` in `Some`.
fn ptr_to_ref<'a, T>(ptr: *mut T) -> Option<&'a mut T> {
    if ptr.is_null() {
        None
    } else {
        // SAFETY: `ptr` is non-null
        unsafe { Some(&mut *ptr) }
    }
}

“This looks as though it’s safe code, however it actually requires an unsafe block.”

Highlight the dereference operation, i.e. *p within the unsafe block.

“Callers must ensure that the ptr is null, or that it may be converted to a reference.

“It may be counter-intuitive, but many pointers cannot be converted to references.

“Among other issues, a pointer could be created that points to some arbitrary bits rather than a valid value. That’s not something that Rust allows and something that this function needs to protect itself against.

“So we, as API designers, have two paths. We can either try to assume responsibility for guarding against invalid inputs, or we can shift that responsibility to the caller with the unsafe keyword.”

“The first path is a difficult one. We’re accepting a generic type T, which is all possible types that implement Sized. That’s a lot of types!

“Therefore, the second path makes more sense.

Extra content (time permitting)

“By the way, if you’re interested in the details of pointers and what the rules of converting them to references are, the standard library has a lot of useful documentation. You should also look into the source code of many of the methods on std::pointer.

“For example, the ptr_to_ref function on this slide actually exists in the standard library as the as_mut method on pointers.”

Open the documentation for std::pointer.as_mut and highlight the Safety section.