use core::cell::Cell;

/// Wrapper around a slice that will increment the slice on reads
#[repr(transparent)]
pub struct TickerTape<'a, T = u8>(Cell<&'a [T]>);

impl<'a, T: Copy> TickerTape<'a, T> {
    pub const fn new(data: &'a [T]) -> Self {
        Self(Cell::new(data))
    }

    pub fn len(&self) -> usize {
        self.0.get().len()
    }

    #[inline]
    fn mov(&self, num: usize) {
        self.0.set(&self.0.get()[num..])
    }

    pub fn peek(&self) -> T {
        debug_assert!(self.len() != 0);
        self.0.get()[0]
    }

    pub fn read(&self) -> T {
        let ret = self.peek();
        self.mov(1);
        ret
    }

    pub fn take<const NUM: usize>(&self) -> [T; NUM] {
        debug_assert!(self.len() >= NUM);

        let ret = unsafe { *self.0.get().as_ptr().cast() };
        self.mov(NUM);
        ret
    }

    pub fn slice(&self, num: usize) -> &[T] {
        debug_assert!(self.len() >= num);

        let ret = &self.0.get()[..num];
        self.mov(num);
        ret
    }

    pub fn as_ptr(&self) -> *const T {
        self.0.get().as_ptr()
    }

    pub fn skip(&self, amt: usize) {
        self.mov(amt)
    }

    pub fn into_inner(self) -> &'a [T] {
        self.0.into_inner()
    }
}

impl<'a> From<&'a [u8]> for TickerTape<'a> {
    fn from(x: &'a [u8]) -> Self {
        TickerTape::new(x)
    }
}
