# `#[require_unsafe_in_body]`
A procedural macro attribute to make an `unsafe fn` still require `unsafe` blocks in its body.
[![Latest version](https://img.shields.io/crates/v/require_unsafe_in_body.svg)](https://crates.io/crates/require_unsafe_in_body)
[![Documentation](https://docs.rs/require_unsafe_in_body/badge.svg)](https://docs.rs/require_unsafe_in_body)
![License](https://img.shields.io/crates/l/require_unsafe_in_body.svg)
## Motivation
Imagine having a function with a _narrow contract_, _i.e._, a function that can
trigger Undefined Behavior in some situations (incorrect inputs or call
context).
Rust safety design requires that this function be annotated `unsafe` if it is
part of a public API, and even when it is not, it is _highly advisable_ to do
so (code will be easier to maintain):
```rust
/// Swaps two values of a mutable slice, without checking that the indices are valid.
pub
unsafe // narrow contract
fn swap_indices_unchecked<T> (slice: &'_ mut [T], i: usize, j: usize)
{
let at_i: *mut T = slice.get_unchecked_mut(i);
let at_j: *mut T = slice.get_unchecked_mut(j);
::core::ptr::swap_nonoverlapping(at_i, at_j, 1)
}
```
As you can see, when a function is annotated `unsafe`, the body of the function
no longer requires special `unsafe` blocks around the most subtle things.
For instance, in this case, it may not be obvious that there are _two_ distinct
`unsafe` things happening:
- we are performing unchecked indexing, which would break if `i ≥ len` or
`j ≥ len`;
- we are asserting that `at_i` and `at_j` do not alias, which would break if
`i = j`.
Since misusing any of these invariants is wildly unsound, it would be better
if we could explicit _where_ each invariant is or may be used:
```rust
/// Swaps two values of a mutable slice, without checking that the indices are valid.
///
/// # Safety
///
/// The indices must be valid:
///
/// - `i ≠ j`
///
/// - `i < slice.len()`
///
/// - `j < slice.len()`
#[allow(unused_unsafe)]
pub
unsafe // narrow contract
fn swap_indices_unchecked<T> (slice: &'_ mut [T], i: usize, j: usize)
{
let at_i: *mut T = unsafe {
// Safety: `i < slice.len()`
debug_assert!(i < slice.len());
slice.get_unchecked_mut(i)
};
let at_j: *mut T = unsafe {
// Safety: `j < slice.len()`
debug_assert!(j < slice.len());
slice.get_unchecked_mut(j)
};
unsafe {
// Safety: `at_i` and `at_j` do not alias since `i ≠ j`
debug_assert_ne!(i, j);
::core::ptr::swap_nonoverlapping(at_i, at_j, 1);
}
}
```
Sadly, since these `unsafe` blocks are not required, not only do they trigger
`unused_unsafe` warnings, they can also be mistakenly missed without Rust
complaining whatsoever.
That's what `#[`[`require_unsafe_in_body`]`]` solves:
> **`#[`[`require_unsafe_in_body`]`]` "automagically removes" the intrinsic `unsafe`-ness (hygiene) of an `unsafe fn` body, thus making it _necessary_ to use `unsafe` scopes inside.**
## Example
The code
```rust,compile_fail
#[macro_use]
extern crate require_unsafe_in_body;
/// Swaps two values of a mutable slice, without checking that the indices are valid.
#[require_unsafe_in_body]
pub
unsafe // narrow contract
fn swap_indices_unchecked<T> (slice: &'_ mut [T], i: usize, j: usize)
{
let at_i: *mut T = slice.get_unchecked_mut(i);
let at_j: *mut T = slice.get_unchecked_mut(j);
::core::ptr::swap_nonoverlapping(at_i, at_j, 1);
}
```
yields the following compiler error:
```text
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
--> example.rs:11:24
|
--> example.rs:12:24
|
12 | let at_j: *mut T = slice.get_unchecked_mut(j);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
--> example.rs:13:5
|
|
= note: consult the function's documentation for information on how to avoid undefined behavior
For more information about this error, try `rustc --explain E0133`.
```
## Usage
1. Add this to your `Cargo.toml`:
```toml
[dependencies]
require_unsafe_in_body = "0.2.0"
```
2. Add this to your `lib.rs` (or `main.rs`):
```rust,ignore
#[macro_use]
extern crate require_unsafe_in_body;
```
3. You can then decorate:
- functions, with the `#[`[`require_unsafe_in_body`]`]` attribute;
- methods, with the `#[`[`require_unsafe_in_bodies`]`]` attribute **applied to the enclosing `impl` or `trait` block**.
[`require_unsafe_in_body`]: https://docs.rs/require_unsafe_in_body/0.2.1/require_unsafe_in_body/attr.require_unsafe_in_body.html
[`require_unsafe_in_bodies`]: https://docs.rs/require_unsafe_in_body/0.2.1/require_unsafe_in_body/attr.require_unsafe_in_bodies.html