extern crate alloc;
use alloc::vec;
use core::ops::{Deref, DerefMut, Index, IndexMut, Range, RangeFrom, RangeFull, RangeTo};
use nex_core;
pub trait Packet {
    fn packet(&self) -> &[u8];
    fn payload(&self) -> &[u8];
}
impl<T: Packet> Packet for alloc::boxed::Box<T> {
    fn packet(&self) -> &[u8] {
        self.deref().packet()
    }
    fn payload(&self) -> &[u8] {
        self.deref().payload()
    }
}
impl<T: Packet> Packet for &T {
    fn packet(&self) -> &[u8] {
        (*self).packet()
    }
    fn payload(&self) -> &[u8] {
        (*self).payload()
    }
}
pub trait MutablePacket: Packet {
    fn packet_mut(&mut self) -> &mut [u8];
    fn payload_mut(&mut self) -> &mut [u8];
    fn clone_from<T: Packet>(&mut self, other: &T) {
        use core::ptr;
        assert!(self.packet().len() >= other.packet().len());
        unsafe {
            ptr::copy_nonoverlapping(
                other.packet().as_ptr(),
                self.packet_mut().as_mut_ptr(),
                other.packet().len(),
            );
        }
    }
}
pub trait FromPacket: Packet {
    type T;
    fn from_packet(&self) -> Self::T;
}
pub trait PacketSize: Packet {
    fn packet_size(&self) -> usize;
}
macro_rules! impl_index {
    ($t:ident, $index_t:ty, $output_t:ty) => {
        impl<'p> Index<$index_t> for $t<'p> {
            type Output = $output_t;
            #[inline]
            fn index(&self, index: $index_t) -> &$output_t {
                &self.as_slice().index(index)
            }
        }
    };
}
macro_rules! impl_index_mut {
    ($t:ident, $index_t:ty, $output_t:ty) => {
        impl<'p> IndexMut<$index_t> for $t<'p> {
            #[inline]
            fn index_mut(&mut self, index: $index_t) -> &mut $output_t {
                self.as_mut_slice().index_mut(index)
            }
        }
    };
}
#[derive(PartialEq)]
pub enum PacketData<'p> {
    Owned(vec::Vec<u8>),
    Borrowed(&'p [u8]),
}
impl<'p> PacketData<'p> {
    #[inline]
    pub fn as_slice(&self) -> &[u8] {
        match self {
            &PacketData::Owned(ref data) => data.deref(),
            &PacketData::Borrowed(ref data) => data,
        }
    }
    #[inline]
    pub fn to_immutable(self) -> PacketData<'p> {
        self
    }
    #[inline]
    pub fn len(&self) -> usize {
        self.as_slice().len()
    }
}
impl_index!(PacketData, usize, u8);
impl_index!(PacketData, Range<usize>, [u8]);
impl_index!(PacketData, RangeTo<usize>, [u8]);
impl_index!(PacketData, RangeFrom<usize>, [u8]);
impl_index!(PacketData, RangeFull, [u8]);
#[derive(PartialEq)]
pub enum MutPacketData<'p> {
    Owned(vec::Vec<u8>),
    Borrowed(&'p mut [u8]),
}
impl<'p> MutPacketData<'p> {
    #[inline]
    pub fn as_slice(&self) -> &[u8] {
        match self {
            &MutPacketData::Owned(ref data) => data.deref(),
            &MutPacketData::Borrowed(ref data) => data,
        }
    }
    #[inline]
    pub fn as_mut_slice(&mut self) -> &mut [u8] {
        match self {
            &mut MutPacketData::Owned(ref mut data) => data.deref_mut(),
            &mut MutPacketData::Borrowed(ref mut data) => data,
        }
    }
    #[inline]
    pub fn to_immutable(self) -> PacketData<'p> {
        match self {
            MutPacketData::Owned(data) => PacketData::Owned(data),
            MutPacketData::Borrowed(data) => PacketData::Borrowed(data),
        }
    }
    #[inline]
    pub fn len(&self) -> usize {
        self.as_slice().len()
    }
}
impl_index!(MutPacketData, usize, u8);
impl_index!(MutPacketData, Range<usize>, [u8]);
impl_index!(MutPacketData, RangeTo<usize>, [u8]);
impl_index!(MutPacketData, RangeFrom<usize>, [u8]);
impl_index!(MutPacketData, RangeFull, [u8]);
impl_index_mut!(MutPacketData, usize, u8);
impl_index_mut!(MutPacketData, Range<usize>, [u8]);
impl_index_mut!(MutPacketData, RangeTo<usize>, [u8]);
impl_index_mut!(MutPacketData, RangeFrom<usize>, [u8]);
impl_index_mut!(MutPacketData, RangeFull, [u8]);
pub trait PrimitiveValues {
    type T;
    fn to_primitive_values(&self) -> Self::T;
}
impl PrimitiveValues for nex_core::mac::MacAddr {
    type T = (u8, u8, u8, u8, u8, u8);
    #[inline]
    fn to_primitive_values(&self) -> (u8, u8, u8, u8, u8, u8) {
        (self.0, self.1, self.2, self.3, self.4, self.5)
    }
}
impl PrimitiveValues for std::net::Ipv4Addr {
    type T = (u8, u8, u8, u8);
    #[inline]
    fn to_primitive_values(&self) -> (u8, u8, u8, u8) {
        let octets = self.octets();
        (octets[0], octets[1], octets[2], octets[3])
    }
}
impl PrimitiveValues for std::net::Ipv6Addr {
    type T = (u16, u16, u16, u16, u16, u16, u16, u16);
    #[inline]
    fn to_primitive_values(&self) -> (u16, u16, u16, u16, u16, u16, u16, u16) {
        let segments = self.segments();
        (
            segments[0],
            segments[1],
            segments[2],
            segments[3],
            segments[4],
            segments[5],
            segments[6],
            segments[7],
        )
    }
}