rawpointer/lib.rs
1// Copyright 2016-2019 bluss and rawpointer developers.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8#![no_std]
9
10
11//! Rawpointer adds extra utility methods to raw pointers `*const T`, `*mut T`
12//! and `NonNull<T>`.
13//!
14//! Features include:
15//!
16//! - Strided offsets - [`.stride_offset(stride,
17//! index)`](PointerExt::stride_offset) make it easy to compute
18//! pointer offsets where the index is unsigned and the stride is signed.
19//!
20//! - Offsetting methods in general for `NonNull`, since it does not have these
21//! from libcore
22//!
23//! - Post- and preincrement and post- and predecrement methods
24//!
25//! - For `p++` use [`p.post_inc()`](PointerExt::post_inc).
26//! - For `++p` use [`p.pre_inc()`](PointerExt::pre_inc).
27//! - For `p--` use [`p.post_dec()`](PointerExt::post_dec).
28//! - For `--p` use [`p.pre_dec()`](PointerExt::pre_dec).
29//!
30//! ```rust
31//! use rawpointer::PointerExt;
32//!
33//! unsafe {
34//! // In this example:
35//! // Use .post_inc() to iterate and overwrite the first four
36//! // elements of the array.
37//!
38//! let mut xs = [0; 16];
39//! let mut ptr = xs.as_mut_ptr();
40//! let end = ptr.offset(4);
41//! let mut i = 0;
42//! while ptr != end {
43//! *ptr.post_inc() = i;
44//! i += 1;
45//! }
46//! assert_eq!(&xs[..8], &[0, 1, 2, 3, 0, 0, 0, 0]);
47//! }
48//! ```
49//!
50//! ## Safety
51//!
52//! See the Rust [core::ptr] documentation for more information.
53//!
54//! ## Rust Version
55//!
56//! This version of the crate requires Rust 1.26 or later
57
58use core::mem::size_of;
59use core::ptr::NonNull;
60
61/// Return the number of elements of `T` from `start` to `end`.<br>
62/// Return the arithmetic difference if `T` is zero size.
63#[inline(always)]
64pub fn ptrdistance<T>(start: *const T, end: *const T) -> usize {
65 let size = size_of::<T>();
66 if size == 0 {
67 (end as usize).wrapping_sub(start as usize)
68 } else {
69 (end as usize - start as usize) / size
70 }
71}
72
73/// Extension methods for raw pointers
74pub trait PointerExt : Copy {
75 unsafe fn offset(self, i: isize) -> Self;
76
77 unsafe fn add(self, i: usize) -> Self {
78 self.offset(i as isize)
79 }
80
81 unsafe fn sub(self, i: usize) -> Self {
82 self.offset((i as isize).wrapping_neg())
83 }
84
85 /// Increment the pointer by 1, and return its new value.
86 ///
87 /// Equivalent to the C idiom `++ptr`.
88 #[inline(always)]
89 unsafe fn pre_inc(&mut self) -> Self {
90 *self = self.offset(1);
91 *self
92 }
93
94 /// Increment the pointer by 1, but return its old value.
95 ///
96 /// Equivalent to the C idiom `ptr++`.
97 #[inline(always)]
98 unsafe fn post_inc(&mut self) -> Self {
99 let current = *self;
100 *self = self.offset(1);
101 current
102 }
103
104 /// Decrement the pointer by 1, and return its new value.
105 ///
106 /// Equivalent to the C idiom `--ptr`.
107 #[inline(always)]
108 unsafe fn pre_dec(&mut self) -> Self {
109 *self = self.offset(-1);
110 *self
111 }
112
113 /// Decrement the pointer by 1, but return its old value.
114 ///
115 /// Equivalent to the C idiom `ptr--`.
116 #[inline(always)]
117 unsafe fn post_dec(&mut self) -> Self {
118 let current = *self;
119 *self = self.offset(-1);
120 current
121 }
122
123 /// Increment by 1
124 #[inline(always)]
125 unsafe fn inc(&mut self) {
126 *self = self.offset(1);
127 }
128
129 /// Decrement by 1
130 #[inline(always)]
131 unsafe fn dec(&mut self) {
132 *self = self.offset(-1);
133 }
134
135 /// Offset the pointer by `s` multiplied by `index`.
136 #[inline(always)]
137 unsafe fn stride_offset(self, s: isize, index: usize) -> Self {
138 self.offset(s * index as isize)
139 }
140}
141
142impl<T> PointerExt for *const T {
143 #[inline(always)]
144 unsafe fn offset(self, i: isize) -> Self {
145 self.offset(i)
146 }
147
148 // Call inherent version of add/sub
149 #[inline]
150 unsafe fn add(self, i: usize) -> Self {
151 self.add(i)
152 }
153
154 #[inline]
155 unsafe fn sub(self, i: usize) -> Self {
156 self.sub(i)
157 }
158}
159
160impl<T> PointerExt for *mut T {
161 #[inline(always)]
162 unsafe fn offset(self, i: isize) -> Self {
163 self.offset(i)
164 }
165
166 #[inline]
167 unsafe fn add(self, i: usize) -> Self {
168 self.add(i)
169 }
170
171 #[inline]
172 unsafe fn sub(self, i: usize) -> Self {
173 self.sub(i)
174 }
175}
176
177/// `NonNull<T>` supports the same offsetting methods under the same
178/// safety constraints as the other raw pointer implementations.
179///
180/// There is no difference - both when offsetting `*mut T` and `NonNull<T>`,
181/// the offset is only well defined if we remain inside the same object or
182/// one-past the end, and we can never land in a null pointer while obeying
183/// those rules.
184impl<T> PointerExt for NonNull<T> {
185 #[inline(always)]
186 unsafe fn offset(self, i: isize) -> Self {
187 NonNull::new_unchecked(self.as_ptr().offset(i))
188 }
189}
190
191
192#[cfg(test)]
193mod tests {
194 use super::PointerExt;
195 use core::ptr::NonNull;
196
197 #[test]
198 fn it_works() {
199 unsafe {
200 let mut xs = [0; 16];
201 let mut ptr = xs.as_mut_ptr();
202 let end = ptr.offset(4);
203 let mut i = 0;
204 while ptr != end {
205 *ptr.post_inc() = i;
206 i += 1;
207 }
208 assert_eq!(&xs[..8], &[0, 1, 2, 3, 0, 0, 0, 0]);
209 }
210 }
211
212 #[test]
213 fn nonnull() {
214 unsafe {
215 let mut xs = [0; 16];
216 let mut ptr = NonNull::new(xs.as_mut_ptr()).unwrap();
217 let end = ptr.offset(4);
218 let mut i = 0;
219 while ptr != end {
220 *ptr.post_inc().as_ptr() = i;
221 i += 1;
222 }
223 assert_eq!(&xs[..8], &[0, 1, 2, 3, 0, 0, 0, 0]);
224 }
225 }
226
227 #[test]
228 fn nonnull_sub() {
229 unsafe {
230 // Test NonNull<T> .sub(1) iteration and equivalence to *mut T
231 let mut xs = [0; 16];
232 let mut ptr = xs.as_mut_ptr().add(xs.len());
233 let nptr = NonNull::new(xs.as_mut_ptr()).unwrap();
234 let mut nend = nptr.add(xs.len());
235 let mut i = 0;
236 while nptr != nend {
237 nend = nend.sub(1);
238 ptr = ptr.sub(1);
239 assert_eq!(nend.as_ptr(), ptr);
240 *nend.as_ptr() = i;
241 i += 1;
242 }
243 assert_eq!(&xs[..8], &[15, 14, 13, 12, 11, 10, 9, 8]);
244 }
245 }
246}