1use crate::{InOutBuf, errors::OutIsTooSmallError};
2use core::{marker::PhantomData, slice};
3
4#[cfg(feature = "block-padding")]
5use {
6 crate::{InOut, errors::PadError},
7 block_padding::Padding,
8 hybrid_array::{Array, ArraySize},
9};
10
11pub struct InOutBufReserved<'inp, 'out, T> {
16 in_ptr: *const T,
17 out_ptr: *mut T,
18 in_len: usize,
19 out_len: usize,
20 _pd: PhantomData<(&'inp T, &'out mut T)>,
21}
22
23impl<'a, T> InOutBufReserved<'a, 'a, T> {
24 pub fn from_mut_slice(buf: &'a mut [T], msg_len: usize) -> Result<Self, OutIsTooSmallError> {
26 if msg_len > buf.len() {
27 return Err(OutIsTooSmallError);
28 }
29 let p = buf.as_mut_ptr();
30 let out_len = buf.len();
31 Ok(Self {
32 in_ptr: p,
33 out_ptr: p,
34 in_len: msg_len,
35 out_len,
36 _pd: PhantomData,
37 })
38 }
39}
40
41impl<T> InOutBufReserved<'_, '_, T> {
42 #[inline(always)]
64 pub unsafe fn from_raw(
65 in_ptr: *const T,
66 in_len: usize,
67 out_ptr: *mut T,
68 out_len: usize,
69 ) -> Self {
70 Self {
71 in_ptr,
72 out_ptr,
73 in_len,
74 out_len,
75 _pd: PhantomData,
76 }
77 }
78
79 #[inline(always)]
81 pub fn into_raw(self) -> (*const T, *mut T) {
82 (self.in_ptr, self.out_ptr)
83 }
84
85 #[inline(always)]
87 pub fn get_in_len(&self) -> usize {
88 self.in_len
89 }
90
91 #[inline(always)]
93 pub fn get_out_len(&self) -> usize {
94 self.out_len
95 }
96
97 pub fn split_reserved(&mut self) -> (InOutBuf<'_, '_, T>, &mut [T]) {
100 let in_len = self.get_in_len();
101 let out_len = self.get_out_len();
102 let in_ptr = self.get_in().as_ptr();
103 let out_ptr = self.get_out().as_mut_ptr();
104 let tail_len = out_len - in_len;
107 unsafe {
108 let body = InOutBuf::from_raw(in_ptr, out_ptr, in_len);
109 let tail = slice::from_raw_parts_mut(out_ptr.add(in_len), tail_len);
110 (body, tail)
111 }
112 }
113}
114
115impl<'inp, 'out, T> InOutBufReserved<'inp, 'out, T> {
116 pub fn from_slices(
118 in_buf: &'inp [T],
119 out_buf: &'out mut [T],
120 ) -> Result<Self, OutIsTooSmallError> {
121 if in_buf.len() > out_buf.len() {
122 return Err(OutIsTooSmallError);
123 }
124 Ok(Self {
125 in_ptr: in_buf.as_ptr(),
126 out_ptr: out_buf.as_mut_ptr(),
127 in_len: in_buf.len(),
128 out_len: out_buf.len(),
129 _pd: PhantomData,
130 })
131 }
132
133 #[inline(always)]
135 pub fn get_in(&self) -> &[T] {
136 unsafe { slice::from_raw_parts(self.in_ptr, self.in_len) }
137 }
138
139 #[inline(always)]
141 pub fn get_out(&mut self) -> &mut [T] {
142 unsafe { slice::from_raw_parts_mut(self.out_ptr, self.out_len) }
143 }
144
145 #[inline(always)]
147 pub fn into_out(self) -> &'out mut [T] {
148 unsafe { slice::from_raw_parts_mut(self.out_ptr, self.out_len) }
149 }
150}
151
152#[cfg(feature = "block-padding")]
153impl<'inp, 'out> InOutBufReserved<'inp, 'out, u8> {
154 #[inline(always)]
156 pub fn into_padded_blocks<P, BS>(self) -> Result<PaddedInOutBuf<'inp, 'out, BS>, PadError>
157 where
158 P: Padding,
159 BS: ArraySize,
160 {
161 let bs = BS::USIZE;
162 let blocks_len = self.in_len / bs;
163
164 use block_padding::PaddedData;
165 let (blocks, tail_block) = match P::pad_detached(self.get_in()) {
166 PaddedData::Pad { blocks, tail_block } => (blocks, Some(tail_block)),
167 PaddedData::NoPad { blocks } => (blocks, None),
168 PaddedData::Error => return Err(PadError),
169 };
170
171 assert_eq!(blocks.len(), blocks_len);
172
173 let out_len = self.out_len;
174 let (in_ptr, out_ptr) = self.into_raw();
175
176 let blocks = unsafe {
177 InOutBuf::from_raw(
178 in_ptr.cast::<Array<u8, BS>>(),
179 out_ptr.cast::<Array<u8, BS>>(),
180 blocks_len,
181 )
182 };
183
184 let Some(tail_block) = tail_block else {
185 let tail_inout = None;
186 return Ok(PaddedInOutBuf { blocks, tail_inout });
187 };
188
189 let blocks_byte_len = blocks_len * bs;
190 let reserve_len = out_len - blocks_byte_len;
191 if reserve_len < tail_block.len() {
192 return Err(PadError);
193 }
194 let tail_out: &mut Array<u8, BS> = unsafe {
196 let tail_out_ptr = out_ptr.add(blocks_byte_len);
197 &mut *(tail_out_ptr.cast())
198 };
199
200 let tail_inout = Some((tail_block, tail_out));
201
202 Ok(PaddedInOutBuf { blocks, tail_inout })
203 }
204}
205
206#[cfg(feature = "block-padding")]
208#[allow(clippy::type_complexity)]
209pub struct PaddedInOutBuf<'inp, 'out, BS: ArraySize> {
210 blocks: InOutBuf<'inp, 'out, Array<u8, BS>>,
211 tail_inout: Option<(Array<u8, BS>, &'out mut Array<u8, BS>)>,
212}
213
214#[cfg(feature = "block-padding")]
215impl<'out, BS: ArraySize> PaddedInOutBuf<'_, 'out, BS> {
216 #[inline(always)]
218 pub fn get_blocks(&mut self) -> InOutBuf<'_, '_, Array<u8, BS>> {
219 self.blocks.reborrow()
220 }
221
222 #[inline(always)]
226 pub fn get_tail_block(&mut self) -> Option<InOut<'_, '_, Array<u8, BS>>> {
227 self.tail_inout.as_mut().map(|(in_block, out_block)| {
228 let in_block = &*in_block;
229 let out_block = &mut **out_block;
230 InOut::from((in_block, out_block))
231 })
232 }
233
234 #[inline(always)]
236 pub fn into_out(self) -> &'out [u8] {
237 let total_blocks = if self.tail_inout.is_some() {
238 self.blocks.len() + 1
239 } else {
240 self.blocks.len()
241 };
242 let res_len = BS::USIZE * total_blocks;
243 let (_, out_ptr) = self.blocks.into_raw();
244 unsafe { slice::from_raw_parts(out_ptr as *const u8, res_len) }
247 }
248}