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