use std::fmt;
use std::ops::{Deref, DerefMut};
use hide::hide_mem;
pub struct ClearOnDrop<T: Default, P: Deref<Target = T> + DerefMut> {
_place: P,
}
impl<T: Default, P: Deref<Target = T> + DerefMut> ClearOnDrop<T, P> {
#[inline]
pub fn new(place: P) -> Self {
ClearOnDrop { _place: place }
}
}
impl<T: Default, P: Deref<Target = T> + DerefMut + fmt::Debug> fmt::Debug for ClearOnDrop<T, P> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self._place, f)
}
}
impl<T: Default, P: Deref<Target = T> + DerefMut> Deref for ClearOnDrop<T, P> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
Deref::deref(&self._place)
}
}
impl<T: Default, P: Deref<Target = T> + DerefMut> DerefMut for ClearOnDrop<T, P> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
DerefMut::deref_mut(&mut self._place)
}
}
impl<T: Default, P: Deref<Target = T> + DerefMut> Drop for ClearOnDrop<T, P> {
#[inline]
fn drop(&mut self) {
let place = self.deref_mut();
*place = Default::default();
hide_mem::<T>(place);
}
}
#[cfg(test)]
mod tests {
use super::ClearOnDrop;
#[derive(Debug, Default)]
struct Place {
data: [u32; 4],
}
const DATA: [u32; 4] = [0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210];
#[test]
fn on_stack() {
let mut place: Place = Default::default();
{
let mut clear = ClearOnDrop::new(&mut place);
clear.data = DATA;
assert_eq!(clear.data, DATA);
}
assert_eq!(place.data, [0, 0, 0, 0]);
}
#[test]
fn on_box() {
let place: Box<Place> = Box::new(Default::default());
let mut clear = ClearOnDrop::new(place);
clear.data = DATA;
assert_eq!(clear.data, DATA);
}
}