use core::ptr;
mod pair;
pub use pair::Pair;
#[inline]
pub fn invariants<T>(slice: &[T], head: usize, len: usize) -> bool {
let cap = slice.len();
ensure!(cap > 0, false);
ensure!(cap > head, false);
ensure!(cap >= len, false);
true
}
#[inline]
pub fn wrap<T>(slice: &[T], head: usize, len: usize) -> usize {
assert!(invariants(slice, head, len));
let cursor = head + len;
if slice.len().is_power_of_two() {
cursor & (slice.len() - 1)
} else {
cursor % slice.len()
}
}
#[inline]
fn tail<T>(slice: &[T], head: usize, len: usize) -> usize {
assert!(invariants(slice, head, len));
wrap(slice, head, len)
}
#[inline]
pub fn filled<T>(slice: &mut [T], head: usize, len: usize) -> Pair<&mut [T]> {
assert!(invariants(slice, head, len));
let tail = tail(slice, head, len);
if is_contiguous(slice, head, len) {
let head = &mut slice[head..tail];
let tail: &mut [T] = &mut [];
debug_assert_eq!(head.len(), len);
return (head, tail).into();
}
let (bytes, head) = slice.split_at_mut(head);
let (tail, _unfilled) = bytes.split_at_mut(tail);
if head.is_empty() {
debug_assert!(tail.is_empty());
}
debug_assert_eq!(head.len() + tail.len(), len);
(head, tail).into()
}
#[inline]
pub fn unfilled<T>(slice: &mut [T], head: usize, len: usize) -> Pair<&mut [T]> {
assert!(invariants(slice, head, len));
let cap = slice.len();
let tail = tail(slice, head, len);
let remaining_capacity = cap - len;
if !is_contiguous(slice, head, len) {
let head = &mut slice[tail..head];
let tail: &mut [T] = &mut [];
debug_assert_eq!(head.len(), remaining_capacity);
return (head, tail).into();
}
let (slice, head_slice) = slice.split_at_mut(tail);
let (tail_slice, _filled) = slice.split_at_mut(head);
let head = head_slice;
let tail = tail_slice;
debug_assert!(!head.is_empty());
debug_assert_eq!(head.len() + tail.len(), remaining_capacity);
(head, tail).into()
}
#[inline]
pub fn is_contiguous<T>(slice: &[T], head: usize, len: usize) -> bool {
assert!(invariants(slice, head, len));
head + len < slice.len()
}
#[inline]
pub fn make_contiguous<T>(slice: &mut [T], head_out: &mut usize, len: usize) {
let head = *head_out;
assert!(invariants(slice, head, len));
ensure!(!is_contiguous(slice, head, len));
let cap = slice.len();
debug_assert!(len <= cap);
debug_assert!(head <= cap);
let free = cap - len;
let head_len = cap - head;
let tail = len - head_len;
let tail_len = tail;
if free >= head_len {
unsafe {
copy(slice, 0, head_len, tail_len);
copy_nonoverlapping(slice, head, 0, head_len);
}
*head_out = 0;
} else if free >= tail_len {
unsafe {
copy(slice, head, tail, head_len);
copy_nonoverlapping(slice, 0, tail + head_len, tail_len);
}
*head_out = tail;
} else {
if head_len > tail_len {
unsafe {
if free != 0 {
copy(slice, 0, free, tail_len);
}
let slice = &mut slice[free..cap];
slice.rotate_left(tail_len);
*head_out = free;
}
} else {
unsafe {
if free != 0 {
copy(slice, head, tail_len, head_len);
}
let slice = &mut slice[..len];
slice.rotate_right(head_len);
*head_out = 0;
}
}
}
}
#[inline]
unsafe fn copy<T>(slice: &mut [T], src: usize, dst: usize, len: usize) {
debug_assert!(
dst + len <= slice.len(),
"copy dst={} src={} len={} cap={}",
dst,
src,
len,
slice.len()
);
debug_assert!(
src + len <= slice.len(),
"copy dst={} src={} len={} cap={}",
dst,
src,
len,
slice.len()
);
let ptr = slice.as_mut_ptr();
unsafe {
ptr::copy(ptr.add(src), ptr.add(dst), len);
}
}
#[inline]
unsafe fn copy_nonoverlapping<T>(slice: &mut [T], src: usize, dst: usize, len: usize) {
debug_assert!(
dst + len <= slice.len(),
"cno dst={} src={} len={} cap={}",
dst,
src,
len,
slice.len()
);
debug_assert!(
src + len <= slice.len(),
"cno dst={} src={} len={} cap={}",
dst,
src,
len,
slice.len()
);
let ptr = slice.as_mut_ptr();
unsafe {
ptr::copy_nonoverlapping(ptr.add(src), ptr.add(dst), len);
}
}