Initial commit
This commit is contained in:
171
src/read_buffer.rs
Normal file
171
src/read_buffer.rs
Normal file
@@ -0,0 +1,171 @@
|
||||
#[must_use]
|
||||
pub struct ReadBuffer<'a> {
|
||||
data: &'a [u8],
|
||||
consumed: usize,
|
||||
used: bool,
|
||||
|
||||
decrypted_consumed: &'a mut usize,
|
||||
}
|
||||
|
||||
impl<'a> ReadBuffer<'a> {
|
||||
#[inline]
|
||||
pub(crate) fn new(buffer: &'a [u8], decrypted_consumed: &'a mut usize) -> Self {
|
||||
Self {
|
||||
data: buffer,
|
||||
consumed: 0,
|
||||
used: false,
|
||||
decrypted_consumed,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn len(&self) -> usize {
|
||||
self.data.len() - self.consumed
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn peek(&mut self, count: usize) -> &'a [u8] {
|
||||
let count = self.len().min(count);
|
||||
let start = self.consumed;
|
||||
|
||||
self.used = true;
|
||||
|
||||
&self.data[start..start + count]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn peek_all(&mut self) -> &'a [u8] {
|
||||
self.peek(self.len())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn pop(&mut self, count: usize) -> &'a [u8] {
|
||||
let count = self.len().min(count);
|
||||
let start = self.consumed;
|
||||
self.consumed += count;
|
||||
self.used = true;
|
||||
|
||||
&self.data[start..start + count]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn pop_all(&mut self) -> &'a [u8] {
|
||||
self.pop(self.len())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn revert(self) {
|
||||
core::mem::forget(self);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn pop_into(&mut self, buf: &mut [u8]) -> usize {
|
||||
let to_copy = self.pop(buf.len());
|
||||
|
||||
buf[..to_copy.len()].copy_from_slice(to_copy);
|
||||
|
||||
to_copy.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ReadBuffer<'_> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
*self.decrypted_consumed += if self.used {
|
||||
self.consumed
|
||||
} else {
|
||||
self.data.len()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn dropping_unused_buffer_consumes_all() {
|
||||
let mut consumed = 1000;
|
||||
let buffer = [0, 1, 2, 3];
|
||||
|
||||
_ = ReadBuffer::new(&buffer, &mut consumed);
|
||||
|
||||
assert_eq!(consumed, 1004);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pop_moves_internal_cursor() {
|
||||
let mut consumed = 0;
|
||||
|
||||
let mut buffer = ReadBuffer::new(&[0, 1, 2, 3], &mut consumed);
|
||||
|
||||
assert_eq!(buffer.pop(1), &[0]);
|
||||
assert_eq!(buffer.pop(1), &[1]);
|
||||
assert_eq!(buffer.pop(1), &[2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dropping_consumes_as_many_bytes_as_used() {
|
||||
let mut consumed = 0;
|
||||
|
||||
let mut buffer = ReadBuffer::new(&[0, 1, 2, 3], &mut consumed);
|
||||
|
||||
assert_eq!(buffer.pop(1), &[0]);
|
||||
assert_eq!(buffer.pop(1), &[1]);
|
||||
assert_eq!(buffer.pop(1), &[2]);
|
||||
|
||||
core::mem::drop(buffer);
|
||||
|
||||
assert_eq!(consumed, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pop_returns_fewer_bytes_if_requested_more_than_what_it_has() {
|
||||
let mut consumed = 0;
|
||||
|
||||
let mut buffer = ReadBuffer::new(&[0, 1, 2, 3], &mut consumed);
|
||||
|
||||
assert_eq!(buffer.pop(1), &[0]);
|
||||
assert_eq!(buffer.pop(1), &[1]);
|
||||
assert_eq!(buffer.pop(4), &[2, 3]);
|
||||
assert_eq!(buffer.pop(1), &[]);
|
||||
|
||||
core::mem::drop(buffer);
|
||||
|
||||
assert_eq!(consumed, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn peek_does_not_consume() {
|
||||
let mut consumed = 0;
|
||||
|
||||
let mut buffer = ReadBuffer::new(&[0, 1, 2, 3], &mut consumed);
|
||||
|
||||
assert_eq!(buffer.peek(1), &[0]);
|
||||
assert_eq!(buffer.peek(1), &[0]);
|
||||
|
||||
core::mem::drop(buffer);
|
||||
|
||||
assert_eq!(consumed, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn revert_undoes_pop() {
|
||||
let mut consumed = 0;
|
||||
|
||||
let mut buffer = ReadBuffer::new(&[0, 1, 2, 3], &mut consumed);
|
||||
|
||||
assert_eq!(buffer.pop(4), &[0, 1, 2, 3]);
|
||||
|
||||
buffer.revert();
|
||||
|
||||
assert_eq!(consumed, 0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user