diff --git a/src/lib.rs b/src/lib.rs index a51ed8a..ebfc195 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -408,3 +408,47 @@ pub fn try_cast_slice_mut< ) -> Result<&mut [B], PodCastError> { unsafe { internal::try_cast_slice_mut(a) } } + +/// Fill all bytes of `target` with zeroes (see [`Zeroable`]). +/// +/// This is similar to `*target = Zeroable::zeroed()`, but guarantees that any +/// padding bytes in `target` are zeroed as well. +/// +/// See also [`fill_zero`], if you have a slice rather than a single value. +#[inline] +pub fn write_zero(target: &mut T) { + struct EnsureZeroWrite(*mut T); + impl Drop for EnsureZeroWrite { + #[inline(always)] + fn drop(&mut self) { + unsafe { + core::ptr::write_bytes(self.0, 0u8, 1); + } + } + } + unsafe { + let guard = EnsureZeroWrite(target); + core::ptr::drop_in_place(guard.0); + drop(guard); + } +} + +/// Fill all bytes of `slice` with zeroes (see [`Zeroable`]). +/// +/// This is similar to `slice.fill(Zeroable::zeroed())`, but guarantees that any +/// padding bytes in `slice` are zeroed as well. +/// +/// See also [`write_zero`], which zeroes all bytes of a single value rather +/// than a slice. +#[inline] +pub fn fill_zero(slice: &mut [T]) { + if core::mem::needs_drop::() { + // If `T` needs to be dropped then we have to do this one item at a time, in + // case one of the intermediate drops does a panic. + slice.iter_mut().for_each(write_zero); + } else { + // Otherwise we can be really fast and just fill everthing with zeros. + let len = core::mem::size_of_val::<[T]>(slice); + unsafe { core::ptr::write_bytes(slice.as_mut_ptr() as *mut u8, 0u8, len) } + } +}