use alloc::vec::Vec;
#[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
use core::mem::MaybeUninit;
#[inline]
pub fn vec_sink_for_compression(
vec: &mut Vec<u8>,
offset: usize,
pos: usize,
required_capacity: usize,
) -> impl Sink + '_ {
#[cfg(not(feature = "safe-encode"))]
return {
assert!(vec.capacity() >= offset + required_capacity);
VecSink::new(vec, offset, pos)
};
#[cfg(feature = "safe-encode")]
return {
vec.resize(offset + required_capacity, 0);
SliceSink::new(&mut vec[offset..], pos)
};
}
#[cfg(feature = "frame")]
#[inline]
pub fn vec_sink_for_decompression(
vec: &mut Vec<u8>,
offset: usize,
pos: usize,
required_capacity: usize,
) -> impl Sink + '_ {
#[cfg(not(feature = "safe-decode"))]
return {
assert!(vec.capacity() >= offset + required_capacity);
crate::sink::VecSink::new(vec, offset, pos)
};
#[cfg(feature = "safe-decode")]
return {
vec.resize(offset + required_capacity, 0);
SliceSink::new(&mut vec[offset..], pos)
};
}
pub trait Sink {
fn filled_slice(&self) -> &[u8];
fn pos(&self) -> usize;
fn capacity(&self) -> usize;
#[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
unsafe fn set_pos(&mut self, new_pos: usize);
#[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
unsafe fn base_mut_ptr(&mut self) -> *mut u8;
#[inline]
#[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
unsafe fn pos_mut_ptr(&mut self) -> *mut u8 {
self.base_mut_ptr().add(self.pos()) as *mut u8
}
#[inline]
fn push(&mut self, byte: u8) {
self.extend_from_slice(&[byte])
}
fn extend_with_fill(&mut self, byte: u8, len: usize);
fn extend_from_slice_wild(&mut self, data: &[u8], copy_len: usize);
#[inline]
fn extend_from_slice(&mut self, data: &[u8]) {
self.extend_from_slice_wild(data, data.len())
}
fn extend_from_within_wild(&mut self, start: usize, wild_len: usize, copy_len: usize);
#[inline]
fn extend_from_within(&mut self, start: usize, len: usize) {
self.extend_from_within_wild(start, len, len)
}
fn extend_from_within_overlapping(&mut self, start: usize, len: usize);
}
pub struct SliceSink<'a> {
output: &'a mut [u8],
pos: usize,
}
impl<'a> SliceSink<'a> {
#[inline]
pub fn new(output: &'a mut [u8], pos: usize) -> Self {
let _ = &mut output[..pos]; SliceSink { output, pos }
}
}
impl<'a> Sink for SliceSink<'a> {
#[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
unsafe fn base_mut_ptr(&mut self) -> *mut u8 {
self.output.as_mut_ptr()
}
#[inline]
fn filled_slice(&self) -> &[u8] {
&self.output[..self.pos]
}
#[inline]
fn pos(&self) -> usize {
self.pos
}
#[inline]
fn capacity(&self) -> usize {
self.output.len()
}
#[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
#[inline]
unsafe fn set_pos(&mut self, new_pos: usize) {
debug_assert!(new_pos <= self.capacity());
self.pos = new_pos;
}
#[inline]
fn extend_with_fill(&mut self, byte: u8, len: usize) {
self.output[self.pos..self.pos + len].fill(byte);
self.pos += len;
}
#[inline]
fn extend_from_slice_wild(&mut self, data: &[u8], copy_len: usize) {
assert!(copy_len <= data.len());
self.output[self.pos..self.pos + data.len()].copy_from_slice(data);
self.pos += copy_len;
}
#[inline]
fn extend_from_within_wild(&mut self, start: usize, wild_len: usize, copy_len: usize) {
assert!(copy_len <= wild_len);
assert!(start + copy_len <= self.pos);
self.output.copy_within(start..start + wild_len, self.pos);
self.pos += copy_len;
}
#[inline]
fn extend_from_within_overlapping(&mut self, start: usize, len: usize) {
assert!(start <= self.pos);
let offset = self.pos - start;
let out = &mut self.output[start..self.pos + len];
out[offset] = 0; for i in offset..out.len() {
out[i] = out[i - offset];
}
self.pos += len;
}
}
#[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
pub struct VecSink<'a> {
output: &'a mut Vec<u8>,
output_ptr: *mut u8,
pos: usize,
capacity: usize,
}
#[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
impl<'a> VecSink<'a> {
#[inline]
pub fn new(output: &'a mut Vec<u8>, offset: usize, pos: usize) -> VecSink<'a> {
output.truncate(offset + pos);
VecSink {
capacity: output.capacity() - offset,
output_ptr: unsafe { output.as_mut_ptr().add(offset) },
output,
pos,
}
}
}
#[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
impl<'a> VecSink<'a> {
#[inline]
fn buffer_mut(&mut self) -> &mut [MaybeUninit<u8>] {
unsafe {
core::slice::from_raw_parts_mut(self.output_ptr as *mut MaybeUninit<u8>, self.capacity)
}
}
}
#[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
impl<'a> Sink for VecSink<'a> {
unsafe fn base_mut_ptr(&mut self) -> *mut u8 {
self.output_ptr
}
#[inline]
fn filled_slice(&self) -> &[u8] {
debug_assert!(self.pos <= self.capacity);
unsafe { core::slice::from_raw_parts(self.output_ptr, self.pos) }
}
#[inline]
fn pos(&self) -> usize {
self.pos
}
#[inline]
fn capacity(&self) -> usize {
self.capacity
}
#[inline]
unsafe fn set_pos(&mut self, new_pos: usize) {
self.pos = new_pos
}
#[inline]
fn extend_with_fill(&mut self, byte: u8, len: usize) {
let pos = self.pos;
self.buffer_mut()[pos..pos + len].fill(MaybeUninit::new(byte));
self.pos += len;
}
#[inline]
fn extend_from_slice_wild(&mut self, data: &[u8], copy_len: usize) {
assert!(copy_len <= data.len());
let pos = self.pos;
self.buffer_mut()[pos..pos + data.len()].copy_from_slice(slice_as_uninit_ref(data));
self.pos += copy_len;
}
#[inline]
fn extend_from_within_wild(&mut self, start: usize, wild_len: usize, copy_len: usize) {
assert!(copy_len <= wild_len);
assert!(start + copy_len <= self.pos);
let pos = self.pos;
self.buffer_mut().copy_within(start..start + wild_len, pos);
self.pos += copy_len;
}
#[inline]
fn extend_from_within_overlapping(&mut self, start: usize, len: usize) {
assert!(start <= self.pos);
let offset = self.pos - start;
let pos = self.pos;
let out = &mut self.buffer_mut()[start..pos + len];
out[offset] = MaybeUninit::new(0); for i in offset..out.len() {
out[i] = out[i - offset];
}
self.pos += len;
}
}
#[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
impl<'a> Drop for VecSink<'a> {
#[inline]
fn drop(&mut self) {
unsafe {
let offset = self.output_ptr.offset_from(self.output.as_ptr()) as usize;
self.output.set_len(offset + self.pos);
}
}
}
#[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
#[inline]
fn slice_as_uninit_ref(slice: &[u8]) -> &[MaybeUninit<u8>] {
unsafe { core::slice::from_raw_parts(slice.as_ptr() as *const MaybeUninit<u8>, slice.len()) }
}
#[cfg(test)]
mod tests {
use crate::sink::SliceSink;
#[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
use crate::sink::VecSink;
use super::{Sink, Vec};
#[test]
fn test_sink_slice() {
let mut data = Vec::new();
data.resize(5, 0);
let mut sink = SliceSink::new(&mut data, 1);
assert_eq!(sink.pos(), 1);
assert_eq!(sink.capacity(), 5);
assert_eq!(sink.filled_slice(), &[0]);
sink.extend_from_slice(&[1, 2, 3]);
assert_eq!(sink.pos(), 4);
assert_eq!(sink.filled_slice(), &[0, 1, 2, 3]);
}
#[cfg(not(all(feature = "safe-encode", feature = "safe-decode")))]
#[test]
fn test_sink_vec() {
let mut data = Vec::with_capacity(5);
data.push(255); data.push(0);
{
let mut sink = VecSink::new(&mut data, 1, 1);
assert_eq!(sink.pos(), 1);
assert_eq!(sink.capacity(), 4);
assert_eq!(sink.filled_slice(), &[0]);
sink.extend_from_slice(&[1, 2, 3]);
assert_eq!(sink.pos(), 4);
assert_eq!(sink.filled_slice(), &[0, 1, 2, 3]);
}
assert_eq!(data.as_slice(), &[255, 0, 1, 2, 3]);
}
}