use std::ops::{Index, IndexMut, Range};
#[derive(Debug, Default, Copy, Clone, PartialEq)]
pub struct SliceIndex(u32);
#[derive(Debug, Default, Copy, Clone)]
struct SessionKey {
start: u32,
end: u32,
}
impl SessionKey {
fn as_range(&self) -> Range<usize> {
self.start as usize..self.end as usize
}
}
#[derive(Debug)]
pub struct Session<'a, T> {
buffer: &'a mut Buffer<T>,
}
impl<'a, T: Copy> Session<'a, T> {
#[must_use]
pub fn next_slice(&mut self) -> SliceIndex {
self.buffer.next_slice()
}
pub fn insert(&mut self, pos: usize, value: T) {
self.buffer.insert(pos, value);
}
pub fn last(&self) -> Option<&T> {
self.buffer.last()
}
pub fn push(&mut self, value: T) {
self.buffer.push(value)
}
pub fn pop(&mut self) -> Option<T> {
self.buffer.pop()
}
pub fn extend(&mut self, iter: impl IntoIterator<Item = T>) {
self.buffer.extend(iter);
}
pub fn tail_drain(&mut self, size: u32) {
self.buffer.tail_drain(size);
}
pub fn slice(&self, index: SliceIndex) -> &[T] {
self.buffer.get(index)
}
pub fn slice_mut(&mut self, index: SliceIndex) -> &mut [T] {
self.buffer.get_mut(index)
}
pub fn len(&self) -> u32 {
self.buffer.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn truncate(&mut self, key: SliceIndex, index: usize) {
self.buffer.truncate(key, index);
}
}
impl<'a, T: Copy> Index<usize> for Session<'a, T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
self.buffer.buf.index(index)
}
}
impl<'a, T: Copy> IndexMut<usize> for Session<'a, T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.buffer.buf.index_mut(index)
}
}
#[derive(Debug)]
pub struct Buffer<T> {
buf: Vec<T>,
keys: Vec<SessionKey>,
}
impl<T: Copy> Buffer<T> {
pub fn empty() -> Self {
Self {
buf: Vec::new(),
keys: Vec::new(),
}
}
fn push(&mut self, value: T) {
assert!(!self.keys.is_empty(), "tried to push to a buffer without a slice key");
self.buf.push(value);
let buf_len = self.buf.len();
let index = self.keys.len() - 1;
self.keys[index].end = buf_len as u32;
}
fn pop(&mut self) -> Option<T> {
assert!(!self.keys.is_empty(), "tried to pop from a buffer without a slice key");
let index = self.keys.len() - 1;
let output = self.buf.pop();
if output.is_some() {
self.keys[index].end -= 1;
}
output
}
fn insert(&mut self, index: usize, value: T) {
assert!(index < u32::MAX as usize);
if self.buf.len() == index {
self.push(value);
return;
}
self.buf.insert(index, value);
let last_key_index = self.keys.len() - 1;
let Some(key_index) = self
.keys
.iter_mut()
.rev()
.position(|key| key.as_range().contains(&index))
.map(|pos| last_key_index - pos)
else {
return;
};
self.keys[key_index].end += 1;
self.keys[key_index + 1..].iter_mut().for_each(|key| {
key.start += 1;
key.end += 1;
});
}
fn extend(&mut self, iter: impl IntoIterator<Item = T>) {
self.buf.extend(iter);
let buf_len = self.buf.len();
if !self.keys.is_empty() {
let index = self.keys.len() - 1;
self.keys[index].end = buf_len as u32;
}
}
pub fn new_session(&mut self) -> Session<'_, T> {
Session { buffer: self }
}
fn next_slice(&mut self) -> SliceIndex {
let slice = SliceIndex(self.keys.len() as u32);
let len = self.buf.len() as u32;
let key = SessionKey { start: len, end: len };
self.keys.push(key);
slice
}
pub fn get(&self, index: SliceIndex) -> &[T] {
let key = self.keys[index.0 as usize];
&self.buf[key.as_range()]
}
pub fn get_mut(&mut self, index: SliceIndex) -> &mut [T] {
let key = self.keys[index.0 as usize];
&mut self.buf[key.as_range()]
}
pub fn tail_drain(&mut self, size: u32) {
assert!(!self.keys.is_empty());
let key_index = self.keys.len() - 1;
self.keys[key_index].end -= size;
let pos = self.len() - size;
let _ = self.buf.drain(pos as usize..);
}
pub fn clear(&mut self) {
self.buf.clear();
self.keys.clear();
}
fn last(&self) -> Option<&T> {
self.buf.last()
}
fn len(&self) -> u32 {
self.buf.len() as u32
}
fn truncate(&mut self, key: SliceIndex, index: usize) {
assert!(
!self.keys.is_empty(),
"tried to truncate from a buffer that contains zero slice keys"
);
let last_key_index = self.keys.len() - 1;
assert_eq!(key.0 as usize, last_key_index, "trying to truncate before the last key");
let slice = &mut self.keys[key.0 as usize];
let index = index + slice.start as usize;
self.buf.truncate(index);
slice.end = self.buf.len() as u32;
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn two_sessions() {
let mut buffer = Buffer::empty();
let mut s1 = buffer.new_session();
let k1 = s1.next_slice();
s1.extend([1, 2, 3]);
let mut s2 = buffer.new_session();
let k2 = s2.next_slice();
s2.extend([10, 20, 30]);
let b1 = buffer.get(k1);
let b2 = buffer.get(k2);
assert_eq!(b1, &[1, 2, 3]);
assert_eq!(b2, &[10, 20, 30]);
}
#[test]
fn buffer_insert_via_session() {
let mut buffer = Buffer::<u8>::empty();
let mut session = buffer.new_session();
let k1 = session.next_slice();
session.extend([b'a', b'b']);
let k2 = session.next_slice();
session.insert(1, b'x');
session.push(b'z');
let output = buffer.get(k1);
assert_eq!(output, b"axb");
let output = buffer.get(k2);
assert_eq!(output, b"z");
}
#[test]
fn session_pop() {
let mut buffer = Buffer::<u8>::empty();
let mut session = buffer.new_session();
let k1 = session.next_slice();
session.push(0);
session.pop();
assert!(buffer.buf.is_empty());
assert!(buffer.get(k1).is_empty());
}
#[test]
fn clear_buffer() {
let mut buffer = Buffer::empty();
let mut session = buffer.new_session();
let _ = session.next_slice();
session.push(0);
assert_eq!(buffer.keys.len(), 1);
assert_eq!(buffer.buf.len(), 1);
buffer.clear();
assert!(buffer.keys.is_empty());
assert!(buffer.buf.is_empty());
}
#[test]
fn tail_drain() {
let mut buffer = Buffer::<u8>::empty();
let mut session = buffer.new_session();
let _k1 = session.next_slice();
session.extend(0..10);
session.tail_drain(3);
let key = buffer.keys[0];
assert_eq!(key.start, 0);
assert_eq!(key.end, 7);
}
#[test]
#[should_panic(expected = "tried to truncate from a buffer that contains zero slice keys")]
fn truncate_empty_buffer() {
let mut buffer = Buffer::<u8>::empty();
buffer.truncate(SliceIndex(0), 123);
}
#[test]
#[should_panic(expected = "trying to truncate before the last key")]
fn truncate_before_last_key() {
let mut buffer = Buffer::<u8>::empty();
let mut session = buffer.new_session();
let k1 = session.next_slice();
let _k2 = session.next_slice();
buffer.truncate(k1, 0);
}
#[test]
fn truncate() {
let mut buffer = Buffer::<u8>::empty();
let mut session = buffer.new_session();
let k1 = session.next_slice();
session.extend([1, 2, 3]);
session.truncate(k1, 2);
assert_eq!(&[1, 2], session.slice(k1));
}
}