pub trait RangeInput {
fn next_byte(&mut self) -> u8;
fn position(&self) -> usize;
fn zero_bytes_past_eof(&self) -> u32;
}
pub trait IntoRangeInput {
type Input: RangeInput;
fn into_range_input(self) -> Self::Input;
}
#[derive(Clone, Debug)]
pub struct SliceInput<'a> {
data: &'a [u8],
pos: usize,
zero_bytes_past_eof: u32,
}
impl<'a> SliceInput<'a> {
#[inline]
pub fn new(data: &'a [u8]) -> Self {
Self {
data,
pos: 0,
zero_bytes_past_eof: 0,
}
}
pub fn remaining(&self) -> &'a [u8] {
self.data.get(self.pos..).unwrap_or_default()
}
#[inline]
pub fn len(&self) -> usize {
self.data.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
#[cold]
#[inline(never)]
fn past_eof(&mut self) -> u8 {
self.zero_bytes_past_eof = self.zero_bytes_past_eof.saturating_add(1);
0
}
}
impl RangeInput for SliceInput<'_> {
#[inline(always)]
fn next_byte(&mut self) -> u8 {
if let Some(&byte) = self.data.get(self.pos) {
self.pos += 1;
byte
} else {
self.past_eof()
}
}
#[inline]
fn position(&self) -> usize {
self.pos
}
#[inline]
fn zero_bytes_past_eof(&self) -> u32 {
self.zero_bytes_past_eof
}
}
impl<'a> IntoRangeInput for &'a [u8] {
type Input = SliceInput<'a>;
#[inline]
fn into_range_input(self) -> SliceInput<'a> {
SliceInput::new(self)
}
}
impl<'a> IntoRangeInput for SliceInput<'a> {
type Input = Self;
#[inline]
fn into_range_input(self) -> Self {
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_slice_is_read_then_padded_with_counted_zeros() {
let mut input = SliceInput::new(&[7, 8]);
assert_eq!((input.next_byte(), input.next_byte()), (7, 8));
assert_eq!((input.next_byte(), input.next_byte()), (0, 0));
assert_eq!((input.position(), input.zero_bytes_past_eof()), (2, 2));
assert!(input.remaining().is_empty());
}
}