Documenting Panics
Because Rust's type system does not encode whether a function can panic in its signature (unlike Result<T, E> for recoverable errors or unsafe fn for memory-safety preconditions), documenting panics under an explicit # Panics heading is the primary contract that warns callers about inputs or states that will unwind the thread.
/// Divides `a` by `b`.
///
/// # Panics
///
/// Panics if `b == 0` or if `a == i32::MIN && b == -1` (signed overflow).
pub fn div(a: i32, b: i32) -> i32 { ... }
What Belongs in a # Panics Section
A # Panics section should state every caller-observable condition that causes the function to panic, and—when a non-panicking try_* or checked_* alternative exists—link directly to that fallible counterpart via an intra-doc link:
| Panic Cause | How to Document It | Fallible Alternative to Link |
|---|---|---|
Precondition violation (assert!) |
State the exact parameter constraint (e.g., "Panics if min > max"). |
[`try_clamp`] or [`checked_new`] |
| Out-of-bounds index or slice split | State the valid index range ("Panics if index >= self.len()"). |
[`get`] / [`split_at_checked`] |
| UTF-8 character boundary violation | State "Panics if mid is not on a UTF-8 code point boundary". |
[`is_char_boundary`] |
| Unwrapping a poisoned lock or closed channel | State when internal synchronization can panic. | — |
Pairing # Panics with a should_panic Doc-Test
You can verify that the documented panic condition remains accurate by including a ```should_panic code block in the documentation:
/// Extracts a fixed-size window of length `window_size` starting at `offset`.
///
/// For a non-panicking version that returns [`None`] on out-of-bounds parameters,
/// see [`try_window`].
///
/// # Panics
///
/// - Panics if `window_size == 0`.
/// - Panics if `offset + window_size > slice.len()`.
///
/// # Examples
///
/// ```
/// # use my_crate::window;
/// let data = [10, 20, 30, 40, 50];
/// assert_eq!(window(&data, 1, 3), &[20, 30, 40]);
/// ```
///
/// Requesting a window past the end of the slice panics:
///
/// ```should_panic
/// # use my_crate::window;
/// let data = [10, 20, 30];
/// let _ = window(&data, 2, 2); // offset 2 + size 2 = 4 > len 3
/// ```
#[track_caller]
pub fn window<T>(slice: &[T], offset: usize, window_size: usize) -> &[T] {
assert!(window_size > 0, "window_size must be greater than 0");
let end = offset
.checked_add(window_size)
.expect("offset + window_size overflowed usize");
assert!(
end <= slice.len(),
"window range {offset}..{end} out of bounds for slice of length {}",
slice.len()
);
&slice[offset..end]
}
/// Non-panicking counterpart to [`window`]. Returns [`None`] if `window_size == 0`
/// or if `offset + window_size > slice.len()`.
pub fn try_window<T>(slice: &[T], offset: usize, window_size: usize) -> Option<&[T]> {
if window_size == 0 {
return None;
}
let end = offset.checked_add(window_size)?;
slice.get(offset..end)
}
fn main() {
let nums = [10, 20, 30, 40, 50];
println!("Window: {:?}", window(&nums, 1, 3));
println!("Try window: {:?}", try_window(&nums, 4, 3));
}
Window: [20, 30, 40]
Try window: None
Enforcing # Panics Documentation with Clippy
Enabling the Clippy lint clippy::missing_panics_doc (#![warn(clippy::missing_panics_doc)]) statically analyzes public functions for calls to panic!, assert!, assert_eq!, .unwrap(), and .expect(...), emitting a warning whenever a public function can panic without a # Panics doc heading.