1 //! Implements methods to write a vector type to a slice. 2 3 macro_rules! impl_slice_write_to_slice { 4 ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { 5 impl $id { 6 /// Writes the values of the vector to the `slice`. 7 /// 8 /// # Panics 9 /// 10 /// If `slice.len() < Self::lanes()` or `&slice[0]` is not 11 /// aligned to an `align_of::<Self>()` boundary. 12 #[inline] 13 pub fn write_to_slice_aligned(self, slice: &mut [$elem_ty]) { 14 unsafe { 15 assert!(slice.len() >= $elem_count); 16 let target_ptr = 17 slice.get_unchecked_mut(0) as *mut $elem_ty; 18 assert_eq!( 19 target_ptr 20 .align_offset(crate::mem::align_of::<Self>()), 21 0 22 ); 23 self.write_to_slice_aligned_unchecked(slice); 24 } 25 } 26 27 /// Writes the values of the vector to the `slice`. 28 /// 29 /// # Panics 30 /// 31 /// If `slice.len() < Self::lanes()`. 32 #[inline] 33 pub fn write_to_slice_unaligned(self, slice: &mut [$elem_ty]) { 34 unsafe { 35 assert!(slice.len() >= $elem_count); 36 self.write_to_slice_unaligned_unchecked(slice); 37 } 38 } 39 40 /// Writes the values of the vector to the `slice`. 41 /// 42 /// # Safety 43 /// 44 /// If `slice.len() < Self::lanes()` or `&slice[0]` is not 45 /// aligned to an `align_of::<Self>()` boundary, the behavior is 46 /// undefined. 47 #[inline] 48 pub unsafe fn write_to_slice_aligned_unchecked( 49 self, slice: &mut [$elem_ty], 50 ) { 51 debug_assert!(slice.len() >= $elem_count); 52 let target_ptr = slice.get_unchecked_mut(0) as *mut $elem_ty; 53 debug_assert_eq!( 54 target_ptr.align_offset(crate::mem::align_of::<Self>()), 55 0 56 ); 57 58 #[allow(clippy::cast_ptr_alignment)] 59 #[allow(clippy::cast_ptr_alignment)] 60 #[allow(clippy::cast_ptr_alignment)] 61 #[allow(clippy::cast_ptr_alignment)] 62 *(target_ptr as *mut Self) = self; 63 } 64 65 /// Writes the values of the vector to the `slice`. 66 /// 67 /// # Safety 68 /// 69 /// If `slice.len() < Self::lanes()` the behavior is undefined. 70 #[inline] 71 pub unsafe fn write_to_slice_unaligned_unchecked( 72 self, slice: &mut [$elem_ty], 73 ) { 74 debug_assert!(slice.len() >= $elem_count); 75 let target_ptr = 76 slice.get_unchecked_mut(0) as *mut $elem_ty as *mut u8; 77 let self_ptr = &self as *const Self as *const u8; 78 crate::ptr::copy_nonoverlapping( 79 self_ptr, 80 target_ptr, 81 crate::mem::size_of::<Self>(), 82 ); 83 } 84 } 85 86 test_if! { 87 $test_tt: 88 paste::item! { 89 // Comparisons use integer casts within mantissa^1 range. 90 #[allow(clippy::float_cmp)] 91 pub mod [<$id _slice_write_to_slice>] { 92 use super::*; 93 use crate::iter::Iterator; 94 95 #[cfg_attr(not(target_arch = "wasm32"), test)] 96 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 97 fn write_to_slice_unaligned() { 98 let mut unaligned = [0 as $elem_ty; $id::lanes() + 1]; 99 let vec = $id::splat(42 as $elem_ty); 100 vec.write_to_slice_unaligned(&mut unaligned[1..]); 101 for (index, &b) in unaligned.iter().enumerate() { 102 if index == 0 { 103 assert_eq!(b, 0 as $elem_ty); 104 } else { 105 assert_eq!(b, 42 as $elem_ty); 106 assert_eq!(b, vec.extract(index - 1)); 107 } 108 } 109 } 110 111 // FIXME: wasm-bindgen-test does not support #[should_panic] 112 // #[cfg_attr(not(target_arch = "wasm32"), test)] 113 // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 114 #[cfg(not(target_arch = "wasm32"))] 115 #[test] 116 #[should_panic] 117 fn write_to_slice_unaligned_fail() { 118 let mut unaligned = [0 as $elem_ty; $id::lanes() + 1]; 119 let vec = $id::splat(42 as $elem_ty); 120 vec.write_to_slice_unaligned(&mut unaligned[2..]); 121 } 122 123 union A { 124 data: [$elem_ty; 2 * $id::lanes()], 125 _vec: $id, 126 } 127 128 #[cfg_attr(not(target_arch = "wasm32"), test)] 129 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 130 fn write_to_slice_aligned() { 131 let mut aligned = A { 132 data: [0 as $elem_ty; 2 * $id::lanes()], 133 }; 134 let vec = $id::splat(42 as $elem_ty); 135 unsafe { 136 vec.write_to_slice_aligned( 137 &mut aligned.data[$id::lanes()..] 138 ); 139 for (idx, &b) in aligned.data.iter().enumerate() { 140 if idx < $id::lanes() { 141 assert_eq!(b, 0 as $elem_ty); 142 } else { 143 assert_eq!(b, 42 as $elem_ty); 144 assert_eq!( 145 b, vec.extract(idx - $id::lanes()) 146 ); 147 } 148 } 149 } 150 } 151 152 // FIXME: wasm-bindgen-test does not support #[should_panic] 153 // #[cfg_attr(not(target_arch = "wasm32"), test)] 154 // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 155 #[cfg(not(target_arch = "wasm32"))] 156 #[test] 157 #[should_panic] 158 fn write_to_slice_aligned_fail_lanes() { 159 let mut aligned = A { 160 data: [0 as $elem_ty; 2 * $id::lanes()], 161 }; 162 let vec = $id::splat(42 as $elem_ty); 163 unsafe { 164 vec.write_to_slice_aligned( 165 &mut aligned.data[2 * $id::lanes()..] 166 ) 167 }; 168 } 169 170 // FIXME: wasm-bindgen-test does not support #[should_panic] 171 // #[cfg_attr(not(target_arch = "wasm32"), test)] 172 // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 173 #[cfg(not(target_arch = "wasm32"))] 174 #[test] 175 #[should_panic] 176 fn write_to_slice_aligned_fail_align() { 177 unsafe { 178 let mut aligned = A { 179 data: [0 as $elem_ty; 2 * $id::lanes()], 180 }; 181 182 // get a pointer to the front of data 183 let ptr: *mut $elem_ty 184 = aligned.data.as_mut_ptr() as *mut $elem_ty; 185 // offset pointer by one element 186 let ptr = ptr.wrapping_add(1); 187 188 if ptr.align_offset(crate::mem::align_of::<$id>()) 189 == 0 { 190 // the pointer is properly aligned, so 191 // write_to_slice_aligned won't fail here (e.g. 192 // this can happen for i128x1). So we panic to 193 // make the "should_fail" test pass: 194 panic!("ok"); 195 } 196 197 // create a slice - this is safe, because the 198 // elements of the slice exist, are properly 199 // initialized, and properly aligned: 200 let s: &mut [$elem_ty] 201 = slice::from_raw_parts_mut(ptr, $id::lanes()); 202 // this should always panic because the slice 203 // alignment does not match the alignment 204 // requirements for the vector type: 205 let vec = $id::splat(42 as $elem_ty); 206 vec.write_to_slice_aligned(s); 207 } 208 } 209 } 210 } 211 } 212 }; 213 } 214