1 #[allow(unused_imports)]
2 use alloc::vec::Vec;
3
4 use crate::fastcpy::slice_copy;
5
6 /// Returns a Sink implementation appropriate for outputing up to `required_capacity`
7 /// bytes at `vec[offset..offset+required_capacity]`.
8 /// It can be either a `SliceSink` (pre-filling the vec with zeroes if necessary)
9 /// when the `safe-decode` feature is enabled, or `VecSink` otherwise.
10 /// The argument `pos` defines the initial output position in the Sink.
11 #[inline]
12 #[cfg(feature = "frame")]
vec_sink_for_compression( vec: &mut Vec<u8>, offset: usize, pos: usize, required_capacity: usize, ) -> SliceSink13 pub fn vec_sink_for_compression(
14 vec: &mut Vec<u8>,
15 offset: usize,
16 pos: usize,
17 required_capacity: usize,
18 ) -> SliceSink {
19 return {
20 vec.resize(offset + required_capacity, 0);
21 SliceSink::new(&mut vec[offset..], pos)
22 };
23 }
24
25 /// Returns a Sink implementation appropriate for outputing up to `required_capacity`
26 /// bytes at `vec[offset..offset+required_capacity]`.
27 /// It can be either a `SliceSink` (pre-filling the vec with zeroes if necessary)
28 /// when the `safe-decode` feature is enabled, or `VecSink` otherwise.
29 /// The argument `pos` defines the initial output position in the Sink.
30 #[cfg(feature = "frame")]
31 #[inline]
vec_sink_for_decompression( vec: &mut Vec<u8>, offset: usize, pos: usize, required_capacity: usize, ) -> SliceSink32 pub fn vec_sink_for_decompression(
33 vec: &mut Vec<u8>,
34 offset: usize,
35 pos: usize,
36 required_capacity: usize,
37 ) -> SliceSink {
38 return {
39 vec.resize(offset + required_capacity, 0);
40 SliceSink::new(&mut vec[offset..], pos)
41 };
42 }
43
44 pub trait Sink {
45 /// Returns a raw ptr to the first unfilled byte of the Sink. Analogous to `[pos..].as_ptr()`.
46 #[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
pos_mut_ptr(&mut self) -> *mut u847 unsafe fn pos_mut_ptr(&mut self) -> *mut u8;
48
49 /// read byte at position
byte_at(&mut self, pos: usize) -> u850 fn byte_at(&mut self, pos: usize) -> u8;
51
52 /// Pushes a byte to the end of the Sink.
53 #[cfg(feature = "safe-encode")]
push(&mut self, byte: u8)54 fn push(&mut self, byte: u8);
55
56 #[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
base_mut_ptr(&mut self) -> *mut u857 unsafe fn base_mut_ptr(&mut self) -> *mut u8;
58
pos(&self) -> usize59 fn pos(&self) -> usize;
60
capacity(&self) -> usize61 fn capacity(&self) -> usize;
62
63 #[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
set_pos(&mut self, new_pos: usize)64 unsafe fn set_pos(&mut self, new_pos: usize);
65
66 #[cfg(feature = "safe-decode")]
extend_with_fill(&mut self, byte: u8, len: usize)67 fn extend_with_fill(&mut self, byte: u8, len: usize);
68
69 /// Extends the Sink with `data`.
extend_from_slice(&mut self, data: &[u8])70 fn extend_from_slice(&mut self, data: &[u8]);
71
extend_from_slice_wild(&mut self, data: &[u8], copy_len: usize)72 fn extend_from_slice_wild(&mut self, data: &[u8], copy_len: usize);
73
74 /// Copies `len` bytes starting from `start` to the end of the Sink.
75 /// # Panics
76 /// Panics if `start` >= `pos`.
77 #[cfg(feature = "safe-decode")]
extend_from_within(&mut self, start: usize, wild_len: usize, copy_len: usize)78 fn extend_from_within(&mut self, start: usize, wild_len: usize, copy_len: usize);
79
80 #[cfg(feature = "safe-decode")]
extend_from_within_overlapping(&mut self, start: usize, num_bytes: usize)81 fn extend_from_within_overlapping(&mut self, start: usize, num_bytes: usize);
82 }
83
84 /// SliceSink is used as target to de/compress data into a preallocated and possibly uninitialized
85 /// `&[u8]`
86 /// space.
87 ///
88 /// # Handling of Capacity
89 /// Extend methods will panic if there's insufficient capacity left in the Sink.
90 ///
91 /// # Invariants
92 /// - Bytes `[..pos()]` are always initialized.
93 pub struct SliceSink<'a> {
94 /// The working slice, which may contain uninitialized bytes
95 output: &'a mut [u8],
96 /// Number of bytes in start of `output` guaranteed to be initialized
97 pos: usize,
98 }
99
100 impl<'a> SliceSink<'a> {
101 /// Creates a `Sink` backed by the given byte slice.
102 /// `pos` defines the initial output position in the Sink.
103 /// # Panics
104 /// Panics if `pos` is out of bounds.
105 #[inline]
new(output: &'a mut [u8], pos: usize) -> Self106 pub fn new(output: &'a mut [u8], pos: usize) -> Self {
107 // SAFETY: Caller guarantees that all elements of `output[..pos]` are initialized.
108 let _ = &mut output[..pos]; // bounds check pos
109 SliceSink { output, pos }
110 }
111 }
112
113 impl<'a> Sink for SliceSink<'a> {
114 /// Returns a raw ptr to the first unfilled byte of the Sink. Analogous to `[pos..].as_ptr()`.
115 #[inline]
116 #[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
pos_mut_ptr(&mut self) -> *mut u8117 unsafe fn pos_mut_ptr(&mut self) -> *mut u8 {
118 self.base_mut_ptr().add(self.pos()) as *mut u8
119 }
120
121 /// Pushes a byte to the end of the Sink.
122 #[inline]
byte_at(&mut self, pos: usize) -> u8123 fn byte_at(&mut self, pos: usize) -> u8 {
124 self.output[pos]
125 }
126
127 /// Pushes a byte to the end of the Sink.
128 #[inline]
129 #[cfg(feature = "safe-encode")]
push(&mut self, byte: u8)130 fn push(&mut self, byte: u8) {
131 self.output[self.pos] = byte;
132 self.pos += 1;
133 }
134
135 #[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
base_mut_ptr(&mut self) -> *mut u8136 unsafe fn base_mut_ptr(&mut self) -> *mut u8 {
137 self.output.as_mut_ptr()
138 }
139
140 #[inline]
pos(&self) -> usize141 fn pos(&self) -> usize {
142 self.pos
143 }
144
145 #[inline]
capacity(&self) -> usize146 fn capacity(&self) -> usize {
147 self.output.len()
148 }
149
150 #[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
151 #[inline]
set_pos(&mut self, new_pos: usize)152 unsafe fn set_pos(&mut self, new_pos: usize) {
153 debug_assert!(new_pos <= self.capacity());
154 self.pos = new_pos;
155 }
156
157 #[inline]
158 #[cfg(feature = "safe-decode")]
extend_with_fill(&mut self, byte: u8, len: usize)159 fn extend_with_fill(&mut self, byte: u8, len: usize) {
160 self.output[self.pos..self.pos + len].fill(byte);
161 self.pos += len;
162 }
163
164 /// Extends the Sink with `data`.
165 #[inline]
extend_from_slice(&mut self, data: &[u8])166 fn extend_from_slice(&mut self, data: &[u8]) {
167 self.extend_from_slice_wild(data, data.len())
168 }
169
170 #[inline]
extend_from_slice_wild(&mut self, data: &[u8], copy_len: usize)171 fn extend_from_slice_wild(&mut self, data: &[u8], copy_len: usize) {
172 assert!(copy_len <= data.len());
173 slice_copy(data, &mut self.output[self.pos..(self.pos) + data.len()]);
174 self.pos += copy_len;
175 }
176
177 /// Copies `len` bytes starting from `start` to the end of the Sink.
178 /// # Panics
179 /// Panics if `start` >= `pos`.
180 #[inline]
181 #[cfg(feature = "safe-decode")]
extend_from_within(&mut self, start: usize, wild_len: usize, copy_len: usize)182 fn extend_from_within(&mut self, start: usize, wild_len: usize, copy_len: usize) {
183 self.output.copy_within(start..start + wild_len, self.pos);
184 self.pos += copy_len;
185 }
186
187 #[inline]
188 #[cfg(feature = "safe-decode")]
189 #[cfg_attr(nightly, optimize(size))] // to avoid loop unrolling
extend_from_within_overlapping(&mut self, start: usize, num_bytes: usize)190 fn extend_from_within_overlapping(&mut self, start: usize, num_bytes: usize) {
191 let offset = self.pos - start;
192 for i in start + offset..start + offset + num_bytes {
193 self.output[i] = self.output[i - offset];
194 }
195 self.pos += num_bytes;
196 }
197 }
198
199 /// PtrSink is used as target to de/compress data into a preallocated and possibly uninitialized
200 /// `&[u8]`
201 /// space.
202 ///
203 ///
204 #[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
205 pub struct PtrSink {
206 /// The working slice, which may contain uninitialized bytes
207 output: *mut u8,
208 /// Number of bytes in start of `output` guaranteed to be initialized
209 pos: usize,
210 /// Number of bytes in output available
211 cap: usize,
212 }
213
214 #[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
215 impl PtrSink {
216 /// Creates a `Sink` backed by the given byte slice.
217 /// `pos` defines the initial output position in the Sink.
218 /// # Panics
219 /// Panics if `pos` is out of bounds.
220 #[inline]
from_vec(output: &mut Vec<u8>, pos: usize) -> Self221 pub fn from_vec(output: &mut Vec<u8>, pos: usize) -> Self {
222 // SAFETY: Bytes behind pointer may be uninitialized.
223 Self {
224 output: output.as_mut_ptr(),
225 pos,
226 cap: output.capacity(),
227 }
228 }
229 }
230
231 #[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
232 impl Sink for PtrSink {
233 /// Returns a raw ptr to the first unfilled byte of the Sink. Analogous to `[pos..].as_ptr()`.
234 #[inline]
235 #[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
pos_mut_ptr(&mut self) -> *mut u8236 unsafe fn pos_mut_ptr(&mut self) -> *mut u8 {
237 self.base_mut_ptr().add(self.pos()) as *mut u8
238 }
239
240 /// Pushes a byte to the end of the Sink.
241 #[inline]
byte_at(&mut self, pos: usize) -> u8242 fn byte_at(&mut self, pos: usize) -> u8 {
243 unsafe { self.output.add(pos).read() }
244 }
245
246 /// Pushes a byte to the end of the Sink.
247 #[inline]
248 #[cfg(feature = "safe-encode")]
push(&mut self, byte: u8)249 fn push(&mut self, byte: u8) {
250 unsafe {
251 self.pos_mut_ptr().write(byte);
252 }
253 self.pos += 1;
254 }
255
256 #[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
base_mut_ptr(&mut self) -> *mut u8257 unsafe fn base_mut_ptr(&mut self) -> *mut u8 {
258 self.output
259 }
260
261 #[inline]
pos(&self) -> usize262 fn pos(&self) -> usize {
263 self.pos
264 }
265
266 #[inline]
capacity(&self) -> usize267 fn capacity(&self) -> usize {
268 self.cap
269 }
270
271 #[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
272 #[inline]
set_pos(&mut self, new_pos: usize)273 unsafe fn set_pos(&mut self, new_pos: usize) {
274 debug_assert!(new_pos <= self.capacity());
275 self.pos = new_pos;
276 }
277
278 #[inline]
279 #[cfg(feature = "safe-decode")]
extend_with_fill(&mut self, _byte: u8, _len: usize)280 fn extend_with_fill(&mut self, _byte: u8, _len: usize) {
281 unreachable!();
282 }
283
284 /// Extends the Sink with `data`.
285 #[inline]
extend_from_slice(&mut self, data: &[u8])286 fn extend_from_slice(&mut self, data: &[u8]) {
287 self.extend_from_slice_wild(data, data.len())
288 }
289
290 #[inline]
extend_from_slice_wild(&mut self, data: &[u8], copy_len: usize)291 fn extend_from_slice_wild(&mut self, data: &[u8], copy_len: usize) {
292 assert!(copy_len <= data.len());
293 unsafe {
294 core::ptr::copy_nonoverlapping(data.as_ptr(), self.pos_mut_ptr(), copy_len);
295 }
296 self.pos += copy_len;
297 }
298
299 /// Copies `len` bytes starting from `start` to the end of the Sink.
300 /// # Panics
301 /// Panics if `start` >= `pos`.
302 #[inline]
303 #[cfg(feature = "safe-decode")]
extend_from_within(&mut self, _start: usize, _wild_len: usize, _copy_len: usize)304 fn extend_from_within(&mut self, _start: usize, _wild_len: usize, _copy_len: usize) {
305 unreachable!();
306 }
307
308 #[inline]
309 #[cfg(feature = "safe-decode")]
extend_from_within_overlapping(&mut self, _start: usize, _num_bytes: usize)310 fn extend_from_within_overlapping(&mut self, _start: usize, _num_bytes: usize) {
311 unreachable!();
312 }
313 }
314
315 #[cfg(test)]
316 mod tests {
317
318 #[test]
319 #[cfg(any(feature = "safe-encode", feature = "safe-decode"))]
test_sink_slice()320 fn test_sink_slice() {
321 use crate::sink::Sink;
322 use crate::sink::SliceSink;
323 use alloc::vec::Vec;
324 let mut data = Vec::new();
325 data.resize(5, 0);
326 let sink = SliceSink::new(&mut data, 1);
327 assert_eq!(sink.pos(), 1);
328 assert_eq!(sink.capacity(), 5);
329 }
330 }
331