use crate::{macros::*, mem::MemValue};
use core::{
    mem,
    ops::{Deref, DerefMut},
};

mod box_byte_slice;
mod box_bytes;
mod byte_slice;
mod owned_byte_slice_cell_ptr;
mod tickertape;

pub use self::{
    box_byte_slice::*, box_bytes::*, byte_slice::*, owned_byte_slice_cell_ptr::*, tickertape::*,
};

#[allow(clippy::missing_safety_doc)]
pub trait ByteOrder {
    fn read(&self, off: usize) -> u8;
    unsafe fn read_unchecked(&self, off: usize) -> u8;

    fn read_le<T: MemValue>(&self, off: usize) -> T;
    unsafe fn read_le_unchecked<T: MemValue>(&self, off: usize) -> T;
    unsafe fn read_le_aligned<T: MemValue>(&self, off: usize) -> T;
    unsafe fn read_le_aligned_unchecked<T: MemValue>(&self, off: usize) -> T;

    fn read_be<T: MemValue>(&self, off: usize) -> T;
    unsafe fn read_be_unchecked<T: MemValue>(&self, off: usize) -> T;
    unsafe fn read_be_aligned<T: MemValue>(&self, off: usize) -> T;
    unsafe fn read_be_aligned_unchecked<T: MemValue>(&self, off: usize) -> T;

    fn read_ne<T: MemValue>(&self, off: usize) -> T;
    unsafe fn read_ne_unchecked<T: MemValue>(&self, off: usize) -> T;
    unsafe fn read_ne_aligned<T: MemValue>(&self, off: usize) -> T;
    unsafe fn read_ne_aligned_unchecked<T: MemValue>(&self, off: usize) -> T;

    /////////////////////////////////////////////////////////////////////

    fn write(&mut self, off: usize, value: u8);
    unsafe fn write_unchecked(&mut self, off: usize, value: u8);

    fn write_le<T: MemValue>(&mut self, off: usize, value: T);
    unsafe fn write_le_unchecked<T: MemValue>(&mut self, off: usize, value: T);
    unsafe fn write_le_aligned<T: MemValue>(&mut self, off: usize, value: T);
    unsafe fn write_le_aligned_unchecked<T: MemValue>(&mut self, off: usize, value: T);

    fn write_be<T: MemValue>(&mut self, off: usize, value: T);
    unsafe fn write_be_unchecked<T: MemValue>(&mut self, off: usize, value: T);
    unsafe fn write_be_aligned<T: MemValue>(&mut self, off: usize, value: T);
    unsafe fn write_be_aligned_unchecked<T: MemValue>(&mut self, off: usize, value: T);

    fn write_ne<T: MemValue>(&mut self, off: usize, value: T);
    unsafe fn write_ne_unchecked<T: MemValue>(&mut self, off: usize, value: T);
    unsafe fn write_ne_aligned<T: MemValue>(&mut self, off: usize, value: T);
    unsafe fn write_ne_aligned_unchecked<T: MemValue>(&mut self, off: usize, value: T);
}

////////////////////////////////////////////////////////////////////////////////////

#[repr(C, align(8))]
#[derive(Clone)]
pub struct Bytes<const LEN: usize>([u8; LEN]);

impl<const LEN: usize> Bytes<LEN> {
    #[inline]
    pub const fn new(value: [u8; LEN]) -> Self {
        Bytes(value)
    }

    #[inline]
    pub const fn into_inner(self) -> [u8; LEN] {
        self.0
    }

    #[inline]
    pub fn as_byte_slice(&self) -> ByteSlice {
        ByteSlice::new(&self[..])
    }

    #[inline]
    pub fn as_byte_mut_slice(&mut self) -> ByteMutSlice {
        ByteMutSlice::new(&mut self[..])
    }
}

impl<const LEN: usize> Deref for Bytes<LEN> {
    type Target = [u8; LEN];
    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<const LEN: usize> DerefMut for Bytes<LEN> {
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl<const LEN: usize> From<[u8; LEN]> for Bytes<LEN> {
    #[inline]
    fn from(other: [u8; LEN]) -> Self {
        Self::new(other)
    }
}

impl<const LEN: usize> From<Bytes<LEN>> for [u8; LEN] {
    #[inline]
    fn from(other: Bytes<LEN>) -> Self {
        other.0
    }
}

impl_byteorder!(Bytes<const LEN: usize>);
