use super::{BorrowOutSlice, OutSlice, TakeItem};
use crate::cast::InitTc;
pub struct Cursor<Item, Arr: BorrowOutSlice<Item> + ?Sized> {
_phantom: core::marker::PhantomData<[Item]>,
position: usize,
data: Arr,
}
impl<Item, Arr: BorrowOutSlice<Item>> Cursor<Item, Arr> {
pub fn new(buf: Arr) -> Self {
Cursor {
_phantom: Default::default(),
data: buf,
position: 0,
}
}
}
impl<Item, Arr: BorrowOutSlice<Item> + ?Sized> Cursor<Item, Arr> {
pub fn push(&mut self, item: Item) -> Result<&mut Item, Item> {
if self.position < self.data.borrow_uninit_slice().len() {
let res = self.data.borrow_out_slice().at_mut(self.position).write(item);
self.position += 1;
Ok(res)
} else {
Err(item)
}
}
pub fn push_iter<I>(&mut self, iter: I) -> &mut [Item] where I: IntoIterator, I::Item: TakeItem<Item> {
let res = self.data.borrow_out_slice()[self.position..].init_from_iter(iter);
self.position += res.len();
res
}
pub fn remaining_count(&self) -> usize {
self.data.borrow_uninit_slice().len() - self.position
}
pub fn reset(&mut self) {
self.position = 0;
}
pub fn written(&self) -> &[Item] {
unsafe {
let slice = &self.data.borrow_uninit_slice()[..self.position];
core::slice::from_raw_parts(slice.as_ptr() as *const Item, slice.len())
}
}
pub fn written_mut(&mut self) -> &mut [Item] {
unsafe {
let slice = &mut self.data.borrow_out_slice()[..self.position];
core::slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut Item, slice.len())
}
}
pub fn pop(&mut self) -> Option<Item> where Item: Copy {
use crate::borrow::BorrowUninit;
unsafe {
if self.position > 0 && self.position - 1 < self.data.borrow_uninit_slice().len() {
let res = *self.data.borrow_out_slice().at_mut(self.position - 1).assume_init_ref();
self.position -= 1;
Some(res)
} else {
None
}
}
}
pub fn pop_slice(&mut self, max: usize) -> &mut [Item] {
unsafe {
let to_remove = self.position.min(max);
let res = &mut self.data.borrow_out_slice()[(self.position - to_remove)..self.position];
self.position -= to_remove;
core::slice::from_raw_parts_mut(res.as_mut_ptr() as *mut Item, to_remove)
}
}
pub fn try_pop_slice(&mut self, required: usize) -> Option<&mut [Item]> {
if self.position >= required {
Some(self.pop_slice(required))
} else {
None
}
}
pub fn split_mut(&mut self) -> (&mut [Item], &mut OutSlice<Item>) {
unsafe {
let (first, second) = self.data.borrow_out_slice().split_at_mut(self.position);
(first.assume_init_mut(), second)
}
}
pub fn try_cast_initialized(self) -> Result<<Arr as InitTc<Item>>::Output, Self> where Arr: Sized + InitTc<Item> {
unsafe {
if self.position == self.data.borrow_uninit_slice().len() {
Ok(self.data.cast())
} else {
Err(self)
}
}
}
}
impl<Item, Arr: BorrowOutSlice<Item>> From<Arr> for Cursor<Item, Arr> {
fn from(value: Arr) -> Self {
Self::new(value)
}
}
#[cfg(feature = "alloc")]
mod alloc_impls {
use super::Cursor;
use core::mem::MaybeUninit;
use super::super::BorrowOutSlice;
use alloc::boxed::Box;
use alloc::vec::Vec;
impl<Item> Cursor<Item, Box<[MaybeUninit<Item>]>> {
pub fn from_vec_preserving_len(vec: Vec<Item>) -> Self {
let len = vec.len();
let mut cursor = Cursor::from_vec_entire_capaity(vec);
cursor.position = len;
cursor
}
pub fn from_vec_entire_capaity<T>(mut vec: Vec<T>) -> Self where Box<[MaybeUninit<T>]>: BorrowOutSlice<Item> {
unsafe {
let ptr = vec.as_mut_ptr();
let capacity = vec.capacity();
core::mem::forget(vec);
let boxed = Vec::from_raw_parts(ptr as *mut MaybeUninit<Item>, capacity, capacity)
.into_boxed_slice();
Cursor {
_phantom: Default::default(),
data: boxed,
position: 0,
}
}
}
}
impl<Item> Cursor<Item, Box<[Item]>> where Box<[Item]>: BorrowOutSlice<Item> {
pub fn from_vec_resizing(vec: Vec<Item>) -> Self {
Cursor::new(vec.into_boxed_slice())
}
}
}
#[cfg(test)]
mod test {
use super::*;
use core::mem::MaybeUninit;
#[test]
fn slice() {
let mut uninit = [MaybeUninit::uninit(); 4];
let mut cursor = Cursor::new(&mut uninit as &mut [MaybeUninit<u8>]);
cursor.push(0).expect("Array full");
cursor.push(1).expect("Array full");
cursor.push(2).expect("Array full");
cursor.push(3).expect("Array full");
assert_eq!(cursor.written(), &[0, 1, 2, 3]);
assert_eq!(cursor.pop().expect("Empty array"), 3);
assert_eq!(cursor.try_pop_slice(2).expect("Array too short"), &[1, 2]);
cursor.push(24).expect("Array full");
cursor.push(42).expect("Array full");
cursor.push(47).expect("Array full");
let arr = cursor.try_cast_initialized().unwrap_or_else(|_| panic!("Cursor not filled"));
assert_eq!(arr, &[0, 24, 42, 47]);
}
#[test]
fn arr() {
let mut uninit = [MaybeUninit::uninit(); 4];
let mut cursor = Cursor::new(&mut uninit);
cursor.push(0).expect("Array full");
cursor.push(1).expect("Array full");
cursor.push(2).expect("Array full");
cursor.push(3).expect("Array full");
assert_eq!(cursor.written(), &[0, 1, 2, 3]);
assert_eq!(cursor.pop().expect("Empty array"), 3);
assert_eq!(cursor.try_pop_slice(2).expect("Array too short"), &[1, 2]);
cursor.push(24).expect("Array full");
cursor.push(42).expect("Array full");
cursor.push(47).expect("Array full");
let arr = cursor.try_cast_initialized().unwrap_or_else(|_| panic!("Cursor not filled"));
assert_eq!(arr, &[0, 24, 42, 47]);
}
#[test]
#[cfg(feature = "alloc")]
fn boxed_arr() {
use alloc::boxed::Box;
let uninit = Box::new([MaybeUninit::uninit(); 4]);
let mut cursor = Cursor::new(uninit);
cursor.push(0).expect("Array full");
cursor.push(1).expect("Array full");
cursor.push(2).expect("Array full");
cursor.push(3).expect("Array full");
assert_eq!(cursor.written(), &[0, 1, 2, 3]);
assert_eq!(cursor.pop().expect("Empty array"), 3);
assert_eq!(cursor.try_pop_slice(2).expect("Array too short"), &[1, 2]);
cursor.push(24).expect("Array full");
cursor.push(42).expect("Array full");
cursor.push(47).expect("Array full");
let arr = cursor.try_cast_initialized().unwrap_or_else(|_| panic!("Cursor not filled"));
assert_eq!(&*arr, &[0, 24, 42, 47]);
}
#[test]
#[cfg(feature = "alloc")]
fn boxed_slice() {
use alloc::vec::Vec;
let uninit = Vec::with_capacity(4);
let mut cursor = Cursor::from_vec_preserving_len(uninit);
cursor.push(0).expect("Array full");
cursor.push(1).expect("Array full");
cursor.push(2).expect("Array full");
cursor.push(3).expect("Array full");
assert_eq!(cursor.written(), &[0, 1, 2, 3]);
assert_eq!(cursor.pop().expect("Empty array"), 3);
assert_eq!(cursor.try_pop_slice(2).expect("Array too short"), &[1, 2]);
cursor.push(24).expect("Array full");
cursor.push(42).expect("Array full");
cursor.push(47).expect("Array full");
let arr = cursor.try_cast_initialized().unwrap_or_else(|_| panic!("Cursor not filled"));
assert_eq!(&*arr, &[0, 24, 42, 47]);
}
}