//! Implements methods to write a vector type to a slice. macro_rules! impl_slice_write_to_slice { ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { impl $id { /// Writes the values of the vector to the `slice`. /// /// # Panics /// /// If `slice.len() < Self::lanes()` or `&slice[0]` is not /// aligned to an `align_of::()` boundary. #[inline] pub fn write_to_slice_aligned(self, slice: &mut [$elem_ty]) { unsafe { assert!(slice.len() >= $elem_count); let target_ptr = slice.get_unchecked_mut(0) as *mut $elem_ty; assert_eq!( target_ptr .align_offset(crate::mem::align_of::()), 0 ); self.write_to_slice_aligned_unchecked(slice); } } /// Writes the values of the vector to the `slice`. /// /// # Panics /// /// If `slice.len() < Self::lanes()`. #[inline] pub fn write_to_slice_unaligned(self, slice: &mut [$elem_ty]) { unsafe { assert!(slice.len() >= $elem_count); self.write_to_slice_unaligned_unchecked(slice); } } /// Writes the values of the vector to the `slice`. /// /// # Safety /// /// If `slice.len() < Self::lanes()` or `&slice[0]` is not /// aligned to an `align_of::()` boundary, the behavior is /// undefined. #[inline] pub unsafe fn write_to_slice_aligned_unchecked( self, slice: &mut [$elem_ty], ) { debug_assert!(slice.len() >= $elem_count); let target_ptr = slice.get_unchecked_mut(0) as *mut $elem_ty; debug_assert_eq!( target_ptr.align_offset(crate::mem::align_of::()), 0 ); #[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)] *(target_ptr as *mut Self) = self; } /// Writes the values of the vector to the `slice`. /// /// # Safety /// /// If `slice.len() < Self::lanes()` the behavior is undefined. #[inline] pub unsafe fn write_to_slice_unaligned_unchecked( self, slice: &mut [$elem_ty], ) { debug_assert!(slice.len() >= $elem_count); let target_ptr = slice.get_unchecked_mut(0) as *mut $elem_ty as *mut u8; let self_ptr = &self as *const Self as *const u8; crate::ptr::copy_nonoverlapping( self_ptr, target_ptr, crate::mem::size_of::(), ); } } test_if! { $test_tt: paste::item! { // Comparisons use integer casts within mantissa^1 range. #[allow(clippy::float_cmp)] pub mod [<$id _slice_write_to_slice>] { use super::*; use crate::iter::Iterator; #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn write_to_slice_unaligned() { let mut unaligned = [0 as $elem_ty; $id::lanes() + 1]; let vec = $id::splat(42 as $elem_ty); vec.write_to_slice_unaligned(&mut unaligned[1..]); for (index, &b) in unaligned.iter().enumerate() { if index == 0 { assert_eq!(b, 0 as $elem_ty); } else { assert_eq!(b, 42 as $elem_ty); assert_eq!(b, vec.extract(index - 1)); } } } // FIXME: wasm-bindgen-test does not support #[should_panic] // #[cfg_attr(not(target_arch = "wasm32"), test)] // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg(not(target_arch = "wasm32"))] #[test] #[should_panic] fn write_to_slice_unaligned_fail() { let mut unaligned = [0 as $elem_ty; $id::lanes() + 1]; let vec = $id::splat(42 as $elem_ty); vec.write_to_slice_unaligned(&mut unaligned[2..]); } union A { data: [$elem_ty; 2 * $id::lanes()], _vec: $id, } #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn write_to_slice_aligned() { let mut aligned = A { data: [0 as $elem_ty; 2 * $id::lanes()], }; let vec = $id::splat(42 as $elem_ty); unsafe { vec.write_to_slice_aligned( &mut aligned.data[$id::lanes()..] ); for (idx, &b) in aligned.data.iter().enumerate() { if idx < $id::lanes() { assert_eq!(b, 0 as $elem_ty); } else { assert_eq!(b, 42 as $elem_ty); assert_eq!( b, vec.extract(idx - $id::lanes()) ); } } } } // FIXME: wasm-bindgen-test does not support #[should_panic] // #[cfg_attr(not(target_arch = "wasm32"), test)] // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg(not(target_arch = "wasm32"))] #[test] #[should_panic] fn write_to_slice_aligned_fail_lanes() { let mut aligned = A { data: [0 as $elem_ty; 2 * $id::lanes()], }; let vec = $id::splat(42 as $elem_ty); unsafe { vec.write_to_slice_aligned( &mut aligned.data[2 * $id::lanes()..] ) }; } // FIXME: wasm-bindgen-test does not support #[should_panic] // #[cfg_attr(not(target_arch = "wasm32"), test)] // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg(not(target_arch = "wasm32"))] #[test] #[should_panic] fn write_to_slice_aligned_fail_align() { unsafe { let mut aligned = A { data: [0 as $elem_ty; 2 * $id::lanes()], }; // get a pointer to the front of data let ptr: *mut $elem_ty = aligned.data.as_mut_ptr() as *mut $elem_ty; // offset pointer by one element let ptr = ptr.wrapping_add(1); if ptr.align_offset(crate::mem::align_of::<$id>()) == 0 { // the pointer is properly aligned, so // write_to_slice_aligned won't fail here (e.g. // this can happen for i128x1). So we panic to // make the "should_fail" test pass: panic!("ok"); } // create a slice - this is safe, because the // elements of the slice exist, are properly // initialized, and properly aligned: let s: &mut [$elem_ty] = slice::from_raw_parts_mut(ptr, $id::lanes()); // this should always panic because the slice // alignment does not match the alignment // requirements for the vector type: let vec = $id::splat(42 as $elem_ty); vec.write_to_slice_aligned(s); } } } } } }; }