ptr_iter/lib.rs
1#![no_std]
2#![warn(missing_docs)]
3
4//! A crate with iterators to simplify working with pointers.
5//!
6//! Constructing these iterators is unsafe, but once constructed the iteration
7//! itself is considered a safe operation.
8//!
9//! The two iterators themselves will iterate forever. The constructor functions
10//! apply the correct iterator adapters to limit the iteration to stay within
11//! safe bounds.
12//!
13//! ## Safety
14//! * You must always use the iterator before the pointer it's based upon
15//! becomes invalidated. This is the same logic as constructing a slice from a
16//! raw pointer: If you use a pointer to build a safe type and then invalidate
17//! the source pointer, the safe type itself will become invalid too.
18//! * The iteration is done with the pointer [`add`](https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.add)
19//! method, and so these iterators must only be constructed with pointers to
20//! valid allocations.
21
22/// An iterator based on a mutable pointer.
23#[derive(Debug, Clone, PartialEq, Eq)]
24#[repr(transparent)]
25pub struct MutPtrIter<T>(*mut T);
26impl<T> Iterator for MutPtrIter<T> {
27 type Item = *mut T;
28 #[inline]
29 fn next(&mut self) -> Option<Self::Item> {
30 let out = self.0;
31 self.0 = unsafe { self.0.add(1) };
32 Some(out)
33 }
34 #[inline]
35 fn size_hint(&self) -> (usize, Option<usize>) {
36 (usize::MAX, None)
37 }
38}
39impl<T> MutPtrIter<T> {
40 /// Iterates all pointers within the slice pointer given.
41 ///
42 /// ```rust
43 /// # use ptr_iter::MutPtrIter;
44 /// let mut arr: [u8; 4] = [5, 6, 7, 8];
45 /// let mut iter = unsafe { MutPtrIter::over_slice_ptr(&mut arr).map(|p| *p) };
46 /// assert_eq!(iter.next(), Some(5_u8));
47 /// assert_eq!(iter.next(), Some(6_u8));
48 /// assert_eq!(iter.next(), Some(7_u8));
49 /// assert_eq!(iter.next(), Some(8_u8));
50 /// assert_eq!(iter.next(), None);
51 /// assert_eq!(iter.next(), None);
52 /// ```
53 ///
54 /// ## Safety
55 /// * The slice pointer must point to a valid allocation.
56 /// * You agree ahead of time to not use the iterator after the pointer is
57 /// invalid.
58 #[inline]
59 pub unsafe fn over_slice_ptr(p: *mut [T]) -> core::iter::Take<Self> {
60 // Safety: the caller has to pass a valid pointer, so we can use
61 // new_unchecked because a null pointer is never valid. This appears to be
62 // the only stable way to get a slice pointer's length.
63 let len: usize = core::ptr::NonNull::new_unchecked(p).len();
64 Self(p as *mut T).take(len)
65 }
66}
67
68/// An iterator based on a constant pointer.
69#[derive(Debug, Clone, PartialEq, Eq)]
70#[repr(transparent)]
71pub struct ConstPtrIter<T>(*const T);
72impl<T> Iterator for ConstPtrIter<T> {
73 type Item = *const T;
74 #[inline]
75 fn next(&mut self) -> Option<Self::Item> {
76 let out = self.0;
77 self.0 = unsafe { self.0.add(1) };
78 Some(out)
79 }
80 #[inline]
81 fn size_hint(&self) -> (usize, Option<usize>) {
82 (usize::MAX, None)
83 }
84}
85impl<T> ConstPtrIter<T> {
86 /// Iterates all pointers within the slice pointer given.
87 ///
88 /// ```rust
89 /// # use ptr_iter::ConstPtrIter;
90 /// let arr: [u8; 4] = [5, 6, 7, 8];
91 /// let mut iter = unsafe { ConstPtrIter::over_slice_ptr(&arr).map(|p| *p) };
92 /// assert_eq!(iter.next(), Some(5_u8));
93 /// assert_eq!(iter.next(), Some(6_u8));
94 /// assert_eq!(iter.next(), Some(7_u8));
95 /// assert_eq!(iter.next(), Some(8_u8));
96 /// assert_eq!(iter.next(), None);
97 /// assert_eq!(iter.next(), None);
98 /// ```
99 ///
100 /// ## Safety
101 /// * The slice pointer must point to a valid allocation.
102 /// * You agree ahead of time to not use the iterator after the pointer is
103 /// invalid.
104 #[inline]
105 pub unsafe fn over_slice_ptr(p: *const [T]) -> core::iter::Take<Self> {
106 // Safety: the caller has to pass a valid pointer, so we can use
107 // new_unchecked because a null pointer is never valid. This appears to be
108 // the only stable way to get a slice pointer's length.
109 let len: usize = core::ptr::NonNull::new_unchecked(p as *mut [T]).len();
110 Self(p as *const T).take(len)
111 }
112
113 /// Reads successive pointer positions and returns values until the type's
114 /// default value is read.
115 ///
116 /// * The default value is *excluded* from the iterator's output sequence.
117 ///
118 /// This covers the common case of iterating "C String" style data, where the
119 /// data consists of an unknown number of non-zero elements and then a 0
120 /// marking the end of the sequence.
121 ///
122 /// ```rust
123 /// # use ptr_iter::ConstPtrIter;
124 /// let arr: &[u8; 5] = b"rust\0";
125 /// let mut iter = unsafe { ConstPtrIter::read_until_default(arr.as_ptr()) };
126 /// assert_eq!(iter.next(), Some(b'r'));
127 /// assert_eq!(iter.next(), Some(b'u'));
128 /// assert_eq!(iter.next(), Some(b's'));
129 /// assert_eq!(iter.next(), Some(b't'));
130 /// assert_eq!(iter.next(), None);
131 /// assert_eq!(iter.next(), None);
132 /// ```
133 ///
134 /// ## Safety
135 /// * The pointer must be valid for reads up to and including the position of
136 /// the default element.
137 /// * You agree ahead of time to not use the iterator after the pointer is
138 /// invalid.
139 #[inline]
140 pub unsafe fn read_until_default(
141 p: *const T,
142 ) -> impl Iterator<Item = T> + Clone
143 where
144 T: Copy + Default + PartialEq,
145 {
146 Self(p).map(|p| unsafe { *p }).take_while(|p| p != &T::default())
147 }
148}