redoubt_codec_core/collections/
array.rs1use redoubt_zero::{FastZeroizable, ZeroizeMetadata};
6
7use crate::codec_buffer::RedoubtCodecBuffer;
8use crate::error::{DecodeError, EncodeError, OverflowError};
9use crate::traits::{
10 BytesRequired, Decode, DecodeSlice, Encode, EncodeSlice, PreAlloc, TryDecode, TryEncode,
11};
12use crate::zeroizing::Zeroizing;
13
14use super::helpers::{header_size, process_header, write_header};
15
16#[cfg(feature = "zeroize")]
18#[cold]
19#[inline(never)]
20fn cleanup_encode_error<T: FastZeroizable + ZeroizeMetadata, const N: usize>(
21 arr: &mut [T; N],
22 buf: &mut RedoubtCodecBuffer,
23) {
24 arr.fast_zeroize();
25 buf.fast_zeroize();
26}
27
28#[cfg(feature = "zeroize")]
30#[cold]
31#[inline(never)]
32fn cleanup_decode_error<T: FastZeroizable + ZeroizeMetadata, const N: usize>(
33 arr: &mut [T; N],
34 buf: &mut &mut [u8],
35) {
36 arr.fast_zeroize();
37 redoubt_util::fast_zeroize_slice(buf);
38}
39
40impl<T, const N: usize> BytesRequired for [T; N]
41where
42 T: BytesRequired,
43{
44 fn encode_bytes_required(&self) -> Result<usize, OverflowError> {
45 let mut bytes_required = header_size();
46
47 for elem in self.iter() {
48 let new_bytes_required = bytes_required.wrapping_add(elem.encode_bytes_required()?);
49
50 if new_bytes_required < bytes_required {
51 return Err(OverflowError {
52 reason: "Array bytes_required overflow".into(),
53 });
54 }
55
56 bytes_required = new_bytes_required;
57 }
58
59 Ok(bytes_required)
60 }
61}
62
63impl<T, const N: usize> TryEncode for [T; N]
64where
65 T: EncodeSlice + BytesRequired + FastZeroizable + ZeroizeMetadata,
66{
67 fn try_encode_into(&mut self, buf: &mut RedoubtCodecBuffer) -> Result<(), EncodeError> {
68 let mut size = Zeroizing::new(N);
69 let mut bytes_required = Zeroizing::from(&mut self.encode_bytes_required()?);
70
71 write_header(buf, &mut size, &mut bytes_required)?;
72
73 T::encode_slice_into(self.as_mut_slice(), buf)
74 }
75}
76
77impl<T, const N: usize> Encode for [T; N]
78where
79 T: EncodeSlice + BytesRequired + FastZeroizable + ZeroizeMetadata,
80{
81 #[inline(always)]
82 fn encode_into(&mut self, buf: &mut RedoubtCodecBuffer) -> Result<(), EncodeError> {
83 let result = self.try_encode_into(buf);
84
85 #[cfg(feature = "zeroize")]
86 if result.is_err() {
87 cleanup_encode_error(self, buf);
88 } else {
89 self.fast_zeroize();
90 }
91
92 result
93 }
94}
95
96impl<T, const N: usize> EncodeSlice for [T; N]
97where
98 T: EncodeSlice + BytesRequired + FastZeroizable + ZeroizeMetadata,
99{
100 fn encode_slice_into(
101 slice: &mut [Self],
102 buf: &mut RedoubtCodecBuffer,
103 ) -> Result<(), EncodeError> {
104 for elem in slice.iter_mut() {
105 elem.encode_into(buf)?;
106 }
107
108 Ok(())
109 }
110}
111
112impl<T, const N: usize> TryDecode for [T; N]
113where
114 T: DecodeSlice + FastZeroizable + ZeroizeMetadata,
115{
116 #[inline(always)]
117 fn try_decode_from(&mut self, buf: &mut &mut [u8]) -> Result<(), DecodeError> {
118 let mut size = Zeroizing::from(&mut 0usize);
119
120 process_header(buf, &mut size)?;
121
122 if *size != N {
124 return Err(DecodeError::PreconditionViolated);
125 }
126
127 drop(size);
128
129 T::decode_slice_from(self.as_mut_slice(), buf)
130 }
131}
132
133impl<T, const N: usize> Decode for [T; N]
134where
135 T: DecodeSlice + FastZeroizable + ZeroizeMetadata,
136{
137 fn decode_from(&mut self, buf: &mut &mut [u8]) -> Result<(), DecodeError> {
138 let result = self.try_decode_from(buf);
139
140 #[cfg(feature = "zeroize")]
141 if result.is_err() {
142 cleanup_decode_error(self, buf);
143 }
144
145 result
146 }
147}
148
149impl<T, const N: usize> DecodeSlice for [T; N]
150where
151 T: DecodeSlice + FastZeroizable + ZeroizeMetadata,
152{
153 fn decode_slice_from(slice: &mut [Self], buf: &mut &mut [u8]) -> Result<(), DecodeError> {
154 for elem in slice.iter_mut() {
155 elem.decode_from(buf)?;
156 }
157
158 Ok(())
159 }
160}
161
162impl<T: Default, const N: usize> PreAlloc for [T; N]
166where
167 Self: Default,
168{
169 const ZERO_INIT: bool = false;
171
172 fn prealloc(&mut self, _size: usize) {
173 }
175}