use core::ops::{Deref, DerefMut};
use core::slice::SliceIndex;
use crate::wire::{Reframe, Payload, PayloadError, PayloadMut, payload};
#[derive(Clone, Debug)]
pub struct Partial<C> {
inner: C,
end: usize,
}
impl<C> Partial<C> {
pub fn new(container: C) -> Self {
Partial {
inner: container,
end: 0,
}
}
pub fn inner(&self) -> &C {
&self.inner
}
pub fn inner_mut(&mut self) -> &mut C {
&mut self.inner
}
pub fn into_inner(self) -> C {
self.inner
}
pub fn set_len_unchecked(&mut self, len: usize) {
self.end = len;
}
pub fn len(&self) -> usize {
self.end
}
pub fn is_empty(&self) -> bool {
self.end == 0
}
pub fn inc(&mut self) {
self.end += 1;
}
pub fn dec(&mut self) {
self.end -= 1;
}
}
impl<C, T> Partial<C>
where C: Deref<Target=[T]>
{
pub fn new_full(inner: C) -> Self {
let end = inner.len();
Partial {
inner,
end,
}
}
pub fn capacity(&self) -> usize {
self.inner.len()
}
pub fn as_slice(&self) -> &[T] {
&self.inner[..self.end]
}
pub fn get<'a, I>(&'a self, idx: I) -> Option<&'a I::Output>
where I: SliceIndex<[T]>, T: 'a,
{
self.as_slice().get(idx)
}
}
impl<C, T> Partial<C>
where C: Deref<Target=[T]> + DerefMut,
{
pub fn init(&mut self) -> Option<&mut T> {
self.inner.get_mut(self.end)
}
pub fn insert_at(&mut self, pos: usize) -> Option<&mut T> {
let rotation = self.end.checked_sub(pos)
.expect("Index out of bounds");
let new_end = self.end.checked_add(1)?;
self.inner
.get_mut(pos..new_end)?
.rotate_left(rotation);
self.end = new_end;
Some(self.inner
.get_mut(pos)
.unwrap())
}
pub fn push(&mut self) -> Option<&mut T> {
self.insert_at(self.end)
}
pub fn remove_at(&mut self, pos: usize) -> Option<&mut T> {
let new_end = self.end.checked_sub(1)?;
let rotation = new_end.checked_sub(pos)?;
self.inner
.get_mut(pos..self.end)?
.rotate_right(rotation);
self.end = new_end;
Some(self.inner
.get_mut(self.end)
.unwrap())
}
pub fn pop(&mut self) -> Option<&mut T> {
self.remove_at(self.end.wrapping_sub(1))
}
pub fn as_mut_slice(&mut self) -> &mut [T] {
&mut self.inner[..self.end]
}
pub fn get_mut<'a, I>(&'a mut self, idx: I) -> Option<&'a mut I::Output>
where I: SliceIndex<[T]>, T: 'a,
{
self.as_mut_slice().get_mut(idx)
}
}
impl<C, T> Deref for Partial<C>
where C: Deref<Target=[T]>
{
type Target = [T];
fn deref(&self) -> &[T] {
self.as_slice()
}
}
impl<C, T> DerefMut for Partial<C>
where C: Deref<Target=[T]> + DerefMut
{
fn deref_mut(&mut self) -> &mut [T] {
self.as_mut_slice()
}
}
impl<C, T> AsRef<[T]> for Partial<C> where C: AsRef<[T]> {
fn as_ref(&self) -> &[T] {
&self.inner.as_ref()[..self.end]
}
}
impl<C, T> AsMut<[T]> for Partial<C> where C: AsMut<[T]> {
fn as_mut(&mut self) -> &mut [T] {
&mut self.inner.as_mut()[..self.end]
}
}
impl<C: Payload> Payload for Partial<C> {
fn payload(&self) -> &payload {
self.inner
.payload()
.as_slice()[..self.end]
.into()
}
}
impl<C: PayloadMut> PayloadMut for Partial<C> {
fn payload_mut(&mut self) -> &mut payload {
let len = self.end;
let slice = self.inner
.payload_mut()
.as_mut_slice();
(&mut slice[..len]).into()
}
fn resize(&mut self, len: usize) -> Result<(), PayloadError> {
if len <= self.inner.payload().len() {
self.end = len;
Ok(())
} else {
self.inner.resize(len)?;
self.end = len;
Ok(())
}
}
fn reframe(&mut self, reframe: Reframe) -> Result<(), PayloadError> {
self.resize(reframe.length)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn normal_operation() {
const SIZE: usize = 4;
let mut slice = [0; SIZE];
let mut partial = Partial::new(&mut slice[..]);
for i in 0..SIZE {
let element = partial.push().expect("Enough space");
*element = i;
}
assert_eq!(partial.len(), 4);
assert_eq!(partial.as_slice(), &[0, 1, 2, 3]);
for i in (0..SIZE).rev() {
let element = partial.pop().expect("Still one left");
assert_eq!(*element, i);
}
assert_eq!(partial.get(0), None);
assert_eq!(partial.get_mut(0), None);
}
#[test]
fn inserts() {
const SIZE: usize = 4;
let mut slice = [0; SIZE];
let mut partial = Partial::new(&mut slice[..]);
*partial.insert_at(0).unwrap() = 2;
*partial.insert_at(0).unwrap() = 0;
*partial.insert_at(1).unwrap() = 1;
*partial.insert_at(3).unwrap() = 3;
assert!(partial.insert_at(0).is_none());
assert!(partial.insert_at(1).is_none());
assert!(partial.insert_at(2).is_none());
assert!(partial.insert_at(3).is_none());
assert!(partial.insert_at(4).is_none());
assert_eq!(partial.as_slice(), [0, 1, 2, 3]);
}
#[test]
#[should_panic]
fn insert_at_invalid() {
let mut slice = [0; 1];
let mut partial = Partial::new(&mut slice[..]);
partial.insert_at(1);
}
#[test]
#[should_panic]
fn insert_at_oob() {
let mut slice = [0; 1];
let mut partial = Partial::new(&mut slice[..]);
assert!(partial.push().is_some());
assert!(partial.len() == 1);
let _x = partial.insert_at(2);
eprintln!("Found a place but shouldn't have: {:?}", _x);
}
}