use {Bits, BitsMut, BitSliceable, BlockType};
use iter::BlockIter;
use range_compat::*;
#[derive(Copy, Clone, Debug)]
pub struct BitSliceAdapter<T> {
    bits:  T,
    start: u64,
    len:   u64,
}
impl<T: Bits> BitSliceAdapter<T> {
    
    
    
    
    
    
    
    pub fn new(bits: T, start: u64, len: u64) -> Self {
        assert!( start + len <= bits.bit_len(),
                 "BitSliceAdapter::new: out of bounds");
        BitSliceAdapter { bits, start, len }
    }
    
    
    
    
    
    
    
    
    fn reslice(self, start: u64, len: u64) -> Self {
        assert!( start + len <= self.bit_len(),
                 "BitSliceAdapter::reslice: out of bounds" );
        BitSliceAdapter {
            bits:  self.bits,
            start: self.start + start,
            len,
        }
    }
    
    
    
    
    
    
    
    
    fn reslice_ref(&self, start: u64, len: u64) -> BitSliceAdapter<&T> {
        assert!( start + len <= self.bit_len(),
                 "BitSliceAdapter::reslice: out of bounds" );
        BitSliceAdapter {
            bits:  &self.bits,
            start: self.start + start,
            len,
        }
    }
}
impl<T, U> PartialEq<U> for BitSliceAdapter<T>
    where T: Bits,
          U: Bits<Block = T::Block> {
    fn eq(&self, other: &U) -> bool {
        BlockIter::new(self) == BlockIter::new(other)
    }
}
macro_rules! impl_bit_sliceable_adapter {
    (
        $(
            impl[ $($param:tt)* ] BitSliceable for $target:ty ;
        )+
    ) => {
        $(
            impl<$($param)*> ::BitSliceable<::std::ops::Range<u64>> for $target {
                type Slice = ::adapter::BitSliceAdapter<Self>;
                fn bit_slice(self, range: ::std::ops::Range<u64>) -> Self::Slice {
                    assert!( range.start <= range.end,
                             format!("{}::slice: bad range", stringify!($target)) );
                    ::adapter::BitSliceAdapter::new(self, range.start, range.end - range.start)
                }
            }
            impl<$($param)*> ::BitSliceable<::std::ops::RangeFrom<u64>> for $target {
                type Slice = ::adapter::BitSliceAdapter<Self>;
                fn bit_slice(self, range: ::std::ops::RangeFrom<u64>) -> Self::Slice {
                    let len = self.bit_len();
                    self.bit_slice(range.start .. len)
                }
            }
            impl<$($param)*> ::BitSliceable<::std::ops::RangeTo<u64>> for $target {
                type Slice = ::adapter::BitSliceAdapter<Self>;
                fn bit_slice(self, range: ::std::ops::RangeTo<u64>) -> Self::Slice {
                    ::adapter::BitSliceAdapter::new(self, 0, range.end)
                }
            }
            impl<$($param)*> ::BitSliceable<::std::ops::RangeFull> for $target {
                type Slice = ::adapter::BitSliceAdapter<Self>;
                fn bit_slice(self, _range: ::std::ops::RangeFull) -> Self::Slice {
                    let len = self.bit_len();
                    ::adapter::BitSliceAdapter::new(self, 0, len)
                }
            }
            #[cfg(inclusive_range)]
            impl<$($param)*> ::BitSliceable<::std::ops::RangeInclusive<u64>> for $target {
                type Slice = ::adapter::BitSliceAdapter<Self>;
                fn bit_slice(self, range: ::std::ops::RangeInclusive<u64>) -> Self::Slice {
                    let (start, end) = ::range_compat::get_inclusive_bounds(range)
                        .expect("BitSliceable::bit_slice: bad inclusive range");
                    ::adapter::BitSliceAdapter::new(self, start, end - start + 1)
                }
            }
            #[cfg(inclusive_range)]
            impl<$($param)*> ::BitSliceable<::std::ops::RangeToInclusive<u64>> for $target {
                type Slice = ::adapter::BitSliceAdapter<Self>;
                fn bit_slice(self, range: ::std::ops::RangeToInclusive<u64>) -> Self::Slice {
                    ::adapter::BitSliceAdapter::new(self, 0, range.end + 1)
                }
            }
        )+
    };
}
impl<T: Bits> Bits for BitSliceAdapter<T> {
    type Block = T::Block;
    fn bit_len(&self) -> u64 {
        self.len
    }
    fn get_bit(&self, position: u64) -> bool {
        assert!( position < self.bit_len(),
                 "BitSliceAdapter::get_bit: out of bounds" );
        self.bits.get_bit(self.start + position)
    }
    fn get_block(&self, position: usize) -> Self::Block {
        assert!( position < self.block_len(),
                 "BitSliceAdapter::get_block: out of bounds" );
        let (real_start, real_len) =
            get_block_addr::<T::Block>(self.start, self.len, position);
        self.bits.get_bits(real_start, real_len)
    }
    fn get_bits(&self, start: u64, count: usize) -> Self::Block {
        assert!( start + count as u64 <= self.bit_len(),
                 "BitSliceAdapter::get_bits: out of bounds" );
        self.bits.get_bits(self.start + start, count)
    }
}
impl<T: BitsMut> BitsMut for BitSliceAdapter<T> {
    fn set_bit(&mut self, position: u64, value: bool) {
        assert!( position < self.bit_len(),
                 "BitSliceAdapter::set_bit: out of bounds" );
        self.bits.set_bit(self.start + position, value);
    }
    fn set_block(&mut self, position: usize, value: Self::Block) {
        assert!( position < self.block_len(),
                 "BitSliceAdapter::get_block: out of bounds" );
        let (real_start, real_len) =
            get_block_addr::<T::Block>(self.start, self.len, position);
        self.bits.set_bits(real_start, real_len, value);
    }
    fn set_bits(&mut self, start: u64, count: usize, value: Self::Block) {
        assert!( start + count as u64 <= self.bit_len(),
                 "BitSliceAdapter::set_bits: out of bounds" );
        self.bits.set_bits(self.start + start, count, value);
    }
}
fn get_block_addr<Block: BlockType>(start: u64, len: u64, position: usize)
                                    -> (u64, usize) {
    let real_start = start + Block::mul_nbits(position);
    let block_size = Block::nbits() as u64;
    let real_len   = if real_start + block_size < start + len {
        block_size
    } else {
        (start + len - real_start)
    };
    (real_start, real_len as usize)
}
impl_index_from_bits! {
    impl[T: Bits] Index<u64> for BitSliceAdapter<T>;
}
impl<T: Bits> BitSliceable<Range<u64>> for BitSliceAdapter<T> {
    type Slice = Self;
    fn bit_slice(self, range: Range<u64>) -> Self::Slice {
        assert!( range.start <= range.end,
                 "BitSliceAdapter::bit_slice: bad range" );
        self.reslice(range.start, range.end - range.start)
    }
}
impl<T: Bits> BitSliceable<RangeTo<u64>> for BitSliceAdapter<T> {
    type Slice = Self;
    fn bit_slice(self, range: RangeTo<u64>) -> Self::Slice {
        self.reslice(0, range.end)
    }
}
impl<T: Bits> BitSliceable<RangeFrom<u64>> for BitSliceAdapter<T> {
    type Slice = Self;
    fn bit_slice(self, range: RangeFrom<u64>) -> Self::Slice {
        let len = self.bit_len();
        assert!( range.start <= len,
                 "BitSliceAdapter::bit_slice: out of bounds" );
        self.reslice(range.start, len - range.start)
    }
}
impl<T: Bits> BitSliceable<RangeFull> for BitSliceAdapter<T> {
    type Slice = Self;
    fn bit_slice(self, _range: RangeFull) -> Self::Slice {
        self
    }
}
#[cfg(inclusive_range)]
impl<T: Bits> BitSliceable<RangeInclusive<u64>> for BitSliceAdapter<T> {
    type Slice = Self;
    fn bit_slice(self, range: RangeInclusive<u64>) -> Self::Slice {
        let (start, limit) = get_inclusive_bounds(range)
            .expect("BitSliceAdapter::bit_slice: bad range");
        self.reslice(start, limit - start + 1)
    }
}
#[cfg(inclusive_range)]
impl<T: Bits> BitSliceable<RangeToInclusive<u64>> for BitSliceAdapter<T> {
    type Slice = Self;
    fn bit_slice(self, range: RangeToInclusive<u64>) -> Self::Slice {
        self.reslice(0, range.end + 1)
    }
}
impl<'a, T: Bits> BitSliceable<Range<u64>> for &'a BitSliceAdapter<T> {
    type Slice = BitSliceAdapter<&'a T>;
    fn bit_slice(self, range: Range<u64>) -> Self::Slice {
        assert!( range.start <= range.end,
                 "BitSliceAdapter::bit_slice: bad range" );
        self.reslice_ref(range.start, range.end - range.start)
    }
}
impl<'a, T: Bits> BitSliceable<RangeTo<u64>> for &'a BitSliceAdapter<T> {
    type Slice = BitSliceAdapter<&'a T>;
    fn bit_slice(self, range: RangeTo<u64>) -> Self::Slice {
        self.reslice_ref(0, range.end)
    }
}
impl<'a, T: Bits> BitSliceable<RangeFrom<u64>> for &'a BitSliceAdapter<T> {
    type Slice = BitSliceAdapter<&'a T>;
    fn bit_slice(self, range: RangeFrom<u64>) -> Self::Slice {
        let len = self.bit_len();
        assert!( range.start <= len,
                 "BitSliceAdapter::bit_slice: out of bounds" );
        self.reslice_ref(range.start, len - range.start)
    }
}
impl<'a, T: Bits> BitSliceable<RangeFull> for &'a BitSliceAdapter<T> {
    type Slice = BitSliceAdapter<&'a T>;
    fn bit_slice(self, _range: RangeFull) -> Self::Slice {
        self.reslice_ref(0, self.bit_len())
    }
}
#[cfg(inclusive_range)]
impl<'a, T: Bits> BitSliceable<RangeInclusive<u64>> for &'a BitSliceAdapter<T> {
    type Slice = BitSliceAdapter<&'a T>;
    fn bit_slice(self, range: RangeInclusive<u64>) -> Self::Slice {
        let (start, limit) = get_inclusive_bounds(range)
            .expect("BitSliceAdapter::bit_slice: bad range");
        self.reslice_ref(start, limit - start + 1)
    }
}
#[cfg(inclusive_range)]
impl<'a, T: Bits> BitSliceable<RangeToInclusive<u64>> for &'a BitSliceAdapter<T> {
    type Slice = BitSliceAdapter<&'a T>;
    fn bit_slice(self, range: RangeToInclusive<u64>) -> Self::Slice {
        self.reslice_ref(0, range.end + 1)
    }
}