use alloc::boxed::Box;
use core::fmt;
use core::mem;
use core::ops::{Deref, DerefMut};
use core::sync::atomic::{Ordering, compiler_fence};
use crate::collections::{collection_zeroed, to_zeroization_probe_dyn_ref};
use super::assert::assert_zeroize_on_drop;
use super::traits::{AssertZeroizeOnDrop, FastZeroizable, ZeroizationProbe};
use super::zeroize_on_drop_sentinel::ZeroizeOnDropSentinel;
pub struct ZeroizingGuard<T>
where
T: FastZeroizable + ZeroizationProbe + Default,
{
inner: Box<T>,
__sentinel: ZeroizeOnDropSentinel,
}
impl<T> fmt::Debug for ZeroizingGuard<T>
where
T: FastZeroizable + ZeroizationProbe + Default,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[REDACTED ZeroizingGuard]")
}
}
impl<T> ZeroizingGuard<T>
where
T: FastZeroizable + ZeroizationProbe + Default,
{
pub fn from_mut(value: &mut T) -> Self {
let mut boxed = Box::new(T::default());
mem::swap(&mut *boxed, value);
value.fast_zeroize();
Self {
inner: boxed,
__sentinel: ZeroizeOnDropSentinel::default(),
}
}
#[inline(always)]
pub fn from_default() -> Self {
let mut value = T::default();
Self::from_mut(&mut value)
}
}
impl<T> Deref for ZeroizingGuard<T>
where
T: FastZeroizable + ZeroizationProbe + Default,
{
type Target = T;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T> DerefMut for ZeroizingGuard<T>
where
T: FastZeroizable + ZeroizationProbe + Default,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl<T> FastZeroizable for ZeroizingGuard<T>
where
T: FastZeroizable + ZeroizationProbe + Default,
{
fn fast_zeroize(&mut self) {
self.inner.fast_zeroize();
compiler_fence(Ordering::SeqCst);
self.__sentinel.fast_zeroize();
compiler_fence(Ordering::SeqCst);
}
}
impl<T> AssertZeroizeOnDrop for ZeroizingGuard<T>
where
T: FastZeroizable + ZeroizationProbe + Default,
{
fn clone_sentinel(&self) -> ZeroizeOnDropSentinel {
self.__sentinel.clone()
}
fn assert_zeroize_on_drop(self) {
assert_zeroize_on_drop(self);
}
}
impl<T> ZeroizationProbe for ZeroizingGuard<T>
where
T: FastZeroizable + ZeroizationProbe + Default,
{
fn is_zeroized(&self) -> bool {
let fields: [&dyn ZeroizationProbe; 1] = [to_zeroization_probe_dyn_ref(&*self.inner)];
collection_zeroed(&mut fields.into_iter())
}
}
impl<T> Drop for ZeroizingGuard<T>
where
T: FastZeroizable + ZeroizationProbe + Default,
{
fn drop(&mut self) {
self.fast_zeroize();
}
}