Documentation

Documenting Safety Requirements

Every unsafe fn and unsafe trait in Rust has soundness invariants that the compiler cannot verify automatically. Documenting safety requirements under an explicit # Safety heading defines the exact contract that a caller (for an unsafe fn) or implementer (for an unsafe trait) must satisfy to prevent undefined behavior (UB).

 Declaration Side (`unsafe fn`):          Call Site (`unsafe { ... }`):
+------------------------------------+   +------------------------------------+
| /// # Safety                       |   | // SAFETY:                         |
| /// - `idx` must be `< self.len()` |<--| // - Checked `idx < slice.len()`   |
| /// - `ptr` must be aligned & valid|   | // - `ptr` comes from valid Box<T> |
| pub unsafe fn get_raw(...)         |   | unsafe { get_raw(...) }            |
+------------------------------------+   +------------------------------------+

# Safety on unsafe fn vs unsafe trait

The perspective of the # Safety section depends on whether you are documenting an unsafe fn or an unsafe trait:

Item Kind Who Must Uphold the Contract? What # Safety Must Specify
pub unsafe fn foo(...) The caller writing unsafe { foo(...) } Pointer validity, alignment, initialization, lifetime/aliasing bounds, and index/UTF-8 preconditions.
pub unsafe trait Bar The implementer writing unsafe impl Bar for T Type-level invariants (e.g., "All bit patterns of Self must be valid", or "Implementing methods must return the exact number of initialized bytes").

Writing a Precise # Safety Contract and Matching // SAFETY: Comment

Enforcing #![deny(clippy::missing_safety_doc)] and #![deny(clippy::undocumented_unsafe_blocks)] ensures that every unsafe fn lists its checklist under # Safety and every unsafe { ... } block addresses each bullet point in a // SAFETY: comment:

#![deny(clippy::missing_safety_doc)]

/// A marker trait for types that can be safely initialized from all-zero bytes.
///
/// # Safety
///
/// Implementers must guarantee that a value of `Self` whose memory representation
/// consists entirely of `0x00` bytes is a valid, initialized instance of `Self`
/// (i.e., `Self` must not contain references `&T`, `NonNull<T>`, `bool` if invalid,
/// or non-zero niches).
pub unsafe trait Zeroable: Sized {
    /// Returns a zero-initialized instance of `Self`.
    fn zeroed() -> Self {
        // SAFETY: The `unsafe impl Zeroable for Self` contract guarantees that
        // an all-zero byte pattern is a valid representation of `Self`.
        unsafe { std::mem::zeroed() }
    }
}

// SAFETY: `u64` is a primitive integer where `0` is a valid bit pattern.
unsafe impl Zeroable for u64 {}

/// Reads two distinct elements from `slice` at `i` and `j` without bounds checking.
///
/// # Safety
///
/// The caller must ensure that:
/// 1. `i < slice.len()` and `j < slice.len()`.
/// 2. `i != j` (if mutating), though for shared references `i == j` is sound.
pub unsafe fn get_pair_unchecked<T>(slice: &[T], i: usize, j: usize) -> (&T, &T) {
    debug_assert!(i < slice.len() && j < slice.len());
    // SAFETY: Caller guaranteed `i < slice.len()` and `j < slice.len()`.
    unsafe { (slice.get_unchecked(i), slice.get_unchecked(j)) }
}

fn main() {
    let zero_val = u64::zeroed();
    assert_eq!(zero_val, 0);

    let items = [10, 20, 30, 40];
    // SAFETY: `1 < 4` and `3 < 4`, satisfying both preconditions of `get_pair_unchecked`.
    let (a, b) = unsafe { get_pair_unchecked(&items, 1, 3) };
    println!("zero_val = {zero_val}, pair = ({a}, {b})");
}
zero_val = 0, pair = (20, 40)

Pairing debug_assert! with # Safety Preconditions

Inside an unsafe fn, always place debug_assert! checks for every quantifiable # Safety precondition (such as debug_assert!(idx < self.len()) or debug_assert!(ptr.is_aligned())). Those checks have zero runtime cost in release builds while catching precondition violations immediately during cargo test runs.