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