use alloc::vec::Vec;
pub trait Sink<Unit>: Sized {
fn write(&mut self, unit: Unit);
fn encoded(&self) -> &[Unit];
}
#[derive(Debug)]
pub struct VecSink<Unit> {
buffer: Vec<Unit>,
pos: usize,
max_size_step: usize,
}
impl<Unit: Default + Copy + Clone> VecSink<Unit> {
pub fn new(initial_capacity: usize) -> Self {
Self::with_params(initial_capacity, 1024 * 1024)
}
pub fn with_params(initial_capacity: usize, max_size_step: usize) -> Self {
let capacity = initial_capacity.max(64);
let mut buffer = Vec::with_capacity(capacity);
buffer.resize(capacity, Unit::default());
Self {
pos: capacity,
buffer,
max_size_step: max_size_step.max(64),
}
}
#[doc(hidden)]
pub fn with_exact_capacity(capacity: usize) -> Self {
let mut buffer = Vec::with_capacity(capacity);
buffer.resize(capacity, Unit::default());
Self {
pos: capacity,
buffer,
max_size_step: 1024 * 1024,
}
}
pub fn encoded(&self) -> &[Unit] {
&self.buffer[self.pos..]
}
pub fn len(&self) -> usize {
self.buffer.len() - self.pos
}
pub fn is_empty(&self) -> bool {
self.buffer.len() == self.pos
}
pub fn reset(&mut self) {
self.pos = self.buffer.len();
}
fn ensure_space(&mut self) {
if self.pos == 0 {
let old_len = self.buffer.len();
let content_len = old_len - self.pos; let growth = old_len.min(self.max_size_step);
let new_len = old_len + growth;
self.buffer.resize(new_len, Unit::default());
let new_pos = new_len - content_len;
self.buffer.copy_within(0..content_len, new_pos);
self.pos = new_pos;
}
}
}
impl<Unit: Default + Copy + Clone> Sink<Unit> for VecSink<Unit> {
#[inline]
fn write(&mut self, unit: Unit) {
self.ensure_space();
self.pos -= 1;
self.buffer[self.pos] = unit;
}
#[inline]
fn encoded(&self) -> &[Unit] {
&self.buffer[self.pos..]
}
}
pub struct SliceSink<'a, Unit> {
buffer: &'a mut [Unit],
pos: usize,
}
impl<'a, Unit: Copy> SliceSink<'a, Unit> {
pub fn new(buffer: &'a mut [Unit]) -> Self {
let pos = buffer.len();
Self { buffer, pos }
}
pub fn encoded(&self) -> &[Unit] {
&self.buffer[self.pos..]
}
pub fn len(&self) -> usize {
self.buffer.len() - self.pos
}
pub fn is_empty(&self) -> bool {
self.buffer.len() == self.pos
}
}
impl<'a, Unit: Copy> Sink<Unit> for SliceSink<'a, Unit> {
#[inline]
fn write(&mut self, unit: Unit) {
debug_assert!(self.pos > 0, "SliceSink overflow");
self.pos -= 1;
self.buffer[self.pos] = unit;
}
#[inline]
fn encoded(&self) -> &[Unit] {
&self.buffer[self.pos..]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vec_sink_basic() {
let mut sink = VecSink::<u8>::new(64);
assert!(sink.is_empty());
sink.write(0xAB);
sink.write(0xCD);
assert_eq!(sink.len(), 2);
assert_eq!(sink.encoded(), &[0xCD, 0xAB]);
}
#[test]
fn test_vec_sink_growth_at_64_boundary() {
let mut sink = VecSink::<u8>::with_exact_capacity(64);
for i in 0..65u8 {
sink.write(i);
}
assert_eq!(sink.len(), 65);
for i in 0..65u8 {
assert_eq!(
sink.encoded()[(64 - i) as usize],
i,
"mismatch at position {}",
i
);
}
}
#[test]
fn test_vec_sink_growth_at_65_boundary() {
let mut sink = VecSink::<u8>::with_exact_capacity(65);
for i in 0..66u8 {
sink.write(i);
}
assert_eq!(sink.len(), 66);
for i in 0..66u8 {
assert_eq!(
sink.encoded()[(65 - i) as usize],
i,
"mismatch at position {}",
i
);
}
}
#[test]
fn test_vec_sink_growth_at_320_boundary() {
let mut sink = VecSink::<u8>::with_exact_capacity(320);
for i in 0..321u16 {
sink.write(i as u8);
}
assert_eq!(sink.len(), 321);
for i in 0..321u16 {
assert_eq!(
sink.encoded()[(320 - i) as usize],
i as u8,
"mismatch at {}",
i
);
}
}
#[test]
fn test_vec_sink_growth_formula_min_step() {
let mut sink = VecSink::<u8>::with_params(64, 256);
for i in 0..200u16 {
sink.write(i as u8);
}
let encoded = sink.encoded();
assert_eq!(encoded.len(), 200);
for i in 0..200u16 {
assert_eq!(encoded[(199 - i) as usize], i as u8, "mismatch at {}", i);
}
}
#[test]
fn test_vec_sink_growth_formula_capped_step() {
let mut sink = VecSink::<u8>::with_params(1024, 256);
for i in 0..1500u16 {
sink.write(i as u8);
}
let encoded = sink.encoded();
assert_eq!(encoded.len(), 1500);
for i in 0..1500u16 {
assert_eq!(encoded[(1499 - i) as usize], i as u8, "mismatch at {}", i);
}
}
#[test]
fn test_vec_sink_multiple_growths() {
let mut sink = VecSink::<u8>::with_exact_capacity(64);
for i in 0..1000u16 {
sink.write(i as u8);
}
assert_eq!(sink.len(), 1000);
for i in 0..1000u16 {
assert_eq!(
sink.encoded()[(999 - i) as usize],
i as u8,
"mismatch at {}",
i
);
}
}
#[test]
fn test_slice_sink_basic() {
let mut buf = [0u8; 16];
let mut sink = SliceSink::new(&mut buf[..]);
sink.write(0xAB);
sink.write(0xCD);
assert_eq!(sink.len(), 2);
assert_eq!(sink.encoded(), &[0xCD, 0xAB]);
}
}