//! The encoded value format: <https://source.android.com/docs/core/runtime/dex-format#encoding>

use crate::{EncodedAnnotation, EncodedArray, Error, ReadSeek, Result, Serializable};
use std::io::Write;

/// An encoded value of arbitrary hierachically structured data:
/// <https://source.android.com/docs/core/runtime/dex-format#encoding>
#[derive(Debug, Clone)]
pub enum EncodedValue {
    Byte(i8),
    Short(i16),
    Char(u16),
    Int(i32),
    Long(i64),
    Float(f32),
    Double(f64),
    /// Index of a [`crate::ProtoIdItem`] in `proto_ids`
    MethodType(u32),
    /// Index of a [`crate::MethodHandleItem`] in `method_handles`
    MethodHandle(u32),
    /// Index of a [`crate::StringIdItem`] in `string_ids`
    String(u32),
    /// Index of a [`crate::TypeIdItem`] in `type_ids`
    Type(u32),
    /// Index of a [`crate::FieldIdItem`] in `field_ids`
    Field(u32),
    /// Index of a [`crate::MethodIdItem`] in `method_ids`
    Method(u32),
    /// Index of a [`crate::FieldIdItem`] in `field_ids` representing an enum.
    Enum(u32),
    Array(EncodedArray),
    Annotation(EncodedAnnotation),
    Null,
    Boolean(bool),
}

/// The id of a type used by a value.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
struct ValueType(u8);

const VALUE_BYTE: ValueType = ValueType(0x00);
const VALUE_SHORT: ValueType = ValueType(0x02);
const VALUE_CHAR: ValueType = ValueType(0x03);
const VALUE_INT: ValueType = ValueType(0x04);
const VALUE_LONG: ValueType = ValueType(0x06);
const VALUE_FLOAT: ValueType = ValueType(0x10);
const VALUE_DOUBLE: ValueType = ValueType(0x11);
const VALUE_METHOD_TYPE: ValueType = ValueType(0x15);
const VALUE_METHOD_HANDLE: ValueType = ValueType(0x16);
const VALUE_STRING: ValueType = ValueType(0x17);
const VALUE_TYPE: ValueType = ValueType(0x18);
const VALUE_FIELD: ValueType = ValueType(0x19);
const VALUE_METHOD: ValueType = ValueType(0x1a);
const VALUE_ENUM: ValueType = ValueType(0x1b);
const VALUE_ARRAY: ValueType = ValueType(0x1c);
const VALUE_ANNOTATION: ValueType = ValueType(0x1d);
const VALUE_NULL: ValueType = ValueType(0x1e);
const VALUE_BOOLEAN: ValueType = ValueType(0x1f);

impl PartialEq for EncodedValue {
    fn eq(&self, item: &Self) -> bool {
        match (self, item) {
            (Self::Byte(val1), Self::Byte(val2)) => val1 == val2,
            (Self::Short(val1), Self::Short(val2)) => val1 == val2,
            (Self::Char(val1), Self::Char(val2)) => val1 == val2,
            (Self::Int(val1), Self::Int(val2)) => val1 == val2,
            (Self::Long(val1), Self::Long(val2)) => val1 == val2,
            (Self::Float(val1), Self::Float(val2)) => val1.to_be_bytes() == val2.to_be_bytes(),
            (Self::Double(val1), Self::Double(val2)) => val1.to_be_bytes() == val2.to_be_bytes(),
            (Self::MethodType(val1), Self::MethodType(val2)) => val1 == val2,
            (Self::MethodHandle(val1), Self::MethodHandle(val2)) => val1 == val2,
            (Self::String(val1), Self::String(val2)) => val1 == val2,
            (Self::Type(val1), Self::Type(val2)) => val1 == val2,
            (Self::Field(val1), Self::Field(val2)) => val1 == val2,
            (Self::Method(val1), Self::Method(val2)) => val1 == val2,
            (Self::Enum(val1), Self::Enum(val2)) => val1 == val2,
            (Self::Array(val1), Self::Array(val2)) => val1 == val2,
            (Self::Annotation(val1), Self::Annotation(val2)) => val1 == val2,
            (Self::Null, Self::Null) => true,
            (Self::Boolean(val1), Self::Boolean(val2)) => val1 == val2,
            _ => false,
        }
    }
}

impl Eq for EncodedValue {}

impl Serializable for EncodedValue {
    fn serialize(&self, output: &mut dyn Write) -> Result<()> {
        match self {
            Self::Byte(byte) => {
                let bytes = byte.to_be_bytes();
                output.write_all(&[VALUE_BYTE.0]).map_err(|err| {
                    Error::SerializationError(format!(
                        "Failed to write serialized Byte to output: {err}"
                    ))
                })?;
                output.write_all(&bytes).map_err(|err| {
                    Error::SerializationError(format!(
                        "Failed to write serialized Byte to output: {err}"
                    ))
                })?;
                Ok(())
            }
            Self::Short(val) => {
                let size = self.size();
                let bytes: [u8; 2] = val.to_le_bytes();
                output
                    .write_all(&[((size as u8 - 2) << 5) | VALUE_SHORT.0])
                    .map_err(|err| {
                        Error::SerializationError(format!(
                            "Failed to write serialized Short to output: {err}"
                        ))
                    })?;
                output.write_all(&bytes[..(size - 1)]).map_err(|err| {
                    Error::SerializationError(format!(
                        "Failed to write serialized Short to output: {err}"
                    ))
                })?;
                Ok(())
            }
            Self::Char(val) => {
                let size = self.size();
                let bytes: [u8; 2] = val.to_le_bytes();
                output
                    .write_all(&[((size as u8 - 2) << 5) | VALUE_CHAR.0])
                    .map_err(|err| {
                        Error::SerializationError(format!(
                            "Failed to write serialized Char to output: {err}"
                        ))
                    })?;
                output.write_all(&bytes[..(size - 1)]).map_err(|err| {
                    Error::SerializationError(format!(
                        "Failed to write serialized Char to output: {err}"
                    ))
                })?;
                Ok(())
            }
            Self::Int(val) => {
                let size = self.size();
                let bytes: [u8; 4] = val.to_le_bytes();
                output
                    .write_all(&[((size as u8 - 2) << 5) | VALUE_INT.0])
                    .map_err(|err| {
                        Error::SerializationError(format!(
                            "Failed to write serialized Int to output: {err}"
                        ))
                    })?;
                output.write_all(&bytes[..(size - 1)]).map_err(|err| {
                    Error::SerializationError(format!(
                        "Failed to write serialized Int to output: {err}"
                    ))
                })?;
                Ok(())
            }
            Self::Long(val) => {
                let size = self.size();
                let bytes: [u8; 8] = val.to_le_bytes();
                output
                    .write_all(&[((size as u8 - 2) << 5) | VALUE_LONG.0])
                    .map_err(|err| {
                        Error::SerializationError(format!(
                            "Failed to write serialized Long to output: {err}"
                        ))
                    })?;
                output.write_all(&bytes[..(size - 1)]).map_err(|err| {
                    Error::SerializationError(format!(
                        "Failed to write serialized Long to output: {err}"
                    ))
                })?;
                Ok(())
            }
            Self::Float(val) => {
                let size = self.size();
                let bytes = val.to_le_bytes(); // TODO: check LE/BE
                output
                    .write_all(&[((size as u8 - 2) << 5) | VALUE_FLOAT.0])
                    .map_err(|err| {
                        Error::SerializationError(format!(
                            "Failed to write serialized Float to output: {err}"
                        ))
                    })?;
                output.write_all(&bytes[..(size - 1)]).map_err(|err| {
                    Error::SerializationError(format!(
                        "Failed to write serialized Float to output: {err}"
                    ))
                })?;
                Ok(())
            }
            Self::Double(val) => {
                let size = self.size();
                let bytes = val.to_le_bytes(); // TODO: check LE/BE
                output
                    .write_all(&[((size as u8 - 2) << 5) | VALUE_DOUBLE.0])
                    .map_err(|err| {
                        Error::SerializationError(format!(
                            "Failed to write serialized Double to output: {err}"
                        ))
                    })?;
                output.write_all(&bytes[..(size - 1)]).map_err(|err| {
                    Error::SerializationError(format!(
                        "Failed to write serialized Double to output: {err}"
                    ))
                })?;
                Ok(())
            }
            Self::MethodType(idx) => Idx(*idx, VALUE_METHOD_TYPE).serialize(output),
            Self::MethodHandle(idx) => Idx(*idx, VALUE_METHOD_HANDLE).serialize(output),
            Self::String(idx) => Idx(*idx, VALUE_STRING).serialize(output),
            Self::Type(idx) => Idx(*idx, VALUE_TYPE).serialize(output),
            Self::Field(idx) => Idx(*idx, VALUE_FIELD).serialize(output),
            Self::Method(idx) => Idx(*idx, VALUE_METHOD).serialize(output),
            Self::Enum(idx) => Idx(*idx, VALUE_ENUM).serialize(output),
            Self::Array(arr) => {
                output.write_all(&[VALUE_ARRAY.0]).map_err(|err| {
                    Error::SerializationError(format!(
                        "Failed to write serialized Array to output: {err}"
                    ))
                })?;
                arr.serialize(output)
            }
            Self::Annotation(ann) => {
                output.write_all(&[VALUE_ANNOTATION.0]).map_err(|err| {
                    Error::SerializationError(format!(
                        "Failed to write serialized Annotation to output: {err}"
                    ))
                })?;
                ann.serialize(output)
            }
            Self::Null => {
                output.write_all(&[VALUE_NULL.0]).map_err(|err| {
                    Error::SerializationError(format!(
                        "Failed to write serialized Null to output: {err}"
                    ))
                })?;
                Ok(())
            }
            Self::Boolean(b) => {
                let val = if *b { 1 } else { 0 };
                output
                    .write_all(&[(val << 5) | VALUE_BOOLEAN.0])
                    .map_err(|err| {
                        Error::SerializationError(format!(
                            "Failed to write serialized Bool to output: {err}"
                        ))
                    })?;
                Ok(())
            }
        }
    }
    fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
        let mut buffer = [0u8; 1];
        input.read_exact(&mut buffer).map_err(|_| {
            Error::InputTooSmall(
                "Failed to read all bytes for the EncodedValue from the input".into(),
            )
        })?;
        let [byte] = buffer;
        let arg = (byte & 0b1110_0000) >> 5;
        match ValueType(byte & 0b0001_1111) {
            VALUE_BYTE => {
                if arg != 0 {
                    Err(Error::DeserializationError(format!(
                        "Unexpected value argument 0x{arg:02x}: expected 0 for VALUE_BYTE"
                    )))
                } else {
                    let mut buffer = [0u8; 1];
                    input.read_exact(&mut buffer).map_err(|_| {
                        Error::InputTooSmall(
                            "Failed to read all bytes for the EncodedValue (Byte) from the input"
                                .into(),
                        )
                    })?;
                    Ok(Self::Byte(i8::from_be_bytes(buffer)))
                }
            }
            VALUE_SHORT => {
                if arg >= 2 {
                    Err(Error::DeserializationError(format!(
                        "Unexpected value argument 0x{arg:02x}: expected 0 or 1 for VALUE_SHORT"
                    )))
                } else {
                    let mut buffer = [0x00u8; 2];
                    let size = (arg + 1) as usize;
                    input.read_exact(&mut buffer[..size]).map_err(|_| {
                        Error::InputTooSmall(
                            "Failed to read all bytes for the EncodedValue (Short) from the input"
                                .into(),
                        )
                    })?;
                    // Sign extention
                    if (buffer[size - 1] & 0b1000_0000) != 0 {
                        for b in buffer.iter_mut().skip(size) {
                            *b = 0xff;
                        }
                    }
                    Ok(Self::Short(i16::from_le_bytes(buffer)))
                }
            }
            VALUE_CHAR => {
                if arg >= 2 {
                    Err(Error::DeserializationError(format!(
                        "Unexpected value argument 0x{arg:02x}: expected 0 or 1 for VALUE_CHAR"
                    )))
                } else {
                    let mut buffer = [0x00u8; 2];
                    let size = (arg + 1) as usize;
                    input.read_exact(&mut buffer[..size]).map_err(|_| {
                        Error::InputTooSmall(
                            "Failed to read all bytes for the EncodedValue (Char) from the input"
                                .into(),
                        )
                    })?;
                    Ok(Self::Char(u16::from_le_bytes(buffer)))
                }
            }
            VALUE_INT => {
                if arg >= 4 {
                    Err(Error::DeserializationError(format!(
                        "Unexpected value argument 0x{arg:02x}: expected 0, 1, 2 or 3 for VALUE_INT"
                    )))
                } else {
                    let mut buffer = [0x00u8; 4];
                    let size = (arg + 1) as usize;
                    input.read_exact(&mut buffer[..size]).map_err(|_| {
                        Error::InputTooSmall(
                            "Failed to read all bytes for the EncodedValue (Int) from the input"
                                .into(),
                        )
                    })?;
                    // Sign extention
                    if (buffer[size - 1] & 0b1000_0000) != 0 {
                        for b in buffer.iter_mut().skip(size) {
                            *b = 0xff;
                        }
                    }
                    Ok(Self::Int(i32::from_le_bytes(buffer)))
                }
            }
            VALUE_LONG => {
                if arg >= 8 {
                    Err(Error::DeserializationError(format!(
                        "Unexpected value argument 0x{arg:02x}: expected 0 to 7 for VALUE_LONG"
                    )))
                } else {
                    let mut buffer = [0x00u8; 8];
                    let size = (arg + 1) as usize;
                    input.read_exact(&mut buffer[..size]).map_err(|_| {
                        Error::InputTooSmall(
                            "Failed to read all bytes for the EncodedValue (Long) from the input"
                                .into(),
                        )
                    })?;
                    // Sign extention
                    if (buffer[size - 1] & 0b1000_0000) != 0 {
                        for b in buffer.iter_mut().skip(size) {
                            *b = 0xff;
                        }
                    }
                    Ok(Self::Long(i64::from_le_bytes(buffer)))
                }
            }
            VALUE_FLOAT => {
                if arg >= 4 {
                    Err(Error::DeserializationError(format!(
                        "Unexpected value argument 0x{arg:02x}: expected 0, 1, 2 or 3 for VALUE_FLOAT"
                    )))
                } else {
                    let mut buffer = [0x00u8; 4];
                    let size = (arg + 1) as usize;
                    input.read_exact(&mut buffer[..size]).map_err(|_| {
                        Error::InputTooSmall(
                            "Failed to read all bytes for the EncodedValue (Float) from the input"
                                .into(),
                        )
                    })?;
                    Ok(Self::Float(f32::from_le_bytes(buffer)))
                }
            }
            VALUE_DOUBLE => {
                if arg >= 8 {
                    Err(Error::DeserializationError(format!(
                        "Unexpected value argument 0x{arg:02x}: expected 0 to 7 for VALUE_DOUBLE"
                    )))
                } else {
                    let mut buffer = [0x00u8; 8];
                    let size = (arg + 1) as usize;
                    input.read_exact(&mut buffer[..size]).map_err(|_| {
                        Error::InputTooSmall(
                            "Failed to read all bytes for the EncodedValue (Double) from the input"
                                .into(),
                        )
                    })?;
                    Ok(Self::Double(f64::from_le_bytes(buffer)))
                }
            }
            VALUE_METHOD_TYPE => {
                if arg >= 4 {
                    Err(Error::DeserializationError(format!(
                        "Unexpected value argument 0x{arg:02x}: expected 0, 1, 2 or 3 for VALUE_METHOD_TYPE"
                    )))
                } else {
                    let mut buffer = [0x00u8; 4];
                    let size = (arg + 1) as usize;
                    input.read_exact(&mut buffer[..size]).map_err(|_| {
                        Error::InputTooSmall(
                            "Failed to read all bytes for the EncodedValue (MethodType) from the input"
                                .into(),
                        )
                    })?;
                    Ok(Self::MethodType(u32::from_le_bytes(buffer)))
                }
            }
            VALUE_METHOD_HANDLE => {
                if arg >= 4 {
                    Err(Error::DeserializationError(format!(
                        "Unexpected value argument 0x{arg:02x}: expected 0, 1, 2 or 3 for VALUE_METHOD_HANDLE"
                    )))
                } else {
                    let mut buffer = [0x00u8; 4];
                    let size = (arg + 1) as usize;
                    input.read_exact(&mut buffer[..size]).map_err(|_| {
                        Error::InputTooSmall(
                            "Failed to read all bytes for the EncodedValue (MethodHandle) from the input"
                                .into(),
                        )
                    })?;
                    Ok(Self::MethodHandle(u32::from_le_bytes(buffer)))
                }
            }
            VALUE_STRING => {
                if arg >= 4 {
                    Err(Error::DeserializationError(format!(
                        "Unexpected value argument 0x{arg:02x}: expected 0, 1, 2 or 3 for VALUE_STRING"
                    )))
                } else {
                    let mut buffer = [0x00u8; 4];
                    let size = (arg + 1) as usize;
                    input.read_exact(&mut buffer[..size]).map_err(|_| {
                        Error::InputTooSmall(
                            "Failed to read all bytes for the EncodedValue (String) from the input"
                                .into(),
                        )
                    })?;
                    Ok(Self::String(u32::from_le_bytes(buffer)))
                }
            }
            VALUE_TYPE => {
                if arg >= 4 {
                    Err(Error::DeserializationError(format!(
                        "Unexpected value argument 0x{arg:02x}: expected 0, 1, 2 or 3 for VALUE_TYPE"
                    )))
                } else {
                    let mut buffer = [0x00u8; 4];
                    let size = (arg + 1) as usize;
                    input.read_exact(&mut buffer[..size]).map_err(|_| {
                        Error::InputTooSmall(
                            "Failed to read all bytes for the EncodedValue (Type) from the input"
                                .into(),
                        )
                    })?;
                    Ok(Self::Type(u32::from_le_bytes(buffer)))
                }
            }
            VALUE_FIELD => {
                if arg >= 4 {
                    Err(Error::DeserializationError(format!(
                        "Unexpected value argument 0x{arg:02x}: expected 0, 1, 2 or 3 for VALUE_FIELD"
                    )))
                } else {
                    let mut buffer = [0x00u8; 4];
                    let size = (arg + 1) as usize;
                    input.read_exact(&mut buffer[..size]).map_err(|_| {
                        Error::InputTooSmall(
                            "Failed to read all bytes for the EncodedValue (Field) from the input"
                                .into(),
                        )
                    })?;
                    Ok(Self::Field(u32::from_le_bytes(buffer)))
                }
            }
            VALUE_METHOD => {
                if arg >= 4 {
                    Err(Error::DeserializationError(format!(
                        "Unexpected value argument 0x{arg:02x}: expected 0, 1, 2 or 3 for VALUE_METHOD"
                    )))
                } else {
                    let mut buffer = [0x00u8; 4];
                    let size = (arg + 1) as usize;
                    input.read_exact(&mut buffer[..size]).map_err(|_| {
                        Error::InputTooSmall(
                            "Failed to read all bytes for the EncodedValue (Method) from the input"
                                .into(),
                        )
                    })?;
                    Ok(Self::Method(u32::from_le_bytes(buffer)))
                }
            }
            VALUE_ENUM => {
                if arg >= 4 {
                    Err(Error::DeserializationError(format!(
                        "Unexpected value argument 0x{arg:02x}: expected 0, 1, 2 or 3 for VALUE_ENUM"
                    )))
                } else {
                    let mut buffer = [0x00u8; 4];
                    let size = (arg + 1) as usize;
                    input.read_exact(&mut buffer[..size]).map_err(|_| {
                        Error::InputTooSmall(
                            "Failed to read all bytes for the EncodedValue (Enum) from the input"
                                .into(),
                        )
                    })?;
                    Ok(Self::Enum(u32::from_le_bytes(buffer)))
                }
            }
            VALUE_ARRAY => {
                if arg != 0 {
                    Err(Error::DeserializationError(format!(
                        "Unexpected value argument 0x{arg:02x}: expected 0 for VALUE_ARRAY"
                    )))
                } else {
                    Ok(Self::Array(EncodedArray::deserialize(input)?))
                }
            }
            VALUE_ANNOTATION => {
                if arg != 0 {
                    Err(Error::DeserializationError(format!(
                        "Unexpected value argument 0x{arg:02x}: expected 0 for VALUE_ANNOTATION"
                    )))
                } else {
                    Ok(Self::Annotation(EncodedAnnotation::deserialize(input)?))
                }
            }
            VALUE_NULL => {
                if arg != 0 {
                    Err(Error::DeserializationError(format!(
                        "Unexpected value argument 0x{arg:02x}: expected 0 for VALUE_NULL"
                    )))
                } else {
                    Ok(Self::Null)
                }
            }
            VALUE_BOOLEAN => {
                if arg == 0 {
                    Ok(Self::Boolean(false))
                } else if arg == 1 {
                    Ok(Self::Boolean(true))
                } else {
                    Err(Error::DeserializationError(format!(
                        "Unexpected value argument 0x{arg:02x}: expected 0 or 1 for VALUE_BOOLEAN"
                    )))
                }
            }
            ValueType(vt) => Err(Error::DeserializationError(format!(
                "Unknown Value Type: 0x{vt:02x}"
            ))),
        }
    }

    fn size(&self) -> usize {
        match self {
            Self::Byte(_) => 2,
            Self::Short(val) => 1 + if *val <= 0x7f && *val >= -0x80 { 1 } else { 2 },
            Self::Char(val) => 1 + if *val <= 0xff { 1 } else { 2 },
            Self::Int(val) => {
                1 + if *val <= 0x7f && *val >= -0x80 {
                    1
                } else if *val <= 0x7f_ff && *val >= -0x80_00 {
                    2
                } else if *val <= 0x7f_ff_ff && *val >= -0x80_00_00 {
                    3
                } else {
                    4
                }
            }
            Self::Long(val) => {
                1 + if *val <= 0x7f && *val >= -0x80 {
                    1
                } else if *val <= 0x7f_ff && *val >= -0x80_00 {
                    2
                } else if *val <= 0x7f_ff_ff && *val >= -0x80_00_00 {
                    3
                } else if *val <= 0x7f_ff_ff_ff && *val >= -0x80_00_00_00 {
                    4
                } else if *val <= 0x7f_ff_ff_ff_ff && *val >= -0x80_00_00_00_00 {
                    5
                } else if *val <= 0x7f_ff_ff_ff_ff_ff && *val >= -0x80_00_00_00_00_00 {
                    6
                } else if *val <= 0x7f_ff_ff_ff_ff_ff_ff && *val >= -0x80_00_00_00_00_00 {
                    7
                } else {
                    8
                }
            }
            Self::Float(val) => {
                let trailing_zeros = val
                    .to_be_bytes()
                    .iter()
                    .rev()
                    .take_while(|b| **b == 0)
                    .count();
                std::cmp::max(1 + 4 - trailing_zeros, 2)
            }
            Self::Double(val) => {
                let trailing_zeros = val
                    .to_be_bytes()
                    .iter()
                    .rev()
                    .take_while(|b| **b == 0)
                    .count();
                std::cmp::max(1 + 8 - trailing_zeros, 2)
            }
            Self::MethodType(idx) => Idx(*idx, VALUE_TYPE).size(),
            Self::MethodHandle(idx) => Idx(*idx, VALUE_METHOD_HANDLE).size(),
            Self::String(idx) => Idx(*idx, VALUE_STRING).size(),
            Self::Type(idx) => Idx(*idx, VALUE_TYPE).size(),
            Self::Field(idx) => Idx(*idx, VALUE_FIELD).size(),
            Self::Method(idx) => Idx(*idx, VALUE_METHOD).size(),
            Self::Enum(idx) => Idx(*idx, VALUE_ENUM).size(),
            Self::Array(arr) => 1 + arr.size(),
            Self::Annotation(ann) => 1 + ann.size(),
            Self::Null => 1,
            Self::Boolean(_) => 1,
        }
    }
}

/// Utility type to encode/decode an Idx.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
struct Idx(u32, ValueType);
impl Serializable for Idx {
    fn serialize(&self, output: &mut dyn Write) -> Result<()> {
        let Idx(idx, ValueType(vt)) = self;
        let size = self.size() - 2;
        let bytes: [u8; 4] = idx.to_le_bytes();
        let vec = &bytes[..(size + 1)];
        output
            .write_all(&[((size as u8) << 5) | vt])
            .map_err(|err| {
                Error::SerializationError(format!(
                    "Failed to write serialized Idx to output: {err}"
                ))
            })?;
        output.write_all(vec).map_err(|err| {
            Error::SerializationError(format!("Failed to write serialized Idx to output: {err}"))
        })?;
        Ok(())
    }
    /// unimplemented, not used because the ValueType must be known before deserializing the idx.
    fn deserialize(_input: &mut dyn ReadSeek) -> Result<Self> {
        unimplemented!()
    }

    fn size(&self) -> usize {
        let Idx(idx, _) = *self;
        1 + if idx <= 0xff {
            1
        } else if idx <= 0xffff {
            2
        } else if idx <= 0xffffff {
            3
        } else {
            4
        }
    }
}

// TODO: more TESTS!!!

#[cfg(test)]
mod test {
    use super::*;
    use crate::*;

    #[test]
    fn boolean_deserialize() {
        assert_eq!(
            EncodedValue::deserialize_from_slice(&[0b0001_1111]).unwrap(),
            EncodedValue::Boolean(false)
        );
        assert_eq!(
            EncodedValue::deserialize_from_slice(&[0b0011_1111]).unwrap(),
            EncodedValue::Boolean(true)
        );
        assert!(EncodedValue::deserialize_from_slice(&[0b0101_1111]).is_err());
    }

    #[test]
    fn boolean_serialize() {
        assert_eq!(
            EncodedValue::Boolean(false).serialize_to_vec().unwrap(),
            vec![0b0001_1111]
        );
        assert_eq!(
            EncodedValue::Boolean(true).serialize_to_vec().unwrap(),
            vec![0b0011_1111]
        );
    }

    #[test]
    fn annotation_deserialize() {
        assert_eq!(
            EncodedValue::deserialize_from_slice(&[0x1d, 0xf6, 0x33, 0x01, 0xd3, 0xe8, 0x02, 0x3f])
                .unwrap(),
            EncodedValue::Annotation(EncodedAnnotation {
                type_idx: Uleb128(6646),
                elements: vec![AnnotationElement {
                    name_idx: Uleb128(46163),
                    value: EncodedValue::Boolean(true)
                }]
            })
        );
    }

    #[test]
    fn annotation_serialize() {
        assert_eq!(
            vec![0x1d, 0xf6, 0x33, 0x01, 0xd3, 0xe8, 0x02, 0x3f],
            EncodedValue::Annotation(EncodedAnnotation {
                type_idx: Uleb128(6646),
                elements: vec![AnnotationElement {
                    name_idx: Uleb128(46163),
                    value: EncodedValue::Boolean(true)
                }]
            })
            .serialize_to_vec()
            .unwrap()
        );
    }

    #[test]
    fn long_serialize() {
        assert_eq!(
            vec![
                0x06 | 7 << 5,
                0x00,
                0x00,
                0x00,
                0x00,
                0x00,
                0x00,
                0x00,
                0x80
            ],
            EncodedValue::Long(-9223372036854775808)
                .serialize_to_vec()
                .unwrap(),
        );
        assert_eq!(
            vec![0x06 | 0 << 5, 0xff],
            EncodedValue::Long(-1).serialize_to_vec().unwrap(),
        );
        assert_eq!(
            vec![0x06 | 0 << 5, 0x01],
            EncodedValue::Long(1).serialize_to_vec().unwrap(),
        );
        assert_eq!(
            vec![0x06 | 1 << 5, 0x23, 0x01],
            EncodedValue::Long(0x0123).serialize_to_vec().unwrap(),
        );
    }

    #[test]
    fn long_deserialize() {
        assert_eq!(
            EncodedValue::deserialize_from_slice(&[
                0x06 | 7 << 5,
                0x00,
                0x00,
                0x00,
                0x00,
                0x00,
                0x00,
                0x00,
                0x80
            ])
            .unwrap(),
            EncodedValue::Long(-9223372036854775808),
        );
        assert_eq!(
            EncodedValue::deserialize_from_slice(&[0x06 | 0 << 5, 0xff]).unwrap(),
            EncodedValue::Long(-1),
        );
        assert_eq!(
            EncodedValue::deserialize_from_slice(&[0x06 | 0 << 5, 0x01]).unwrap(),
            EncodedValue::Long(1),
        );
        assert_eq!(
            EncodedValue::deserialize_from_slice(&[0x06 | 1 << 5, 0x23, 0x01]).unwrap(),
            EncodedValue::Long(0x0123),
        );
    }

    #[test]
    fn short_serialize() {
        assert_eq!(
            vec![0x02 | 0 << 5, 0xff],
            EncodedValue::Short(-1).serialize_to_vec().unwrap(),
        );
        assert_eq!(
            vec![0x02 | 0 << 5, 0x01],
            EncodedValue::Short(1).serialize_to_vec().unwrap(),
        );
        assert_eq!(
            vec![0x02 | 1 << 5, 0x23, 0x01],
            EncodedValue::Short(0x0123).serialize_to_vec().unwrap(),
        );
    }

    #[test]
    fn short_deserialize() {
        assert_eq!(
            EncodedValue::deserialize_from_slice(&[0x02 | 0 << 5, 0xff]).unwrap(),
            EncodedValue::Short(-1),
        );
        assert_eq!(
            EncodedValue::deserialize_from_slice(&[0x02 | 0 << 5, 0x01]).unwrap(),
            EncodedValue::Short(1),
        );
        assert_eq!(
            EncodedValue::deserialize_from_slice(&[0x02 | 1 << 5, 0x23, 0x01]).unwrap(),
            EncodedValue::Short(0x0123),
        );
    }

    #[test]
    fn int_serialize() {
        assert_eq!(
            vec![0x04 | 3 << 5, 0x00, 0x00, 0x00, 0x80],
            EncodedValue::Int(-2147483648).serialize_to_vec().unwrap(),
        );
        assert_eq!(
            vec![0x04 | 0 << 5, 0xff],
            EncodedValue::Int(-1).serialize_to_vec().unwrap(),
        );
        assert_eq!(
            vec![0x04 | 0 << 5, 0x01],
            EncodedValue::Int(1).serialize_to_vec().unwrap(),
        );
        assert_eq!(
            vec![0x04 | 1 << 5, 0x23, 0x01],
            EncodedValue::Int(0x0123).serialize_to_vec().unwrap(),
        );
    }

    #[test]
    fn int_deserialize() {
        assert_eq!(
            EncodedValue::deserialize_from_slice(&[0x04 | 3 << 5, 0x00, 0x00, 0x00, 0x80]).unwrap(),
            EncodedValue::Int(-2147483648),
        );
        assert_eq!(
            EncodedValue::deserialize_from_slice(&[0x04 | 0 << 5, 0xff]).unwrap(),
            EncodedValue::Int(-1),
        );
        assert_eq!(
            EncodedValue::deserialize_from_slice(&[0x04 | 0 << 5, 0x01]).unwrap(),
            EncodedValue::Int(1),
        );
        assert_eq!(
            EncodedValue::deserialize_from_slice(&[0x04 | 1 << 5, 0x23, 0x01]).unwrap(),
            EncodedValue::Int(0x0123),
        );
    }
}
