safety-guard 0.1.9

#[safety] attribute to generate a corresponding doc entry and a debug assertion if a constraint is specified.
Documentation
Adds a `#[safety]` attribute for functions. The attribute adds a `# Safety` 
section to the documentation of the function and tests the given constraints
in debug builds.

The attribute has four different forms:

* `#[safety("Description")]`: Only the description is included in the documentation.
* `#[safety(assert(constraint), "Description")]`: `constraint` must evaluate to `true`.
* `#[safety(eq(lhs, rhs), "Description")]`: `lhs` and `rhs` needs to be equal
* `#[safety(ne(lhs, rhs), "Description")]`: `lhs` and `rhs` must not be equal

A function with a `#[safety]` attribute must be marked as `unsafe`. Otherwise 
a compile error is generated.

If `# Safety` already exists in the documentation, the heading is not added.

# Examples

    #[safety(assert(lhs.checked_add(rhs).is_some()), "`lhs` + `rhs` must not overflow")]
    unsafe fn add_unchecked(lhs: usize, rhs: usize) -> usize {
        lhs + rhs
    }

generates

    /// # Safety
    /// - `lhs` + `rhs` must not overflow
    unsafe fn add_unchecked(lhs: usize, rhs: usize) -> usize {
        debug_assert!(lhs.checked_add(rhs).is_some(), "`lhs` + `rhs` must not overflow");
        lhs + rhs
    }

Without a constraint, only the documentation is added:

    #[safety("`hash` must correspond to the `string`s hash value")]
    unsafe fn add_string_with_hash(string: &str, hash: u64) -> u64 {
        // ...
    }

generates

    /// # Safety
    /// - `hash` must correspond to the `string`s hash value
    unsafe fn add_string_with_hash(string: &str, hash: u64) -> u64 {
        // ...
    }

It is also possible to use multiple `#[safety]` attributes:

    #[safety(eq(ptr as usize % layout.align(), 0), "`layout` must *fit* the `ptr`")]
    #[safety(assert(new_size > 0), "`new_size` must be greater than zero")]
    #[safety(
        "`new_size`, when rounded up to the nearest multiple of `layout.align()`, must not \
        overflow (i.e., the rounded value must be less than `usize::MAX`)."
    )]
    unsafe fn realloc(
        ptr: *mut u8,
        layout: Layout,
        new_size: usize,
    ) -> *mut u8 {
        // ...
    }

However, the documentation is generated in reversed order:

    /// # Safety
    /// - `new_size`, when rounded up to the nearest multiple of `layout.align()`, must not
    ///   overflow (i.e., the rounded value must be less than `usize::MAX`).
    /// - `new_size` must be greater than zero
    /// - `layout` must *fit* the `ptr`
    unsafe fn realloc(
        ptr: *mut u8,
        layout: Layout,
        new_size: usize,
    ) -> *mut u8 {
        debug_assert!(new_size > 0, "`new_size` must be greater than zero");
        debug_assert_eq!(ptr as usize % layout.align(), 0, "`layout` must *fit* the `ptr`");
        // ...
    }