use redoubt_zero::{
FastZeroizable, RedoubtZero, ZeroizationProbe, ZeroizeMetadata, ZeroizeOnDropSentinel,
};
use crate::error::RedoubtOptionError;
#[derive(RedoubtZero, Default)]
pub struct RedoubtOption<T>
where
T: FastZeroizable + ZeroizeMetadata + ZeroizationProbe,
{
inner: Option<T>,
__sentinel: ZeroizeOnDropSentinel,
}
impl<T> RedoubtOption<T>
where
T: FastZeroizable + ZeroizeMetadata + ZeroizationProbe,
{
pub fn as_ref(&self) -> Result<&T, RedoubtOptionError> {
self.inner.as_ref().ok_or(RedoubtOptionError::Empty)
}
pub fn as_mut(&mut self) -> Result<&mut T, RedoubtOptionError> {
self.inner.as_mut().ok_or(RedoubtOptionError::Empty)
}
pub fn replace(&mut self, value: &mut T)
where
T: Default,
{
if let Some(old) = &mut self.inner {
old.fast_zeroize();
}
let mut new_value = T::default();
unsafe {
core::ptr::swap_nonoverlapping(value, &mut new_value, 1);
}
self.inner = Some(new_value);
value.fast_zeroize();
}
pub fn take(&mut self) -> Result<T, RedoubtOptionError> {
self.inner.take().ok_or(RedoubtOptionError::Empty)
}
pub fn is_some(&self) -> bool {
self.inner.is_some()
}
pub fn is_none(&self) -> bool {
self.inner.is_none()
}
#[inline(always)]
pub fn as_option(&self) -> &Option<T> {
&self.inner
}
#[inline(always)]
pub fn as_mut_option(&mut self) -> &mut Option<T> {
&mut self.inner
}
}