use alloc::vec::Vec;
use core::ops::{Deref, DerefMut};
use redoubt_zero::{
FastZeroizable, RedoubtZero, ZeroizationProbe, ZeroizeMetadata, ZeroizeOnDropSentinel,
};
#[derive(RedoubtZero)]
pub struct RedoubtVec<T>
where
T: FastZeroizable + ZeroizeMetadata + ZeroizationProbe,
{
inner: Vec<T>,
__sentinel: ZeroizeOnDropSentinel,
}
#[cfg(any(test, feature = "test-utils"))]
impl<T: FastZeroizable + ZeroizeMetadata + ZeroizationProbe + PartialEq> PartialEq
for RedoubtVec<T>
{
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
#[cfg(any(test, feature = "test-utils"))]
impl<T: FastZeroizable + ZeroizeMetadata + Eq + ZeroizationProbe> Eq for RedoubtVec<T> {}
impl<T> core::fmt::Debug for RedoubtVec<T>
where
T: FastZeroizable + ZeroizeMetadata + ZeroizationProbe,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("RedoubtVec")
.field("data", &"REDACTED")
.field("len", &self.len())
.field("capacity", &self.capacity())
.finish()
}
}
impl<T> RedoubtVec<T>
where
T: FastZeroizable + ZeroizeMetadata + ZeroizationProbe,
{
pub fn new() -> Self {
Self {
inner: Vec::new(),
__sentinel: ZeroizeOnDropSentinel::default(),
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
inner: Vec::with_capacity(capacity),
__sentinel: ZeroizeOnDropSentinel::default(),
}
}
pub fn from_mut_slice(src: &mut [T]) -> Self
where
T: Default,
{
let mut vec = Self::new();
vec.extend_from_mut_slice(src);
vec
}
#[inline]
pub fn len(&self) -> usize {
self.inner.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
#[inline]
pub fn capacity(&self) -> usize {
self.inner.capacity()
}
#[cold]
#[inline(never)]
fn grow_to(&mut self, min_capacity: usize) {
let current_len = self.len();
let new_capacity = min_capacity.next_power_of_two();
let mut tmp = Vec::with_capacity(current_len);
unsafe {
core::ptr::copy_nonoverlapping(self.inner.as_ptr(), tmp.as_mut_ptr(), current_len);
tmp.set_len(current_len);
}
self.inner.fast_zeroize();
self.inner.clear();
self.inner.shrink_to_fit();
self.inner.reserve_exact(new_capacity);
unsafe {
core::ptr::copy_nonoverlapping(tmp.as_ptr(), self.inner.as_mut_ptr(), current_len);
self.inner.set_len(current_len);
}
tmp.fast_zeroize();
}
#[inline(always)]
fn maybe_grow_to(&mut self, min_capacity: usize) {
if self.capacity() >= min_capacity {
return;
}
self.grow_to(min_capacity);
}
pub fn extend_from_mut_slice(&mut self, src: &mut [T])
where
T: Default,
{
self.maybe_grow_to(self.len() + src.len());
unsafe {
let src_ptr = src.as_ptr();
let dst_ptr = self.inner.as_mut_ptr().add(self.len());
core::ptr::copy_nonoverlapping(src_ptr, dst_ptr, src.len());
self.inner.set_len(self.len() + src.len());
}
src.fast_zeroize();
}
pub fn replace_from_mut_slice(&mut self, src: &mut [T])
where
T: Default,
{
self.clear();
self.extend_from_mut_slice(src);
}
pub fn drain_value(&mut self, src: &mut T)
where
T: Default,
{
self.maybe_grow_to(self.len() + 1);
let item = core::mem::take(src);
self.inner.push(item);
src.fast_zeroize();
}
pub fn clear(&mut self) {
self.inner.fast_zeroize();
self.inner.clear();
}
pub fn as_slice(&self) -> &[T] {
&self.inner
}
pub fn as_mut_slice(&mut self) -> &mut [T] {
&mut self.inner
}
pub fn as_vec(&self) -> &Vec<T> {
&self.inner
}
pub fn as_mut_vec(&mut self) -> &mut Vec<T> {
&mut self.inner
}
#[cfg(feature = "default_init")]
pub fn default_init_to_size(&mut self, size: usize)
where
T: Default,
{
self.clear();
self.maybe_grow_to(size);
if T::CAN_BE_BULK_ZEROIZED {
self.inner.fast_zeroize();
unsafe {
self.inner.set_len(size);
}
} else {
for _ in 0..size {
self.inner.push(T::default());
}
self.inner.fast_zeroize();
}
debug_assert_eq!(self.len(), size);
}
}
impl<T> Default for RedoubtVec<T>
where
T: FastZeroizable + ZeroizeMetadata + ZeroizationProbe,
{
fn default() -> Self {
Self::new()
}
}
impl<T> Deref for RedoubtVec<T>
where
T: FastZeroizable + ZeroizeMetadata + ZeroizationProbe,
{
type Target = [T];
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T> DerefMut for RedoubtVec<T>
where
T: FastZeroizable + ZeroizeMetadata + ZeroizationProbe,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}