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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
//! `gep`, a better pointer arithmetic library.
//!
//! The name `gep` comes from LLVM's `getelementptr` instruction, the infamous
//! pointer arithmetic operation.
//!
//! This library provides two new pointer types, [`Ptr`] and [`NonNull`], which
//! have very similar APIs; they correspond to `*mut T` and
//! [`core::ptr::NonNull`], respectively.
//!
//! It also provides Rusty versions of [`memcpy`], [`memmove`], and [`memset`].
//!
//! # Offsets
//!
//! The premiere operation provided by this library is [`Ptr::at()`], which is
//! a generalized pointer arithmetic operation. For example, it will accept
//! any integer as input, not just `isize` (although, like [`<*mut T>::offset`],
//! the offset value must be valid to convert to `isize`).
//!
//! ```
//! # use gep::Ptr;
//! let mut ints = [0i32; 6];
//! let p = Ptr::from(&mut ints).element();
//!
//! unsafe {
//! // Pointer to the 4th element.
//! let q = p.at(4);
//! q.write(42);
//!
//! // Many operations have an `*_at` variant that internally calls .at().
//! q.write_at(-1, 55);
//! }
//!
//! assert_eq!(ints, [0, 0, 0, 55, 42, 0]);
//! ```
//!
//! By default, `at()` works on multiples of elements. To do a direct byte
//! offset instead, you can use the [`offset::ByteOffset`] type instead.
//!
//! ```
//! # use gep::Ptr;
//! use gep::offset::ByteOffset;
//!
//! let mut ints = [0i32; 6];
//! let p = Ptr::from(&mut ints).element();
//!
//! unsafe {
//! p.write_at(ByteOffset(4), 4242);
//! }
//!
//! assert_eq!(ints[1], 4242);
//! ```
//!
//! It's also possible to use "field offsets" (via the [`offset::Field`] type)
//! for accessing the fields of a struct directly, without creating intermediate
//! references to potentially invalid data.
//!
//! ```
//! # use gep::Ptr;
//! use gep::offset::Field;
//!
//! struct Foo {
//! a: i32,
//! b: [i32; 3],
//! }
//!
//! let foo = Foo { a: 0, b: [1, 2, 3] };
//!
//! let p = Ptr::from(&foo);
//! let value = unsafe {
//! p.read_at(gep::field!(Foo.b[1]))
//! };
//!
//! assert_eq!(value, 2);
//! ```
use mem;
pub use NonNull;
pub use Ptr;
/// Implemented for pointer-like types that are marked as `mut`.
///
/// This primarily exists to make it harder to accidentally pass a `&T` into the
/// `dst` argument of [`memcpy`].
///
/// # Safety
///
/// This trait should not be implemented by external crates.
pub unsafe
unsafe
unsafe
unsafe
unsafe
unsafe
/// Const check for whether a pointer is aligned. This operation is... somewhat
/// sketchy, so it's not exposed publicly. The ordinary is_aligned() functions
/// use non-const ptr2int conversions.
const
/// Performs a memory copy operation.
///
/// This operation is analogous to [`std::ptr::copy_nonoverlapping`], but uses
/// the common argument order from C.
///
/// Unlike C's `memcpy` and [`std::ptr::copy_nonoverlapping`], `count == 0` is
/// guaranteed to always succeed and do nothing.
///
/// # Safety
///
/// This function simply forwards to [`std::ptr::copy_nonoverlapping`], so its
/// safety contract must be upheld. Namely, `dst` and `src` must be valid for
/// writing and reading, respectively, `count * size_of::<T>()` must not
/// overflow, and the regions being copied between must not overlap.
pub unsafe
/// Performs an overlapping memory copy operation.
///
/// This operation is analogous to [`std::ptr::copy`], but uses
/// the common argument order from C.
///
/// Unlike C's `memmove` and [`std::ptr::copy`], `count == 0` is
/// guaranteed to always succeed and do nothing.
///
/// # Safety
///
/// This function simply forwards to [`std::ptr::copy`], so its
/// safety contract must be upheld. Namely, `dst` and `src` must be valid for
/// writing and reading, respectively, and `count * size_of::<T>()` must not
/// overflow.
pub unsafe
/// Performs a memory set operation.
///
/// This operation is analogous to [`std::ptr::write_bytes`].
///
/// Unlike C's `memset` and [`std::ptr::write_bytes`], `count == 0` is
/// guaranteed to always succeed and do nothing.
///
/// # Safety
///
/// This function simply forwards to [`std::ptr::copy`], so its
/// safety contract must be upheld. Namely, `dst` must be valid for
/// writing and `count * size_of::<T>()` must not
/// overflow.
pub unsafe