use chacha20poly1305::aead;
use std::ops::{Deref, DerefMut};
pub struct HelperBuf {
inner: Box<[u8]>,
l_cursor: usize,
r_cursor: usize,
}
impl HelperBuf {
pub fn with_capacity(capacity: usize) -> Self {
Self {
inner: vec![0; capacity].into_boxed_slice(),
l_cursor: 0,
r_cursor: 0,
}
}
pub fn consume(&mut self, num_bytes: usize) {
self.l_cursor += num_bytes;
assert!(self.l_cursor <= self.r_cursor);
if self.l_cursor == self.r_cursor {
self.l_cursor = 0;
self.r_cursor = 0;
}
}
pub fn spare_capacity(&mut self) -> &mut [u8] {
&mut self.inner[self.r_cursor..]
}
pub fn increase_len(&mut self, num_bytes: usize) {
self.r_cursor += num_bytes;
debug_assert!(self.r_cursor <= self.inner.len());
}
pub fn left_align(&mut self) {
if self.l_cursor != 0 {
self.inner.copy_within(self.l_cursor..self.r_cursor, 0);
self.r_cursor -= self.l_cursor;
self.l_cursor = 0;
}
}
pub fn split_off_aead_buf<'a>(&'a mut self, i: usize) -> HelperBufPart<'a> {
let start_i = self.l_cursor + i;
HelperBufPart {
parent: self,
start_i,
}
}
}
impl aead::Buffer for HelperBuf {
fn extend_from_slice(&mut self, other: &[u8]) -> aead::Result<()> {
let new_r_cursor = self.r_cursor + other.len();
if new_r_cursor > self.inner.len() {
return Err(aead::Error);
}
self.inner[self.r_cursor..new_r_cursor].copy_from_slice(other);
self.r_cursor = new_r_cursor;
Ok(())
}
fn truncate(&mut self, len: usize) {
let new_r_cursor = self.l_cursor + len;
debug_assert!(new_r_cursor <= self.r_cursor);
self.r_cursor = new_r_cursor;
}
}
impl Deref for HelperBuf {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.inner[self.l_cursor..self.r_cursor]
}
}
impl DerefMut for HelperBuf {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner[self.l_cursor..self.r_cursor]
}
}
impl AsRef<[u8]> for HelperBuf {
fn as_ref(&self) -> &[u8] {
&self.inner[self.l_cursor..self.r_cursor]
}
}
impl AsMut<[u8]> for HelperBuf {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.inner[self.l_cursor..self.r_cursor]
}
}
pub struct HelperBufPart<'a> {
parent: &'a mut HelperBuf,
start_i: usize,
}
impl aead::Buffer for HelperBufPart<'_> {
fn extend_from_slice(&mut self, other: &[u8]) -> aead::Result<()> {
let new_r_cursor = self.parent.r_cursor + other.len();
if new_r_cursor > self.parent.inner.len() {
return Err(aead::Error);
}
self.parent.inner[self.parent.r_cursor..new_r_cursor].copy_from_slice(other);
self.parent.r_cursor = new_r_cursor;
Ok(())
}
fn truncate(&mut self, len: usize) {
let new_r_cursor = self.start_i + len;
debug_assert!(new_r_cursor <= self.parent.r_cursor);
self.parent.r_cursor = new_r_cursor;
}
}
impl Deref for HelperBufPart<'_> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.parent.inner[self.start_i..self.parent.r_cursor]
}
}
impl DerefMut for HelperBufPart<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.parent.inner[self.start_i..self.parent.r_cursor]
}
}
impl AsRef<[u8]> for HelperBufPart<'_> {
fn as_ref(&self) -> &[u8] {
&self.parent.inner[self.start_i..self.parent.r_cursor]
}
}
impl AsMut<[u8]> for HelperBufPart<'_> {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.parent.inner[self.start_i..self.parent.r_cursor]
}
}
#[cfg(test)]
mod tests {
use crate::helper_buf::HelperBuf;
use chacha20poly1305::aead::{self, Buffer};
#[test]
fn test_helper_buf() {
let mut buf = HelperBuf::with_capacity(4);
assert!(buf.is_empty());
assert!(buf[..].is_empty());
assert_eq!(buf.spare_capacity(), [0, 0, 0, 0]);
assert_eq!(*buf.inner, [0, 0, 0, 0]);
buf.extend_from_slice(&[1, 2, 3]).unwrap();
assert_eq!(*buf, [1, 2, 3]);
assert_eq!(buf.spare_capacity(), [0]);
assert_eq!(*buf.inner, [1, 2, 3, 0]);
buf.consume(1);
assert_eq!(*buf, [2, 3]);
assert_eq!(buf.spare_capacity(), [0]);
assert_eq!(*buf.inner, [1, 2, 3, 0]);
buf.as_mut()[0] = 7;
assert_eq!(*buf, [7, 3]);
assert_eq!(buf.spare_capacity(), [0]);
assert_eq!(*buf.inner, [1, 7, 3, 0]);
buf.left_align();
assert_eq!(*buf, [7, 3]);
assert_eq!(buf.spare_capacity(), [3, 0]);
assert_eq!(*buf.inner, [7, 3, 3, 0]);
buf.spare_capacity()[0] = 5;
buf.increase_len(1);
assert_eq!(*buf, [7, 3, 5]);
assert_eq!(buf.spare_capacity(), [0]);
assert_eq!(*buf.inner, [7, 3, 5, 0]);
assert_eq!(buf.extend_from_slice(&[2, 2, 2, 2]), Err(aead::Error));
buf.truncate(1);
assert_eq!(*buf, [7]);
assert_eq!(buf.spare_capacity(), [3, 5, 0]);
assert_eq!(*buf.inner, [7, 3, 5, 0]);
}
#[test]
fn test_helper_buf_part() {
let mut buf = HelperBuf::with_capacity(4);
buf.extend_from_slice(&[1, 2, 3]).unwrap();
assert_eq!(*buf, [1, 2, 3]);
let mut part = buf.split_off_aead_buf(1);
assert_eq!(*part, [2, 3]);
part[0] = 5;
assert_eq!(*part, [5, 3]);
part.extend_from_slice(&[6]).unwrap();
assert_eq!(*part, [5, 3, 6]);
assert_eq!(part.extend_from_slice(&[0]), Err(aead::Error));
part.truncate(1);
assert_eq!(*part, [5]);
assert_eq!(*buf, [1, 5]);
}
}