#![no_std]
use core::ops::Bound::*;
use core::ops::RangeBounds;
#[derive(Debug)]
pub enum Error {
OutOfBoundsMove {
len: usize,
dest: (usize, usize)
},
InvalidBounds {
len: usize,
bounds: (usize, usize)
}
}
pub trait Moveslice<T, R> {
type Target;
type Err;
fn moveslice(&mut self, bounds: R, destination: Self::Target)
where R: RangeBounds<usize>;
fn try_moveslice(&mut self, bounds: R, destination: Self::Target) -> Result<(), Self::Err>
where R: RangeBounds<usize>;
}
impl<T: 'static,R,A> Moveslice<T,R> for A where A: AsMut<[T]> {
type Target = usize;
type Err = Error;
fn moveslice(&mut self, bounds: R, destination: Self::Target)
where R: RangeBounds<usize>
{
let res = self.try_moveslice(bounds, destination);
if let Err(Error::OutOfBoundsMove{len, dest: (x,y)}) = res {
panic!("Movement goes beyond bounds. [len = {}, destination = {}..{}]", len, x, y);
}
else if let Err(Error::InvalidBounds{len, bounds: (x,y)}) = res {
panic!("Bounds passed go beyond slice length. [len = {}, bounds = {}..{}]", len, x, y);
}
}
fn try_moveslice(&mut self, bounds: R, destination: Self::Target) -> Result<(), Self::Err>
where R: RangeBounds<usize>
{
let slice = self.as_mut();
let startbound = bounds.start_bound();
let endbound = bounds.end_bound();
let x = if let Included(x) = startbound {*x} else {0};
let y = if let Excluded(x) = endbound {*x}
else if let Included(x) = endbound {x+1}
else {slice.len()};
let chunk = (x,y);
if chunk.0 > slice.len() || chunk.1 > slice.len() {
return Err(Error::InvalidBounds {
len: slice.len(),
bounds: chunk
});
}
if destination > chunk.0 {
let chunksize = chunk.1 - chunk.0;
let index1 = chunk.0;
let index2 = destination + chunksize - index1;
let (_, mid) = slice.split_at_mut(index1);
let mid = if index2 <= mid.len() {
mid.split_at_mut(index2).0
} else {
return Err(Error::OutOfBoundsMove {
len: slice.len(),
dest: (destination, destination + chunksize),
});
};
mid.rotate_left(chunk.1-chunk.0);
} else if destination < chunk.0 {
let index1 = destination;
let index2 = chunk.1 - destination;
let (_, mid) = slice.split_at_mut(index1);
let mid = mid.split_at_mut(index2).0;
mid.rotate_right(chunk.1-chunk.0);
}
Ok(())
}
}