1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//! Provides a `#[safety]` attribute for generating a corresponding section in the documentation
//! and, if provided, checks for a constraint in debug builds.
extern crate proc_macro;
use TokenStream;
use quote;
use ;
/// 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 added to 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
///
/// ```
/// use safety_guard::safety;
///
/// #[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:
///
/// ```
/// use safety_guard::safety;
///
/// #[safety("`hash` must correspond to the `string`s hash value")]
/// unsafe fn add_string_with_hash(string: &str, hash: u64) -> u64 {
/// # unimplemented!()
/// // ...
/// }
/// ```
///
/// generates
///
/// ```
/// /// # Safety
/// /// - `hash` must correspond to the `string`s hash value
/// unsafe fn add_string_with_hash(string: &str, hash: u64) -> u64 {
/// # unimplemented!()
/// // ...
/// }
/// ```
///
/// It is also possible to use multiple `#[safety]` attributes:
///
/// ```
/// # use core::alloc::Layout;
/// use safety_guard::safety;
///
/// #[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 {
/// # unimplemented!()
/// // ...
/// }
/// ```
///
/// However, the documentation is generated in reversed order:
///
///
/// ```
/// # use core::alloc::Layout;
/// /// # 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`");
/// # unimplemented!()
/// // ...
/// }
/// ```