redoubt_codec_core/
codec_buffer.rs1use alloc::vec::Vec;
7
8use redoubt_alloc::AllockedVec;
9
10#[cfg(feature = "zeroize")]
11use redoubt_zero::{FastZeroizable, RedoubtZero, ZeroizeOnDropSentinel};
12
13use crate::error::RedoubtCodecBufferError;
14
15#[cfg_attr(feature = "zeroize", derive(RedoubtZero))]
16pub struct RedoubtCodecBuffer {
17 cursor: usize,
18 capacity: usize,
19 allocked_vec: AllockedVec<u8>,
20 #[cfg(feature = "zeroize")]
21 __sentinel: ZeroizeOnDropSentinel,
22}
23
24#[cfg(feature = "zeroize")]
25impl Drop for RedoubtCodecBuffer {
26 fn drop(&mut self) {
27 self.fast_zeroize();
28 }
29}
30
31impl Default for RedoubtCodecBuffer {
32 fn default() -> Self {
33 Self::with_capacity(0)
34 }
35}
36
37impl RedoubtCodecBuffer {
38 #[inline(always)]
39 fn debug_assert_invariant(&self) {
40 debug_assert!(
41 self.cursor <= self.capacity,
42 "Invariant violated: cursor ({}) <= capacity ({})",
43 self.cursor,
44 self.capacity
45 );
46 }
47
48 #[inline(always)]
49 pub fn with_capacity(capacity: usize) -> Self {
50 let allocked_vec = AllockedVec::<u8>::with_capacity(capacity);
51
52 Self {
53 cursor: 0,
54 capacity,
55 allocked_vec,
56 #[cfg(feature = "zeroize")]
57 __sentinel: ZeroizeOnDropSentinel::default(),
58 }
59 }
60
61 #[inline(always)]
62 pub fn realloc_with_capacity(&mut self, capacity: usize) {
63 self.allocked_vec.realloc_with_capacity(capacity);
64 self.allocked_vec.fill_with_default();
65
66 self.capacity = capacity;
67 self.cursor = 0;
68 }
69
70 #[inline(always)]
71 pub fn clear(&mut self) {
72 self.cursor = 0;
73 #[cfg(feature = "zeroize")]
74 self.allocked_vec.fast_zeroize();
75 }
76
77 #[inline(always)]
78 pub fn as_slice(&self) -> &[u8] {
79 unsafe { self.allocked_vec.as_capacity_slice() }
80 }
81
82 #[inline(always)]
83 pub fn as_mut_slice(&mut self) -> &mut [u8] {
84 unsafe { self.allocked_vec.as_capacity_mut_slice() }
85 }
86
87 #[inline(always)]
88 pub fn len(&self) -> usize {
89 unsafe { self.allocked_vec.as_capacity_slice().len() }
90 }
91
92 #[inline(always)]
93 pub fn is_empty(&self) -> bool {
94 self.len() == 0
95 }
96
97 #[inline(always)]
98 pub fn write<T>(&mut self, src: &mut T) -> Result<(), RedoubtCodecBufferError> {
99 let len = core::mem::size_of::<T>();
100
101 if self.cursor + len > self.capacity {
102 return Err(RedoubtCodecBufferError::CapacityExceeded);
103 }
104
105 unsafe {
106 let ptr = self.allocked_vec.as_mut_ptr().add(self.cursor);
107 core::ptr::copy_nonoverlapping(src as *const T as *const u8, ptr, len);
108 }
109 self.cursor += len;
110
111 self.debug_assert_invariant();
113
114 Ok(())
115 }
116
117 #[inline(always)]
118 pub fn write_slice<T>(&mut self, src: &mut [T]) -> Result<(), RedoubtCodecBufferError> {
119 let byte_len = core::mem::size_of_val(src);
120
121 if self.cursor + byte_len > self.capacity {
122 return Err(RedoubtCodecBufferError::CapacityExceeded);
123 }
124
125 unsafe {
126 let ptr = self.allocked_vec.as_mut_ptr().add(self.cursor);
127 core::ptr::copy_nonoverlapping(src.as_ptr() as *const u8, ptr, byte_len);
128 }
129 self.cursor += byte_len;
130
131 self.debug_assert_invariant();
133
134 Ok(())
135 }
136
137 #[inline(always)]
160 pub fn export_as_vec(&mut self) -> Vec<u8> {
161 let vec = self.as_slice().to_vec();
162 self.fast_zeroize();
163 vec
164 }
165}