1 use core::fmt::{self, Debug, Formatter}; 2 use core::marker::PhantomData; 3 use core::mem::MaybeUninit; 4 5 #[cfg(feature = "alloc")] 6 use alloc::vec::Vec; 7 8 /// Slice backed by a potentially-unaligned pointer. 9 /// 10 /// This wrapper can be used to safely expose slices that are inside a 11 /// [`repr(packed)`] struct. The element type must be [`Copy`]. 12 /// 13 /// [`repr(packed)`]: https://doc.rust-lang.org/nomicon/other-reprs.html#reprpacked 14 #[derive(Clone)] 15 pub struct UnalignedSlice<'a, T: Copy> { 16 data: *const T, 17 len: usize, 18 _phantom_lifetime: PhantomData<&'a T>, 19 } 20 21 impl<'a, T: Copy> UnalignedSlice<'a, T> { 22 /// Create an `UnalignedSlice` from a raw pointer. The pointer must 23 /// not be dangling but can be unaligned. The `len` parameter is the 24 /// number of elements in the slice (not the number of bytes). 25 /// 26 /// # Safety 27 /// 28 /// The `data` pointer must point to a packed array of at least 29 /// `len` elements of type `T`. The pointer must remain valid for as 30 /// long as the `'a` lifetime. new(data: *const T, len: usize) -> Self31 pub const unsafe fn new(data: *const T, len: usize) -> Self { 32 Self { 33 data, 34 len, 35 _phantom_lifetime: PhantomData, 36 } 37 } 38 39 /// Returns true if the slice has a length of 0. 40 #[must_use] is_empty(&self) -> bool41 pub const fn is_empty(&self) -> bool { 42 self.len == 0 43 } 44 45 /// Get the underlying pointer, which may be unaligned. 46 #[must_use] as_ptr(&self) -> *const T47 pub const fn as_ptr(&self) -> *const T { 48 self.data 49 } 50 51 /// Returns the number of elements in the slice. 52 #[must_use] len(&self) -> usize53 pub const fn len(&self) -> usize { 54 self.len 55 } 56 57 /// Returns the element at `index`, or `None` if the `index` is out 58 /// of bounds. 59 #[must_use] get(&self, index: usize) -> Option<T>60 pub fn get(&self, index: usize) -> Option<T> { 61 if index < self.len { 62 Some(unsafe { self.data.add(index).read_unaligned() }) 63 } else { 64 None 65 } 66 } 67 68 /// Returns an iterator over the slice. 69 /// 70 /// The iterator yields all items from start to end. 71 #[must_use] iter(&'a self) -> UnalignedSliceIter<'a, T>72 pub const fn iter(&'a self) -> UnalignedSliceIter<'a, T> { 73 UnalignedSliceIter { 74 slice: self, 75 index: 0, 76 } 77 } 78 79 /// Copy the data to an aligned buffer. 80 /// 81 /// The length of `dest` must be the same as `self`. 82 /// 83 /// # Panics 84 /// 85 /// This function will panic if the two slices have different lengths. copy_to(&self, dest: &mut [T])86 pub fn copy_to(&self, dest: &mut [T]) { 87 if dest.len() != self.len { 88 panic!( 89 "source slice length ({}) does not match destination slice length ({})", 90 self.len(), 91 dest.len(), 92 ); 93 } 94 95 for (i, elem) in dest.iter_mut().enumerate() { 96 *elem = unsafe { self.data.add(i).read_unaligned() }; 97 } 98 } 99 100 /// Copy the data to an aligned [`MaybeUninit`] buffer. 101 /// 102 /// The length of `dest` must be the same as `self`. 103 /// 104 /// This function fully initializes the `dest` slice. 105 /// 106 /// # Panics 107 /// 108 /// This function will panic if the two slices have different lengths. copy_to_maybe_uninit(&self, dest: &mut [MaybeUninit<T>])109 pub fn copy_to_maybe_uninit(&self, dest: &mut [MaybeUninit<T>]) { 110 if dest.len() != self.len { 111 panic!( 112 "source slice length ({}) does not match destination slice length ({})", 113 self.len(), 114 dest.len(), 115 ); 116 } 117 118 for (i, elem) in dest.iter_mut().enumerate() { 119 unsafe { elem.write(self.data.add(i).read_unaligned()) }; 120 } 121 } 122 123 /// Copies `self` into a new `Vec`. 124 #[cfg(feature = "alloc")] 125 #[must_use] to_vec(&self) -> Vec<T>126 pub fn to_vec(&self) -> Vec<T> { 127 let len = self.len(); 128 let mut v = Vec::with_capacity(len); 129 unsafe { 130 self.copy_to_maybe_uninit(v.spare_capacity_mut()); 131 v.set_len(len); 132 } 133 v 134 } 135 } 136 137 impl<'a, T: Copy + Debug> Debug for UnalignedSlice<'a, T> { fmt(&self, f: &mut Formatter<'_>) -> fmt::Result138 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 139 f.debug_list().entries(self.iter()).finish() 140 } 141 } 142 143 #[cfg(feature = "alloc")] 144 impl<'a, T: Copy> From<UnalignedSlice<'a, T>> for Vec<T> { from(input: UnalignedSlice<'a, T>) -> Self145 fn from(input: UnalignedSlice<'a, T>) -> Self { 146 input.to_vec() 147 } 148 } 149 150 impl<'a, T: Copy> IntoIterator for UnalignedSlice<'a, T> { 151 type Item = T; 152 type IntoIter = UnalignedSliceIntoIter<'a, T>; 153 into_iter(self) -> Self::IntoIter154 fn into_iter(self) -> Self::IntoIter { 155 UnalignedSliceIntoIter { 156 slice: self, 157 index: 0, 158 } 159 } 160 } 161 162 impl<'a, T: Copy> IntoIterator for &'a UnalignedSlice<'a, T> { 163 type Item = T; 164 type IntoIter = UnalignedSliceIter<'a, T>; 165 into_iter(self) -> Self::IntoIter166 fn into_iter(self) -> Self::IntoIter { 167 self.iter() 168 } 169 } 170 171 /// Iterator for a [`UnalignedSlice`]. 172 #[derive(Debug)] 173 pub struct UnalignedSliceIntoIter<'a, T: Copy> { 174 slice: UnalignedSlice<'a, T>, 175 index: usize, 176 } 177 178 impl<'a, T: Copy> Iterator for UnalignedSliceIntoIter<'a, T> { 179 type Item = T; 180 next(&mut self) -> Option<T>181 fn next(&mut self) -> Option<T> { 182 let output = self.slice.get(self.index)?; 183 self.index += 1; 184 Some(output) 185 } 186 } 187 188 /// Iterator for a [`UnalignedSlice`] reference. 189 #[derive(Debug)] 190 pub struct UnalignedSliceIter<'a, T: Copy> { 191 slice: &'a UnalignedSlice<'a, T>, 192 index: usize, 193 } 194 195 impl<'a, T: Copy> Iterator for UnalignedSliceIter<'a, T> { 196 type Item = T; 197 next(&mut self) -> Option<T>198 fn next(&mut self) -> Option<T> { 199 let output = self.slice.get(self.index)?; 200 self.index += 1; 201 Some(output) 202 } 203 } 204 205 #[cfg(test)] 206 mod tests { 207 use super::*; 208 use alloc::vec::Vec; 209 210 #[test] test_unaligned_slice()211 fn test_unaligned_slice() { 212 #[rustfmt::skip] 213 let bytes: [u8; 13] = [ 214 // Extra byte to make the rest of the data unaligned. 215 0, 216 // First element. 217 0x10, 0x11, 0x12, 0x13, 218 // Second element. 219 0x20, 0x21, 0x22, 0x23, 220 // Third element. 221 0x30, 0x31, 0x32, 0x33, 222 ]; 223 224 // Skip past the first byte and create an unaligned `*const u32` pointer. 225 let bytes = &bytes[1..]; 226 let slice_ptr: *const u32 = bytes.as_ptr().cast(); 227 228 let slice: UnalignedSlice<u32> = unsafe { UnalignedSlice::new(slice_ptr, 0) }; 229 assert!(slice.is_empty()); 230 231 let slice: UnalignedSlice<u32> = unsafe { UnalignedSlice::new(slice_ptr, 3) }; 232 assert!(!slice.is_empty()); 233 assert_eq!(slice.len(), 3); 234 235 assert_eq!(slice.get(0), Some(0x13121110)); 236 assert_eq!(slice.get(1), Some(0x23222120)); 237 assert_eq!(slice.get(2), Some(0x33323130)); 238 assert_eq!(slice.get(3), None); 239 240 let mut copy = [0; 3]; 241 slice.copy_to(&mut copy); 242 assert_eq!(copy, [0x13121110, 0x23222120, 0x33323130]); 243 244 assert_eq!( 245 slice.iter().collect::<Vec<_>>(), 246 [0x13121110, 0x23222120, 0x33323130] 247 ); 248 249 assert_eq!( 250 slice.into_iter().collect::<Vec<_>>(), 251 [0x13121110, 0x23222120, 0x33323130] 252 ); 253 } 254 } 255