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}