use std::boxed::Box;
use std::ops::{Deref,DerefMut};
use std::convert::{AsRef,AsMut};
use std::borrow::{Borrow,BorrowMut};
#[derive(Debug)]
pub struct ZeroDrop<T>(Box<T>) where T: Copy;
impl<T> Drop for ZeroDrop<T> where T: Copy {
#[inline(never)]
fn drop(&mut self) {
let s: &mut T = self.0.deref_mut();
unsafe { ::std::intrinsics::volatile_set_memory::<T>(s,0,1) }
}
}
impl<T> ZeroDrop<T> where T: Copy {
pub fn new_insecure(t: T) -> ZeroDrop<T> {
ZeroDrop(Box::new(t))
}
pub fn new_box(b: Box<T>) -> ZeroDrop<T> {
ZeroDrop(b)
}
pub unsafe fn new_uninitialized() -> ZeroDrop<T> {
ZeroDrop(Box::new(::std::mem::uninitialized::<T>()))
}
pub fn new_copy(t: &T) -> ZeroDrop<T> {
let mut b = Box::new(unsafe { ::std::mem::uninitialized::<T>() });
unsafe { ::std::ptr::copy_nonoverlapping::<T>(t,b.deref_mut(),1) }
ZeroDrop(b)
}
pub unsafe fn zero_out(&mut self) {
let s: &mut T = self.0.deref_mut();
::std::intrinsics::volatile_set_memory::<T>(s,0,1)
}
pub fn new_zeroed() -> ZeroDrop<T> {
let mut b = Box::new(unsafe { ::std::mem::uninitialized::<T>() });
unsafe { ::std::intrinsics::volatile_set_memory::<T>(b.deref_mut(),0,1) }
ZeroDrop(b)
}
}
impl<T> Default for ZeroDrop<T> where T: Copy+Default {
fn default() -> ZeroDrop<T> {
ZeroDrop(Default::default())
}
}
impl<T> Clone for ZeroDrop<T> where T: Copy {
fn clone(&self) -> ZeroDrop<T> {
ZeroDrop(self.0.clone())
}
fn clone_from(&mut self, source: &ZeroDrop<T>) {
self.0.clone_from(&source.0);
}
}
impl<T> Deref for ZeroDrop<T> where T: Copy {
type Target = T;
fn deref(&self) -> &T {
self.0.deref()
}
}
impl<T> DerefMut for ZeroDrop<T> where T: Copy {
fn deref_mut(&mut self) -> &mut T {
self.0.deref_mut()
}
}
impl<T> AsRef<T> for ZeroDrop<T> where T: Copy {
fn as_ref(&self) -> &T {
self.0.as_ref()
}
}
impl<T> AsMut<T> for ZeroDrop<T> where T: Copy {
fn as_mut(&mut self) -> &mut T {
self.0.as_mut()
}
}
impl<T> Borrow<T> for ZeroDrop<T> where T: Copy {
fn borrow(&self) -> &T {
self.0.borrow()
}
}
impl<T> BorrowMut<T> for ZeroDrop<T> where T: Copy {
fn borrow_mut(&mut self) -> &mut T {
self.0.borrow_mut()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zeroing_drops() {
let p : *const [u8; 32];
let s = ZeroDrop::new_insecure([3u8; 32]);
p = s.deref();
::std::mem::drop(s);
unsafe { assert_eq!(*p,[0u8; 32]); }
}
#[test]
#[should_panic(expected = "assertion failed")]
fn not_droped() {
let p : *const [u8; 32];
let s = ZeroDrop::new_insecure([3u8; 32]);
p = s.deref();
unsafe { assert_eq!(*p,[0u8; 32]); }
}
}