use std::{mem, slice};
pub trait AsByteVec {
    fn as_byte_vec(&self) -> Vec<Vec<u8>>;
}
macro_rules! impl_as_byte_vec_for_integer_type {
    ($int_ty:ty) => {
        impl AsByteVec for $int_ty {
            fn as_byte_vec(&self) -> Vec<Vec<u8>> {
                vec![self.to_ne_bytes().to_vec()]
            }
        }
    };
}
macro_rules! impl_as_byte_vec_for_primitive_type {
    ($int_ty:ty) => {
        impl AsByteVec for $int_ty {
            fn as_byte_vec(&self) -> Vec<Vec<u8>> {
                let len = mem::size_of_val(self);
                let self_ptr: *const Self = self;
                let self_byte_slice = unsafe { slice::from_raw_parts(self_ptr.cast::<u8>(), len) };
                vec![self_byte_slice.to_vec()]
            }
        }
    };
}
impl_as_byte_vec_for_integer_type!(i8);
impl_as_byte_vec_for_integer_type!(u8);
impl_as_byte_vec_for_integer_type!(i16);
impl_as_byte_vec_for_integer_type!(u16);
impl_as_byte_vec_for_integer_type!(i32);
impl_as_byte_vec_for_integer_type!(u32);
impl_as_byte_vec_for_integer_type!(i64);
impl_as_byte_vec_for_integer_type!(u64);
impl_as_byte_vec_for_integer_type!(isize);
impl_as_byte_vec_for_integer_type!(usize);
impl_as_byte_vec_for_integer_type!(i128);
impl_as_byte_vec_for_integer_type!(u128);
impl_as_byte_vec_for_primitive_type!(bool);
impl<T> AsByteVec for Option<T>
where
    T: AsByteVec,
{
    fn as_byte_vec(&self) -> Vec<Vec<u8>> {
        match self {
            Some(hashable) => {
                let mut bytes = hashable.as_byte_vec();
                bytes.reserve(1);
                bytes.insert(0, vec![1]);
                bytes
            }
            None => vec![vec![0]],
        }
    }
}
impl<const N: usize> AsByteVec for [u8; N] {
    fn as_byte_vec(&self) -> Vec<Vec<u8>> {
        vec![self.to_vec()]
    }
}
impl AsByteVec for String {
    fn as_byte_vec(&self) -> Vec<Vec<u8>> {
        vec![self.as_bytes().to_vec()]
    }
}
#[cfg(feature = "solana")]
impl AsByteVec for solana_program::pubkey::Pubkey {
    fn as_byte_vec(&self) -> Vec<Vec<u8>> {
        vec![self.to_bytes().to_vec()]
    }
}
#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn test_as_byte_vec_integers() {
        let i8_min: &dyn AsByteVec = &i8::MIN;
        let i8_min_bytes = i8_min.as_byte_vec();
        assert_eq!(i8_min_bytes, &[&[128]]);
        assert_eq!(i8_min_bytes, &[i8::MIN.to_ne_bytes()]);
        let i8_max: &dyn AsByteVec = &i8::MAX;
        let i8_max_bytes = i8_max.as_byte_vec();
        assert_eq!(i8_max_bytes, &[&[127]]);
        assert_eq!(i8_max_bytes, &[i8::MAX.to_ne_bytes()]);
        let u8_min: &dyn AsByteVec = &u8::MIN;
        let u8_min_bytes = u8_min.as_byte_vec();
        assert_eq!(u8_min_bytes, &[&[0]]);
        assert_eq!(u8_min_bytes, &[u8::MIN.to_ne_bytes()]);
        let u8_max: &dyn AsByteVec = &u8::MAX;
        let u8_max_bytes = u8_max.as_byte_vec();
        assert_eq!(u8_max_bytes, &[&[255]]);
        assert_eq!(u8_max_bytes, &[u8::MAX.to_ne_bytes()]);
        let i16_min: &dyn AsByteVec = &i16::MIN;
        let i16_min_bytes = i16_min.as_byte_vec();
        assert_eq!(i16_min_bytes, &[&[0, 128]]);
        assert_eq!(i16_min_bytes, &[&i16::MIN.to_ne_bytes()]);
        let i16_max: &dyn AsByteVec = &i16::MAX;
        let i16_max_bytes = i16_max.as_byte_vec();
        assert_eq!(i16_max_bytes, &[&[255, 127]]);
        assert_eq!(i16_max_bytes, &[i16::MAX.to_ne_bytes()]);
        let u16_min: &dyn AsByteVec = &u16::MIN;
        let u16_min_bytes = u16_min.as_byte_vec();
        assert_eq!(u16_min_bytes, &[&[0, 0]]);
        assert_eq!(u16_min_bytes, &[u16::MIN.to_ne_bytes()]);
        let u16_max: &dyn AsByteVec = &u16::MAX;
        let u16_max_bytes = u16_max.as_byte_vec();
        assert_eq!(u16_max_bytes, &[&[255, 255]]);
        assert_eq!(u16_max_bytes, &[u16::MAX.to_ne_bytes()]);
        let i32_min: &dyn AsByteVec = &i32::MIN;
        let i32_min_bytes = i32_min.as_byte_vec();
        assert_eq!(i32_min_bytes, &[&[0, 0, 0, 128]]);
        assert_eq!(i32_min_bytes, &[i32::MIN.to_ne_bytes()]);
        let i32_max: &dyn AsByteVec = &i32::MAX;
        let i32_max_bytes = i32_max.as_byte_vec();
        assert_eq!(i32_max_bytes, &[&[255, 255, 255, 127]]);
        assert_eq!(i32_max_bytes, &[i32::MAX.to_ne_bytes()]);
        let u32_min: &dyn AsByteVec = &u32::MIN;
        let u32_min_bytes = u32_min.as_byte_vec();
        assert_eq!(u32_min_bytes, &[&[0, 0, 0, 0]]);
        assert_eq!(u32_min_bytes, &[u32::MIN.to_ne_bytes()]);
        let u32_max: &dyn AsByteVec = &u32::MAX;
        let u32_max_bytes = u32_max.as_byte_vec();
        assert_eq!(u32_max_bytes, &[&[255, 255, 255, 255]]);
        assert_eq!(u32_max_bytes, &[u32::MAX.to_ne_bytes()]);
        let i64_min: &dyn AsByteVec = &i64::MIN;
        let i64_min_bytes = i64_min.as_byte_vec();
        assert_eq!(i64_min_bytes, &[&[0, 0, 0, 0, 0, 0, 0, 128]]);
        assert_eq!(i64_min_bytes, &[i64::MIN.to_ne_bytes()]);
        let i64_max: &dyn AsByteVec = &i64::MAX;
        let i64_max_bytes = i64_max.as_byte_vec();
        assert_eq!(i64_max_bytes, &[&[255, 255, 255, 255, 255, 255, 255, 127]]);
        assert_eq!(i64_max_bytes, &[i64::MAX.to_ne_bytes()]);
        let u64_min: &dyn AsByteVec = &u64::MIN;
        let u64_min_bytes = u64_min.as_byte_vec();
        assert_eq!(u64_min_bytes, &[[0, 0, 0, 0, 0, 0, 0, 0]]);
        assert_eq!(i64_min_bytes, &[i64::MIN.to_ne_bytes()]);
        let u64_max: &dyn AsByteVec = &u64::MAX;
        let u64_max_bytes = u64_max.as_byte_vec();
        assert_eq!(u64_max_bytes, &[&[255, 255, 255, 255, 255, 255, 255, 255]]);
        assert_eq!(u64_max_bytes, &[u64::MAX.to_ne_bytes()]);
        let i128_min: &dyn AsByteVec = &i128::MIN;
        let i128_min_bytes = i128_min.as_byte_vec();
        assert_eq!(
            i128_min_bytes,
            &[&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128]]
        );
        assert_eq!(i128_min_bytes, &[i128::MIN.to_ne_bytes()]);
        let i128_max: &dyn AsByteVec = &i128::MAX;
        let i128_max_bytes = i128_max.as_byte_vec();
        assert_eq!(
            i128_max_bytes,
            &[&[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127]]
        );
        assert_eq!(i128_max_bytes, &[i128::MAX.to_ne_bytes()]);
        let u128_min: &dyn AsByteVec = &u128::MIN;
        let u128_min_bytes = u128_min.as_byte_vec();
        assert_eq!(
            u128_min_bytes,
            &[&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
        );
        assert_eq!(u128_min_bytes, &[u128::MIN.to_ne_bytes()]);
        let u128_max: &dyn AsByteVec = &u128::MAX;
        let u128_max_bytes = u128_max.as_byte_vec();
        assert_eq!(
            u128_max_bytes,
            &[&[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]]
        );
        assert_eq!(u128_max_bytes, &[u128::MAX.to_ne_bytes()]);
    }
    #[test]
    fn test_as_byte_vec_primitives() {
        let bool_false: &dyn AsByteVec = &false;
        assert_eq!(bool_false.as_byte_vec(), &[&[0]]);
        let bool_true: &dyn AsByteVec = &true;
        assert_eq!(bool_true.as_byte_vec(), &[&[1]]);
    }
    #[test]
    fn test_as_byte_vec_option() {
        let u8_none: Option<u8> = None;
        let u8_none: &dyn AsByteVec = &u8_none;
        assert_eq!(u8_none.as_byte_vec(), &[&[0]]);
        let u8_some_zero: Option<u8> = Some(0);
        let u8_some_zero: &dyn AsByteVec = &u8_some_zero;
        assert_eq!(u8_some_zero.as_byte_vec(), &[&[1], &[0]]);
        let u16_none: Option<u16> = None;
        let u16_none: &dyn AsByteVec = &u16_none;
        assert_eq!(u16_none.as_byte_vec(), &[&[0]]);
        let u16_some_zero: Option<u16> = Some(0);
        let u16_some_zero: &dyn AsByteVec = &u16_some_zero;
        assert_eq!(u16_some_zero.as_byte_vec(), &[&[1][..], &[0, 0][..]]);
        let u32_none: Option<u32> = None;
        let u32_none: &dyn AsByteVec = &u32_none;
        assert_eq!(u32_none.as_byte_vec(), &[&[0]]);
        let u32_some_zero: Option<u32> = Some(0);
        let u32_some_zero: &dyn AsByteVec = &u32_some_zero;
        assert_eq!(u32_some_zero.as_byte_vec(), &[&[1][..], &[0, 0, 0, 0][..]]);
        let u64_none: Option<u64> = None;
        let u64_none: &dyn AsByteVec = &u64_none;
        assert_eq!(u64_none.as_byte_vec(), &[&[0]]);
        let u64_some_zero: Option<u64> = Some(0);
        let u64_some_zero: &dyn AsByteVec = &u64_some_zero;
        assert_eq!(
            u64_some_zero.as_byte_vec(),
            &[&[1][..], &[0, 0, 0, 0, 0, 0, 0, 0][..]]
        );
        let u128_none: Option<u128> = None;
        let u128_none: &dyn AsByteVec = &u128_none;
        assert_eq!(u128_none.as_byte_vec(), &[&[0]]);
        let u128_some_zero: Option<u128> = Some(0);
        let u128_some_zero: &dyn AsByteVec = &u128_some_zero;
        assert_eq!(
            u128_some_zero.as_byte_vec(),
            &[
                &[1][..],
                &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0][..]
            ]
        );
    }
    #[test]
    fn test_as_byte_vec_array() {
        let arr: [u8; 0] = [];
        let arr: &dyn AsByteVec = &arr;
        assert_eq!(arr.as_byte_vec(), &[&[]]);
        let arr: [u8; 1] = [255];
        let arr: &dyn AsByteVec = &arr;
        assert_eq!(arr.as_byte_vec(), &[&[255]]);
        let arr: [u8; 4] = [255, 255, 255, 255];
        let arr: &dyn AsByteVec = &arr;
        assert_eq!(arr.as_byte_vec(), &[&[255, 255, 255, 255]]);
    }
    #[test]
    fn test_as_byte_vec_string() {
        let s: &dyn AsByteVec = &"".to_string();
        assert_eq!(s.as_byte_vec(), &[b""]);
        let s: &dyn AsByteVec = &"foobar".to_string();
        assert_eq!(s.as_byte_vec(), &[b"foobar"]);
    }
}