use std::borrow::{Borrow, BorrowMut};
use std::cmp::Ordering;
use std::fmt::{Debug, Error, Formatter};
use std::hash::{Hash, Hasher};
use std::io;
use std::iter::{FromIterator, FusedIterator};
use std::mem::{self, replace, ManuallyDrop};
use std::ops::{Deref, DerefMut, Index, IndexMut};
use std::ptr;
use std::slice::{
    from_raw_parts, from_raw_parts_mut, Iter as SliceIter, IterMut as SliceIterMut, SliceIndex,
};
use typenum::U64;
use crate::types::ChunkLength;
pub struct Chunk<A, N = U64>
where
    N: ChunkLength<A>,
{
    left: usize,
    right: usize,
    data: ManuallyDrop<N::SizedType>,
}
impl<A, N> Drop for Chunk<A, N>
where
    N: ChunkLength<A>,
{
    fn drop(&mut self) {
        if mem::needs_drop::<A>() {
            for i in self.left..self.right {
                unsafe { Chunk::force_drop(i, self) }
            }
        }
    }
}
impl<A, N> Clone for Chunk<A, N>
where
    A: Clone,
    N: ChunkLength<A>,
{
    fn clone(&self) -> Self {
        let mut out = Self::new();
        out.left = self.left;
        out.right = self.right;
        for index in self.left..self.right {
            unsafe { Chunk::force_write(index, self.values()[index].clone(), &mut out) }
        }
        out
    }
}
impl<A, N> Chunk<A, N>
where
    N: ChunkLength<A>,
{
    
    pub fn new() -> Self {
        let mut chunk: Self;
        unsafe {
            chunk = mem::zeroed();
            ptr::write(&mut chunk.left, 0);
            ptr::write(&mut chunk.right, 0);
        }
        chunk
    }
    
    pub fn unit(value: A) -> Self {
        let mut chunk: Self;
        unsafe {
            chunk = mem::zeroed();
            ptr::write(&mut chunk.left, 0);
            ptr::write(&mut chunk.right, 1);
            Chunk::force_write(0, value, &mut chunk);
        }
        chunk
    }
    
    pub fn pair(left: A, right: A) -> Self {
        let mut chunk: Self;
        unsafe {
            chunk = mem::zeroed();
            ptr::write(&mut chunk.left, 0);
            ptr::write(&mut chunk.right, 2);
            Chunk::force_write(0, left, &mut chunk);
            Chunk::force_write(1, right, &mut chunk);
        }
        chunk
    }
    
    
    
    
    pub fn drain_from(other: &mut Self) -> Self {
        let other_len = other.len();
        Self::from_front(other, other_len)
    }
    
    
    
    
    
    
    pub fn collect_from<I>(iter: &mut I, mut count: usize) -> Self
    where
        I: Iterator<Item = A>,
    {
        let mut chunk = Self::new();
        while count > 0 {
            count -= 1;
            chunk.push_back(
                iter.next()
                    .expect("Chunk::collect_from: underfull iterator"),
            );
        }
        chunk
    }
    
    
    
    
    pub fn from_front(other: &mut Self, count: usize) -> Self {
        let other_len = other.len();
        debug_assert!(count <= other_len);
        let mut chunk = Self::new();
        unsafe { Chunk::force_copy_to(other.left, 0, count, other, &mut chunk) };
        chunk.right = count;
        other.left += count;
        chunk
    }
    
    
    
    
    pub fn from_back(other: &mut Self, count: usize) -> Self {
        let other_len = other.len();
        debug_assert!(count <= other_len);
        let mut chunk = Self::new();
        unsafe { Chunk::force_copy_to(other.right - count, 0, count, other, &mut chunk) };
        chunk.right = count;
        other.right -= count;
        chunk
    }
    
    #[inline]
    pub fn len(&self) -> usize {
        self.right - self.left
    }
    
    #[inline]
    pub fn capacity() -> usize {
        N::USIZE
    }
    
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.left == self.right
    }
    
    #[inline]
    pub fn is_full(&self) -> bool {
        self.left == 0 && self.right == N::USIZE
    }
    #[inline]
    fn values(&self) -> &[A] {
        unsafe {
            from_raw_parts(
                &self.data as *const ManuallyDrop<N::SizedType> as *const A,
                N::USIZE,
            )
        }
    }
    #[inline]
    fn values_mut(&mut self) -> &mut [A] {
        unsafe {
            from_raw_parts_mut(
                &mut self.data as *mut ManuallyDrop<N::SizedType> as *mut A,
                N::USIZE,
            )
        }
    }
    
    #[inline]
    unsafe fn force_read(index: usize, chunk: &mut Self) -> A {
        ptr::read(&chunk.values()[index])
    }
    
    #[inline]
    unsafe fn force_write(index: usize, value: A, chunk: &mut Self) {
        ptr::write(&mut chunk.values_mut()[index], value)
    }
    
    #[inline]
    unsafe fn force_drop(index: usize, chunk: &mut Self) {
        ptr::drop_in_place(&mut chunk.values_mut()[index])
    }
    
    #[inline]
    unsafe fn force_copy(from: usize, to: usize, count: usize, chunk: &mut Self) {
        if count > 0 {
            ptr::copy(&chunk.values()[from], &mut chunk.values_mut()[to], count)
        }
    }
    
    #[inline]
    unsafe fn force_copy_to(
        from: usize,
        to: usize,
        count: usize,
        chunk: &mut Self,
        other: &mut Self,
    ) {
        if count > 0 {
            ptr::copy_nonoverlapping(&chunk.values()[from], &mut other.values_mut()[to], count)
        }
    }
    
    
    
    
    
    pub fn push_front(&mut self, value: A) {
        if self.is_full() {
            panic!("Chunk::push_front: can't push to full chunk");
        }
        if self.is_empty() {
            self.left = N::USIZE;
            self.right = N::USIZE;
        } else if self.left == 0 {
            self.left = N::USIZE - self.right;
            unsafe { Chunk::force_copy(0, self.left, self.right, self) };
            self.right = N::USIZE;
        }
        self.left -= 1;
        unsafe { Chunk::force_write(self.left, value, self) }
    }
    
    
    
    
    
    pub fn push_back(&mut self, value: A) {
        if self.is_full() {
            panic!("Chunk::push_back: can't push to full chunk");
        }
        if self.is_empty() {
            self.left = 0;
            self.right = 0;
        } else if self.right == N::USIZE {
            unsafe { Chunk::force_copy(self.left, 0, self.len(), self) };
            self.right = N::USIZE - self.left;
            self.left = 0;
        }
        unsafe { Chunk::force_write(self.right, value, self) }
        self.right += 1;
    }
    
    
    
    
    
    pub fn pop_front(&mut self) -> A {
        if self.is_empty() {
            panic!("Chunk::pop_front: can't pop from empty chunk");
        } else {
            let value = unsafe { Chunk::force_read(self.left, self) };
            self.left += 1;
            value
        }
    }
    
    
    
    
    
    pub fn pop_back(&mut self) -> A {
        if self.is_empty() {
            panic!("Chunk::pop_back: can't pop from empty chunk");
        } else {
            self.right -= 1;
            unsafe { Chunk::force_read(self.right, self) }
        }
    }
    
    
    
    
    
    pub fn drop_left(&mut self, index: usize) {
        if index > 0 {
            if index > self.len() {
                panic!("Chunk::drop_left: index out of bounds");
            }
            let start = self.left;
            for i in start..(start + index) {
                unsafe { Chunk::force_drop(i, self) }
            }
            self.left += index;
        }
    }
    
    
    
    
    
    pub fn drop_right(&mut self, index: usize) {
        if index > self.len() {
            panic!("Chunk::drop_right: index out of bounds");
        }
        if index == self.len() {
            return;
        }
        let start = self.left + index;
        for i in start..self.right {
            unsafe { Chunk::force_drop(i, self) }
        }
        self.right = start;
    }
    
    
    
    
    
    
    
    pub fn split_off(&mut self, index: usize) -> Self {
        if index > self.len() {
            panic!("Chunk::split: index out of bounds");
        }
        if index == self.len() {
            return Self::new();
        }
        let mut right_chunk = Self::new();
        let start = self.left + index;
        let len = self.right - start;
        unsafe { Chunk::force_copy_to(start, 0, len, self, &mut right_chunk) };
        right_chunk.right = len;
        self.right = start;
        right_chunk
    }
    
    
    
    
    
    pub fn append(&mut self, other: &mut Self) {
        let self_len = self.len();
        let other_len = other.len();
        if self_len + other_len > N::USIZE {
            panic!("Chunk::append: chunk size overflow");
        }
        if self.right + other_len > N::USIZE {
            unsafe { Chunk::force_copy(self.left, 0, self_len, self) };
            self.right -= self.left;
            self.left = 0;
        }
        unsafe { Chunk::force_copy_to(other.left, self.right, other_len, other, self) };
        self.right += other_len;
        other.left = 0;
        other.right = 0;
    }
    
    
    
    
    
    
    
    pub fn drain_from_front(&mut self, other: &mut Self, count: usize) {
        let self_len = self.len();
        let other_len = other.len();
        debug_assert!(self_len + count <= N::USIZE);
        debug_assert!(other_len >= count);
        if self.right + count > N::USIZE {
            unsafe { Chunk::force_copy(self.left, 0, self_len, self) };
            self.right -= self.left;
            self.left = 0;
        }
        unsafe { Chunk::force_copy_to(other.left, self.right, count, other, self) };
        self.right += count;
        other.left += count;
    }
    
    
    
    
    
    
    
    pub fn drain_from_back(&mut self, other: &mut Self, count: usize) {
        let self_len = self.len();
        let other_len = other.len();
        debug_assert!(self_len + count <= N::USIZE);
        debug_assert!(other_len >= count);
        if self.left < count {
            unsafe { Chunk::force_copy(self.left, N::USIZE - self_len, self_len, self) };
            self.left = N::USIZE - self_len;
            self.right = N::USIZE;
        }
        unsafe { Chunk::force_copy_to(other.right - count, self.left - count, count, other, self) };
        self.left -= count;
        other.right -= count;
    }
    
    
    
    
    
    pub fn set(&mut self, index: usize, value: A) -> A {
        replace(&mut self[index], value)
    }
    
    
    
    
    
    
    pub fn insert(&mut self, index: usize, value: A) {
        if self.is_full() {
            panic!("Chunk::insert: chunk is full");
        }
        if index > self.len() {
            panic!("Chunk::insert: index out of bounds");
        }
        let real_index = index + self.left;
        let left_size = index;
        let right_size = self.right - real_index;
        if self.right == N::USIZE || (self.left > 0 && left_size < right_size) {
            unsafe {
                Chunk::force_copy(self.left, self.left - 1, left_size, self);
                Chunk::force_write(real_index - 1, value, self);
            }
            self.left -= 1;
        } else {
            unsafe {
                Chunk::force_copy(real_index, real_index + 1, right_size, self);
                Chunk::force_write(real_index, value, self);
            }
            self.right += 1;
        }
    }
    
    
    
    
    
    
    
    
    pub fn remove(&mut self, index: usize) -> A {
        if index >= self.len() {
            panic!("Chunk::remove: index out of bounds");
        }
        let real_index = index + self.left;
        let value = unsafe { Chunk::force_read(real_index, self) };
        let left_size = index;
        let right_size = self.right - real_index - 1;
        if left_size < right_size {
            unsafe { Chunk::force_copy(self.left, self.left + 1, left_size, self) };
            self.left += 1;
        } else {
            unsafe { Chunk::force_copy(real_index + 1, real_index, right_size, self) };
            self.right -= 1;
        }
        value
    }
    
    pub fn drain(&mut self) -> Drain<'_, A, N> {
        Drain { chunk: self }
    }
    
    
    
    pub fn clear(&mut self) {
        for i in self.left..self.right {
            unsafe { Chunk::force_drop(i, self) }
        }
        self.left = 0;
        self.right = 0;
    }
    
    pub fn as_slice(&self) -> &[A] {
        unsafe {
            from_raw_parts(
                (&self.data as *const ManuallyDrop<N::SizedType> as *const A).add(self.left),
                self.len(),
            )
        }
    }
    
    pub fn as_mut_slice(&mut self) -> &mut [A] {
        unsafe {
            from_raw_parts_mut(
                (&mut self.data as *mut ManuallyDrop<N::SizedType> as *mut A).add(self.left),
                self.len(),
            )
        }
    }
}
impl<A, N> Default for Chunk<A, N>
where
    N: ChunkLength<A>,
{
    fn default() -> Self {
        Self::new()
    }
}
impl<A, N, I> Index<I> for Chunk<A, N>
where
    I: SliceIndex<[A]>,
    N: ChunkLength<A>,
{
    type Output = I::Output;
    fn index(&self, index: I) -> &Self::Output {
        self.as_slice().index(index)
    }
}
impl<A, N, I> IndexMut<I> for Chunk<A, N>
where
    I: SliceIndex<[A]>,
    N: ChunkLength<A>,
{
    fn index_mut(&mut self, index: I) -> &mut Self::Output {
        self.as_mut_slice().index_mut(index)
    }
}
impl<A, N> Debug for Chunk<A, N>
where
    A: Debug,
    N: ChunkLength<A>,
{
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str("Chunk")?;
        f.debug_list().entries(self.iter()).finish()
    }
}
impl<A, N> Hash for Chunk<A, N>
where
    A: Hash,
    N: ChunkLength<A>,
{
    fn hash<H>(&self, hasher: &mut H)
    where
        H: Hasher,
    {
        for item in self {
            item.hash(hasher)
        }
    }
}
impl<A, N, Slice> PartialEq<Slice> for Chunk<A, N>
where
    Slice: Borrow<[A]>,
    A: PartialEq,
    N: ChunkLength<A>,
{
    fn eq(&self, other: &Slice) -> bool {
        self.as_slice() == other.borrow()
    }
}
impl<A, N> Eq for Chunk<A, N>
where
    A: Eq,
    N: ChunkLength<A>,
{
}
impl<A, N> PartialOrd for Chunk<A, N>
where
    A: PartialOrd,
    N: ChunkLength<A>,
{
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.iter().partial_cmp(other.iter())
    }
}
impl<A, N> Ord for Chunk<A, N>
where
    A: Ord,
    N: ChunkLength<A>,
{
    fn cmp(&self, other: &Self) -> Ordering {
        self.iter().cmp(other.iter())
    }
}
impl<N> io::Write for Chunk<u8, N>
where
    N: ChunkLength<u8>,
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let old_len = self.len();
        self.extend(buf.iter().cloned().take(N::USIZE - old_len));
        Ok(self.len() - old_len)
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}
impl<A, N> Borrow<[A]> for Chunk<A, N>
where
    N: ChunkLength<A>,
{
    fn borrow(&self) -> &[A] {
        self.as_slice()
    }
}
impl<A, N> BorrowMut<[A]> for Chunk<A, N>
where
    N: ChunkLength<A>,
{
    fn borrow_mut(&mut self) -> &mut [A] {
        self.as_mut_slice()
    }
}
impl<A, N> AsRef<[A]> for Chunk<A, N>
where
    N: ChunkLength<A>,
{
    fn as_ref(&self) -> &[A] {
        self.as_slice()
    }
}
impl<A, N> AsMut<[A]> for Chunk<A, N>
where
    N: ChunkLength<A>,
{
    fn as_mut(&mut self) -> &mut [A] {
        self.as_mut_slice()
    }
}
impl<A, N> Deref for Chunk<A, N>
where
    N: ChunkLength<A>,
{
    type Target = [A];
    fn deref(&self) -> &Self::Target {
        self.as_slice()
    }
}
impl<A, N> DerefMut for Chunk<A, N>
where
    N: ChunkLength<A>,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.as_mut_slice()
    }
}
impl<A, N> FromIterator<A> for Chunk<A, N>
where
    N: ChunkLength<A>,
{
    fn from_iter<I>(it: I) -> Self
    where
        I: IntoIterator<Item = A>,
    {
        let mut chunk = Self::new();
        for item in it {
            chunk.push_back(item);
        }
        chunk
    }
}
impl<'a, A, N> IntoIterator for &'a Chunk<A, N>
where
    N: ChunkLength<A>,
{
    type Item = &'a A;
    type IntoIter = SliceIter<'a, A>;
    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}
impl<'a, A, N> IntoIterator for &'a mut Chunk<A, N>
where
    N: ChunkLength<A>,
{
    type Item = &'a mut A;
    type IntoIter = SliceIterMut<'a, A>;
    fn into_iter(self) -> Self::IntoIter {
        self.iter_mut()
    }
}
impl<A, N> Extend<A> for Chunk<A, N>
where
    N: ChunkLength<A>,
{
    
    
    
    
    
    fn extend<I>(&mut self, it: I)
    where
        I: IntoIterator<Item = A>,
    {
        for item in it {
            self.push_back(item);
        }
    }
}
impl<'a, A, N> Extend<&'a A> for Chunk<A, N>
where
    A: 'a + Copy,
    N: ChunkLength<A>,
{
    
    
    
    
    
    fn extend<I>(&mut self, it: I)
    where
        I: IntoIterator<Item = &'a A>,
    {
        for item in it {
            self.push_back(*item);
        }
    }
}
pub struct Iter<A, N>
where
    N: ChunkLength<A>,
{
    chunk: Chunk<A, N>,
}
impl<A, N> Iterator for Iter<A, N>
where
    N: ChunkLength<A>,
{
    type Item = A;
    fn next(&mut self) -> Option<Self::Item> {
        if self.chunk.is_empty() {
            None
        } else {
            Some(self.chunk.pop_front())
        }
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.chunk.len(), Some(self.chunk.len()))
    }
}
impl<A, N> DoubleEndedIterator for Iter<A, N>
where
    N: ChunkLength<A>,
{
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.chunk.is_empty() {
            None
        } else {
            Some(self.chunk.pop_back())
        }
    }
}
impl<A, N> ExactSizeIterator for Iter<A, N> where N: ChunkLength<A> {}
impl<A, N> FusedIterator for Iter<A, N> where N: ChunkLength<A> {}
impl<A, N> IntoIterator for Chunk<A, N>
where
    N: ChunkLength<A>,
{
    type Item = A;
    type IntoIter = Iter<A, N>;
    fn into_iter(self) -> Self::IntoIter {
        Iter { chunk: self }
    }
}
pub struct Drain<'a, A, N>
where
    A: 'a,
    N: ChunkLength<A> + 'a,
{
    chunk: &'a mut Chunk<A, N>,
}
impl<'a, A, N> Iterator for Drain<'a, A, N>
where
    A: 'a,
    N: ChunkLength<A> + 'a,
{
    type Item = A;
    fn next(&mut self) -> Option<Self::Item> {
        if self.chunk.is_empty() {
            None
        } else {
            Some(self.chunk.pop_front())
        }
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.chunk.len(), Some(self.chunk.len()))
    }
}
impl<'a, A, N> ExactSizeIterator for Drain<'a, A, N>
where
    A: 'a,
    N: ChunkLength<A> + 'a,
{
}
impl<'a, A, N> FusedIterator for Drain<'a, A, N>
where
    A: 'a,
    N: ChunkLength<A> + 'a,
{
}
#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn is_full() {
        let mut chunk = Chunk::<_, U64>::new();
        for i in 0..64 {
            assert_eq!(false, chunk.is_full());
            chunk.push_back(i);
        }
        assert_eq!(true, chunk.is_full());
    }
    #[test]
    fn push_back_front() {
        let mut chunk = Chunk::<_, U64>::new();
        for i in 12..20 {
            chunk.push_back(i);
        }
        assert_eq!(8, chunk.len());
        for i in (0..12).rev() {
            chunk.push_front(i);
        }
        assert_eq!(20, chunk.len());
        for i in 20..32 {
            chunk.push_back(i);
        }
        assert_eq!(32, chunk.len());
        let right: Vec<i32> = chunk.into_iter().collect();
        let left: Vec<i32> = (0..32).collect();
        assert_eq!(left, right);
    }
    #[test]
    fn push_and_pop() {
        let mut chunk = Chunk::<_, U64>::new();
        for i in 0..64 {
            chunk.push_back(i);
        }
        for i in 0..64 {
            assert_eq!(i, chunk.pop_front());
        }
        for i in 0..64 {
            chunk.push_front(i);
        }
        for i in 0..64 {
            assert_eq!(i, chunk.pop_back());
        }
    }
    #[test]
    fn drop_left() {
        let mut chunk = Chunk::<_, U64>::new();
        for i in 0..6 {
            chunk.push_back(i);
        }
        chunk.drop_left(3);
        let vec: Vec<i32> = chunk.into_iter().collect();
        assert_eq!(vec![3, 4, 5], vec);
    }
    #[test]
    fn drop_right() {
        let mut chunk = Chunk::<_, U64>::new();
        for i in 0..6 {
            chunk.push_back(i);
        }
        chunk.drop_right(3);
        let vec: Vec<i32> = chunk.into_iter().collect();
        assert_eq!(vec![0, 1, 2], vec);
    }
    #[test]
    fn split_off() {
        let mut left = Chunk::<_, U64>::new();
        for i in 0..6 {
            left.push_back(i);
        }
        let right = left.split_off(3);
        let left_vec: Vec<i32> = left.into_iter().collect();
        let right_vec: Vec<i32> = right.into_iter().collect();
        assert_eq!(vec![0, 1, 2], left_vec);
        assert_eq!(vec![3, 4, 5], right_vec);
    }
    #[test]
    fn append() {
        let mut left = Chunk::<_, U64>::new();
        for i in 0..32 {
            left.push_back(i);
        }
        let mut right = Chunk::<_, U64>::new();
        for i in (32..64).rev() {
            right.push_front(i);
        }
        left.append(&mut right);
        let out_vec: Vec<i32> = left.into_iter().collect();
        let should_vec: Vec<i32> = (0..64).collect();
        assert_eq!(should_vec, out_vec);
    }
    #[test]
    fn ref_iter() {
        let mut chunk = Chunk::<_, U64>::new();
        for i in 0..64 {
            chunk.push_back(i);
        }
        let out_vec: Vec<&i32> = chunk.iter().collect();
        let should_vec_p: Vec<i32> = (0..64).collect();
        let should_vec: Vec<&i32> = should_vec_p.iter().collect();
        assert_eq!(should_vec, out_vec);
    }
    #[test]
    fn mut_ref_iter() {
        let mut chunk = Chunk::<_, U64>::new();
        for i in 0..64 {
            chunk.push_back(i);
        }
        let out_vec: Vec<&mut i32> = chunk.iter_mut().collect();
        let mut should_vec_p: Vec<i32> = (0..64).collect();
        let should_vec: Vec<&mut i32> = should_vec_p.iter_mut().collect();
        assert_eq!(should_vec, out_vec);
    }
    #[test]
    fn consuming_iter() {
        let mut chunk = Chunk::<_, U64>::new();
        for i in 0..64 {
            chunk.push_back(i);
        }
        let out_vec: Vec<i32> = chunk.into_iter().collect();
        let should_vec: Vec<i32> = (0..64).collect();
        assert_eq!(should_vec, out_vec);
    }
    #[test]
    fn insert_middle() {
        let mut chunk = Chunk::<_, U64>::new();
        for i in 0..32 {
            chunk.push_back(i);
        }
        for i in 33..64 {
            chunk.push_back(i);
        }
        chunk.insert(32, 32);
        let out_vec: Vec<i32> = chunk.into_iter().collect();
        let should_vec: Vec<i32> = (0..64).collect();
        assert_eq!(should_vec, out_vec);
    }
    #[test]
    fn insert_back() {
        let mut chunk = Chunk::<_, U64>::new();
        for i in 0..63 {
            chunk.push_back(i);
        }
        chunk.insert(63, 63);
        let out_vec: Vec<i32> = chunk.into_iter().collect();
        let should_vec: Vec<i32> = (0..64).collect();
        assert_eq!(should_vec, out_vec);
    }
    #[test]
    fn insert_front() {
        let mut chunk = Chunk::<_, U64>::new();
        for i in 1..64 {
            chunk.push_front(64 - i);
        }
        chunk.insert(0, 0);
        let out_vec: Vec<i32> = chunk.into_iter().collect();
        let should_vec: Vec<i32> = (0..64).collect();
        assert_eq!(should_vec, out_vec);
    }
    #[test]
    fn remove_value() {
        let mut chunk = Chunk::<_, U64>::new();
        for i in 0..64 {
            chunk.push_back(i);
        }
        chunk.remove(32);
        let out_vec: Vec<i32> = chunk.into_iter().collect();
        let should_vec: Vec<i32> = (0..32).chain(33..64).collect();
        assert_eq!(should_vec, out_vec);
    }
    use std::sync::atomic::{AtomicUsize, Ordering};
    struct DropTest<'a> {
        counter: &'a AtomicUsize,
    }
    impl<'a> DropTest<'a> {
        fn new(counter: &'a AtomicUsize) -> Self {
            counter.fetch_add(1, Ordering::Relaxed);
            DropTest { counter }
        }
    }
    impl<'a> Drop for DropTest<'a> {
        fn drop(&mut self) {
            self.counter.fetch_sub(1, Ordering::Relaxed);
        }
    }
    #[test]
    fn dropping() {
        let counter = AtomicUsize::new(0);
        {
            let mut chunk: Chunk<DropTest> = Chunk::new();
            for _i in 0..20 {
                chunk.push_back(DropTest::new(&counter))
            }
            for _i in 0..20 {
                chunk.push_front(DropTest::new(&counter))
            }
            assert_eq!(40, counter.load(Ordering::Relaxed));
            for _i in 0..10 {
                chunk.pop_back();
            }
            assert_eq!(30, counter.load(Ordering::Relaxed));
        }
        assert_eq!(0, counter.load(Ordering::Relaxed));
    }
}