//! Code items

use crate as androscalpel_serializer;
use crate::{Error, Instruction, ReadSeek, Result, Serializable, Sleb128, Uleb128};
use log::debug;
use std::io::Write;

/// <https://source.android.com/docs/core/runtime/dex-format#code-item>
/// alignment: 4 bytes
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CodeItem {
    pub registers_size: u16,
    pub ins_size: u16,
    pub outs_size: u16,
    // pub tries_size: u16,
    /// 0 if no debug info, else offset to a [`crate::DebugInfoItem`].
    pub debug_info_off: u32,
    // pub insns_size: u32,
    pub insns: Vec<Instruction>,
    // pub padding: Vec<u8>,
    /// try items must refere to non overlapping range an order from low to hight addresses.
    pub tries: Vec<TryItem>,
    pub handlers: Option<EncodedCatchHandlerList>,
}

impl CodeItem {
    pub fn tries_size_field(&self) -> u16 {
        self.tries.len() as u16
    }

    pub fn insns_size_field(&self) -> u32 {
        self.insns.iter().map(|ins| ins.size() as u32).sum::<u32>() / 2
    }

    pub fn sanity_check(&self) -> Result<()> {
        if self.tries.is_empty() && self.handlers.is_some() {
            return Err(Error::InconsistantStruct(
                "CodeItem cannot have a `handlers` value if `tries_size` \
                is 0 (CodeItem.tries is empty)"
                    .into(),
            ));
        }
        if !self.tries.is_empty() && self.handlers.is_none() {
            return Err(Error::InconsistantStruct(
                "CodeItem must have a `handlers` value if `tries_size` \
                is not 0 (CodeItem.tries not empty)"
                    .into(),
            ));
        }
        let mut max_addr = 0;
        for item in &self.tries {
            let addr = item.start_addr;
            if addr < max_addr {
                return Err(Error::InconsistantStruct(
                    "try_item in a code_item must be non overlapping and \
                    sorted from low to high address"
                        .into(),
                ));
            }
            max_addr = addr + (item.insn_count as u32);
        }
        /*
        // Necessary? no in spec and apk in the wild seams to have try blocks spaming outside the
        // insns array.
        if max_addr > self.insns_size_field() {
            return Err(Error::InconsistantStruct(
                "found try_item whose block span outside of the insns array".into(),
            ));
        }
        */

        for try_ in &self.tries {
            let handler = self
                .handlers
                .as_ref()
                .unwrap()
                .get_handler_at_offset(try_.handler_off)?;
            handler.sanity_check()?;
            for handler in &handler.handlers {
                // Necessary? no in spec
                if handler.addr.0 > self.insns_size_field() {
                    return Err(Error::InconsistantStruct(
                        "Found an handler whose address is outside of the insns array".into(),
                    ));
                }
            }
            if let Some(Uleb128(addr)) = handler.catch_all_addr {
                // Necessary? no in spec
                if addr > self.insns_size_field() {
                    return Err(Error::InconsistantStruct(
                        "Found a catch all handler whose address is outside of the insns array"
                            .into(),
                    ));
                }
            }
        }

        let mut addresses = vec![];
        for try_ in &self.tries {
            addresses.push(try_.start_addr);
            addresses.push(try_.start_addr + try_.insn_count as u32);
        }
        for handler in &self.handlers {
            for catch in &handler.list {
                for EncodedTypeAddrPair {
                    addr: Uleb128(addr),
                    ..
                } in &catch.handlers
                {
                    addresses.push(*addr);
                }
                if let Some(Uleb128(addr)) = catch.catch_all_addr {
                    addresses.push(addr);
                }
            }
        }
        addresses.sort();
        let mut addr = 0;
        let mut i = 0;
        while i < addresses.len() && addresses[i] == addr {
            i += 1;
        }
        for insn in &self.insns {
            addr += insn.size() as u32 / 2;
            while i < addresses.len() && addresses[i] == addr {
                i += 1;
            }
        }
        if i < addresses.len() && addresses[i] < addr {
            return Err(Error::InconsistantStruct(format!(
                "Found an address in try block (0x{:x}) that does not align with an instruction",
                addresses[i]
            )));
        }

        // TODO check goto and if addresses? pb: op code are not parsed so goto instruction are not known

        Ok(())
    }
}

impl Serializable for CodeItem {
    fn serialize(&self, output: &mut dyn Write) -> Result<()> {
        self.sanity_check().map_err(|err| match err {
            Error::InconsistantStruct(msg) => {
                Error::SerializationError(format!("Inconsistant CodeItem: {msg}"))
            }
            err => err,
        })?;
        self.registers_size.serialize(output)?;
        self.ins_size.serialize(output)?;
        self.outs_size.serialize(output)?;
        self.tries_size_field().serialize(output)?;
        self.debug_info_off.serialize(output)?;
        let insns_size = self.insns.iter().map(|i| i.size() as u32).sum::<u32>() / 2;
        insns_size.serialize(output)?;
        for insn in &self.insns {
            insn.serialize(output)?;
        }
        if !self.tries.is_empty() && insns_size % 2 == 1 {
            0u16.serialize(output)?;
        }
        for item in &self.tries {
            item.serialize(output)?;
        }
        let mut tries = vec![];
        for item in &self.tries {
            for c in item.serialize_to_vec().unwrap().into_iter() {
                tries.push(c);
            }
        }
        if let Some(ref handlers) = self.handlers {
            handlers.serialize(output)?;
        }
        Ok(())
    }

    fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
        let registers_size = u16::deserialize(input)?;
        let ins_size = u16::deserialize(input)?;
        let outs_size = u16::deserialize(input)?;
        let tries_size = u16::deserialize(input)?;
        let debug_info_off = u32::deserialize(input)?;
        let insns_size = u32::deserialize(input)?;

        let mut insns = vec![];
        let mut serialized_insns_size = 0;
        while serialized_insns_size < insns_size {
            let ins = Instruction::deserialize(input).map_err(|err| {
                Error::DeserializationError(format!(
                    "Failed to deserialize instruction at 0x{serialized_insns_size:x}: {err}"
                ))
            })?;
            serialized_insns_size += ins.size() as u32 / 2;
            insns.push(ins);
        }
        if serialized_insns_size != insns_size {
            return Err(Error::DeserializationError(format!(
                "Failed to deserialize instructions, expected size of {insns_size} code \
                units (16 bits), found at least {serialized_insns_size}"
            )));
        }
        if tries_size != 0 && insns_size % 2 == 1 {
            let _ = u16::deserialize(input)?;
        }
        let mut tries = vec![];
        for _ in 0..tries_size {
            tries.push(TryItem::deserialize(input)?);
        }
        let handlers = if tries_size != 0 {
            Some(EncodedCatchHandlerList::deserialize(input)?)
        } else {
            None
        };
        Ok(Self {
            registers_size,
            ins_size,
            outs_size,
            debug_info_off,
            insns,
            tries,
            handlers,
        })
    }
    fn size(&self) -> usize {
        let insns_size = self.insns.iter().map(|i| i.size() as u32).sum::<u32>() / 2;
        self.registers_size.size()
            + self.ins_size.size()
            + self.outs_size.size()
            + self.tries_size_field().size()
            + self.debug_info_off.size()
            + insns_size.size()
            + self.insns.iter().map(|val| val.size()).sum::<usize>()
            + if !self.tries.is_empty() && insns_size % 2 == 1 {
                2
            } else {
                0
            }
            + self.tries.iter().map(|val| val.size()).sum::<usize>()
            + self.handlers.as_ref().map(|val| val.size()).unwrap_or(0)
    }
}

/// <https://source.android.com/docs/core/runtime/dex-format#type-item>
#[derive(Serializable, Clone, Copy, Debug, PartialEq, Eq)]
pub struct TryItem {
    /// Start address of the block of code covered. It's a count of 16-bit code unit to the
    /// start of the first covered instruction of the block.
    pub start_addr: u32,
    /// Number of 16-bit code unit covered by the entry.
    pub insn_count: u16,
    /// **Offset in bytes** from the start of the [`crate::EncodedCatchHandlerList`] to the
    /// [`crate::EncodedCatchHandler`] associated.
    pub handler_off: u16,
}

/// <https://source.android.com/docs/core/runtime/dex-format#encoded-catch-handlerlist>
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct EncodedCatchHandlerList {
    // pub size: Uleb128,
    pub list: Vec<EncodedCatchHandler>,
}

impl EncodedCatchHandlerList {
    pub fn size_field(&self) -> Uleb128 {
        Uleb128(self.list.len() as u32)
    }

    /// Return a reference to the [`crate::EncodedCatchHandler`] located at `offset` bytes after
    /// the begining of the [`crate::EncodedCatchHandlerList`]. Expected to be used to lookup
    /// the value refered to by [`crate::TryItem`]`.handler_off`.
    pub fn get_handler_at_offset(&self, offset: u16) -> Result<&EncodedCatchHandler> {
        let offset = offset as usize;
        let mut current_offset = self.size_field().size();
        for handler in &self.list {
            if current_offset == offset {
                return Ok(handler);
            }
            current_offset += handler.size();
            if current_offset > offset {
                break;
            }
        }
        let mut current_offset = self.size_field().size();
        for handler in &self.list {
            debug!(
                "{:#?}: size {} at offset {}",
                handler,
                handler.size(),
                current_offset
            );
            current_offset += handler.size();
        }
        Err(Error::InconsistantStruct(format!(
            "Offset 0x{offset:x} does not match with the begining of a \
            EncodedCatchHandler in this EncodedCatchHandlerList"
        )))
    }
}

impl Serializable for EncodedCatchHandlerList {
    fn serialize(&self, output: &mut dyn Write) -> Result<()> {
        self.size_field().serialize(output)?;
        for item in &self.list {
            item.serialize(output)?;
        }
        Ok(())
    }

    fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
        let Uleb128(size) = Uleb128::deserialize(input)?;
        let mut list = vec![];
        for _ in 0..size {
            list.push(EncodedCatchHandler::deserialize(input)?);
        }
        Ok(Self {
            // size,
            list,
        })
    }

    fn size(&self) -> usize {
        self.size_field().size() + self.list.iter().map(|val| val.size()).sum::<usize>()
    }
}

/// <https://source.android.com/docs/core/runtime/dex-format#encoded-catch-handler>
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct EncodedCatchHandler {
    // pub size: Sleb128,
    /// List of handler, one by type caught, in the order of the type tests
    pub handlers: Vec<EncodedTypeAddrPair>,
    /// Bytecode address of the catchall handler.
    pub catch_all_addr: Option<Uleb128>,
}

impl EncodedCatchHandler {
    pub fn size_field(&self) -> Sleb128 {
        let sign = if self.catch_all_addr.is_some() { -1 } else { 1 };
        let len = self.handlers.len() as i32;
        //if len == 0 && self.catch_all_addr.is_none() {
        // Not good. Panic? Error?
        //}
        Sleb128(len * sign)
    }

    pub fn sanity_check(&self) -> Result<()> {
        if self.catch_all_addr.is_none() && self.handlers.is_empty() {
            return Err(Error::InconsistantStruct(
                "EncodedCatchHandler must have at least one handler or catch_all_addr defined"
                    .into(),
            ));
        }
        Ok(())
    }
}

impl Serializable for EncodedCatchHandler {
    fn serialize(&self, output: &mut dyn Write) -> Result<()> {
        self.sanity_check().map_err(|err| match err {
            Error::InconsistantStruct(msg) => {
                Error::SerializationError(format!("Inconsistant EncodedCatchHandler: {msg}"))
            }
            err => err,
        })?;
        self.size_field().serialize(output)?;
        for handler in &self.handlers {
            handler.serialize(output)?;
        }
        if let Some(catch_all_addr) = self.catch_all_addr {
            catch_all_addr.serialize(output)?;
        }
        Ok(())
    }
    fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
        let Sleb128(size) = Sleb128::deserialize(input)?;
        let mut handlers = vec![];
        for _ in 0..size.abs() {
            handlers.push(EncodedTypeAddrPair::deserialize(input)?);
        }
        let catch_all_addr = if size <= 0 {
            Some(Uleb128::deserialize(input)?)
        } else {
            None
        };
        Ok(Self {
            handlers,
            catch_all_addr,
        })
    }
    fn size(&self) -> usize {
        self.size_field().size()
            + self.handlers.iter().map(|val| val.size()).sum::<usize>()
            + self
                .catch_all_addr
                .as_ref()
                .map(|val| val.size())
                .unwrap_or(0)
    }
}

/// <https://source.android.com/docs/core/runtime/dex-format#encoded-type-addr-pair>
#[derive(Serializable, Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct EncodedTypeAddrPair {
    /// Index of the [`crate::TypeIdItem`] in `type_ids`
    pub type_idx: Uleb128,
    /// Bytecode address of the exception handler
    pub addr: Uleb128,
}

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

    const CODE_ITEM_RAW_1: &[u8] = &[
        0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x3d, 0x25, 0x4f, 0x00, 0x15, 0x00, 0x00,
        0x00, 0x54, 0x30, 0x6c, 0x01, 0x71, 0x10, 0xb1, 0x0c, 0x00, 0x00, 0x28, 0x0e, 0x0d, 0x00,
        0x6e, 0x10, 0x26, 0x85, 0x00, 0x00, 0x0c, 0x01, 0x1a, 0x02, 0xcb, 0x15, 0x71, 0x20, 0xe3,
        0x05, 0x21, 0x00, 0x0a, 0x01, 0x38, 0x01, 0x03, 0x00, 0x0e, 0x00, 0x27, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x01, 0xe9, 0x46, 0x06,
    ];
    const CODE_ITEM_RAW_2: &[u8] = &[
        0x09, 0x00, 0x04, 0x00, 0x03, 0x00, 0x07, 0x00, 0xd7, 0x28, 0x4f, 0x00, 0x19, 0x01, 0x00,
        0x00, 0x70, 0x10, 0x8b, 0x84, 0x05, 0x00, 0x22, 0x00, 0x2d, 0x24, 0x70, 0x10, 0x51, 0x87,
        0x00, 0x00, 0x5b, 0x50, 0x54, 0x06, 0x5b, 0x57, 0x58, 0x06, 0x22, 0x00, 0x84, 0x05, 0x70,
        0x10, 0x09, 0x1c, 0x00, 0x00, 0x5b, 0x50, 0x56, 0x06, 0x54, 0x77, 0xcc, 0x09, 0x71, 0x20,
        0xed, 0x18, 0x76, 0x00, 0x0c, 0x07, 0x5b, 0x57, 0x55, 0x06, 0x71, 0x10, 0xb9, 0x17, 0x06,
        0x00, 0x0c, 0x06, 0x5b, 0x56, 0x57, 0x06, 0x22, 0x06, 0x1e, 0x24, 0x70, 0x10, 0xa1, 0x86,
        0x06, 0x00, 0x54, 0x70, 0x01, 0x08, 0x1f, 0x00, 0x7a, 0x04, 0x6e, 0x10, 0x8e, 0x84, 0x00,
        0x00, 0x54, 0x00, 0x04, 0x08, 0x6e, 0x10, 0x2a, 0x04, 0x00, 0x00, 0x0c, 0x00, 0x71, 0x10,
        0xbc, 0x86, 0x00, 0x00, 0x0c, 0x00, 0x39, 0x08, 0x16, 0x00, 0x72, 0x10, 0x8d, 0x87, 0x00,
        0x00, 0x0c, 0x07, 0x72, 0x10, 0x6c, 0x87, 0x07, 0x00, 0x0a, 0x08, 0x38, 0x08, 0x58, 0x00,
        0x72, 0x10, 0x6d, 0x87, 0x07, 0x00, 0x0c, 0x08, 0x1f, 0x08, 0x87, 0x23, 0x6e, 0x20, 0xa5,
        0x86, 0x86, 0x00, 0x28, 0xf1, 0x6e, 0x10, 0xf3, 0x19, 0x08, 0x00, 0x0c, 0x01, 0x71, 0x30,
        0x73, 0x17, 0x17, 0x00, 0x0c, 0x07, 0x28, 0x02, 0x12, 0x07, 0x22, 0x01, 0x1e, 0x24, 0x70,
        0x10, 0xa1, 0x86, 0x01, 0x00, 0x72, 0x10, 0x8d, 0x87, 0x00, 0x00, 0x0c, 0x00, 0x72, 0x10,
        0x6c, 0x87, 0x00, 0x00, 0x0a, 0x02, 0x38, 0x02, 0x17, 0x00, 0x72, 0x10, 0x6d, 0x87, 0x00,
        0x00, 0x0c, 0x02, 0x1f, 0x02, 0x87, 0x23, 0x6e, 0x20, 0xb5, 0x84, 0x72, 0x00, 0x0a, 0x03,
        0x38, 0x03, 0x03, 0x00, 0x28, 0xee, 0x6e, 0x20, 0x8f, 0x16, 0x25, 0x00, 0x0c, 0x02, 0x6e,
        0x20, 0xa5, 0x86, 0x21, 0x00, 0x28, 0xe6, 0x6e, 0x20, 0xf2, 0x19, 0x18, 0x00, 0x0c, 0x07,
        0x72, 0x10, 0x8d, 0x87, 0x07, 0x00, 0x0c, 0x07, 0x72, 0x10, 0x6c, 0x87, 0x07, 0x00, 0x0a,
        0x08, 0x38, 0x08, 0x12, 0x00, 0x72, 0x10, 0x6d, 0x87, 0x07, 0x00, 0x0c, 0x08, 0x1f, 0x08,
        0xd4, 0x04, 0x1f, 0x08, 0x7d, 0x05, 0x72, 0x10, 0xf3, 0x1b, 0x08, 0x00, 0x0c, 0x08, 0x6e,
        0x20, 0xa5, 0x86, 0x86, 0x00, 0x28, 0xeb, 0x22, 0x07, 0x1e, 0x24, 0x70, 0x10, 0xa1, 0x86,
        0x07, 0x00, 0x6e, 0x10, 0xaf, 0x86, 0x06, 0x00, 0x0c, 0x06, 0x72, 0x10, 0x6c, 0x87, 0x06,
        0x00, 0x0a, 0x08, 0x38, 0x08, 0x57, 0x00, 0x72, 0x10, 0x6d, 0x87, 0x06, 0x00, 0x0c, 0x08,
        0x1f, 0x08, 0x87, 0x23, 0x1a, 0x00, 0xb5, 0x0d, 0x6e, 0x20, 0xb5, 0x84, 0x08, 0x00, 0x0a,
        0x00, 0x39, 0x00, 0x45, 0x00, 0x1a, 0x00, 0xd0, 0x0d, 0x6e, 0x20, 0xb5, 0x84, 0x08, 0x00,
        0x0a, 0x00, 0x38, 0x00, 0x03, 0x00, 0x28, 0x3b, 0x62, 0x00, 0xe2, 0x00, 0x1a, 0x01, 0x49,
        0xc0, 0x6e, 0x20, 0xb5, 0x84, 0x01, 0x00, 0x0a, 0x00, 0x38, 0x00, 0x03, 0x00, 0x28, 0x1a,
        0x54, 0x50, 0x55, 0x06, 0x6e, 0x20, 0xee, 0x18, 0x80, 0x00, 0x0c, 0x00, 0x62, 0x01, 0xb6,
        0x00, 0x6e, 0x20, 0xc4, 0x18, 0x10, 0x00, 0x0c, 0x00, 0x1f, 0x00, 0x9c, 0x2e, 0x12, 0x01,
        0x38, 0x00, 0x0f, 0x00, 0x21, 0x02, 0x01, 0x13, 0x35, 0x23, 0x0b, 0x00, 0x44, 0x04, 0x00,
        0x03, 0x39, 0x04, 0x04, 0x00, 0x12, 0x11, 0x28, 0x04, 0xd8, 0x03, 0x03, 0x01, 0x28, 0xf6,
        0x38, 0x01, 0xba, 0xff, 0x6e, 0x20, 0xa5, 0x86, 0x87, 0x00, 0x28, 0xb5, 0x0d, 0x06, 0x22,
        0x07, 0x1e, 0x05, 0x71, 0x10, 0xff, 0x48, 0x06, 0x00, 0x0c, 0x06, 0x70, 0x20, 0xc2, 0x1a,
        0x67, 0x00, 0x27, 0x07, 0x6e, 0x20, 0xa5, 0x86, 0x87, 0x00, 0x28, 0xa6, 0x5b, 0x57, 0x53,
        0x06, 0x0e, 0x00, 0x0d, 0x06, 0x22, 0x07, 0x47, 0x04, 0x70, 0x20, 0x84, 0x18, 0x67, 0x00,
        0x27, 0x07, 0x0d, 0x06, 0x22, 0x07, 0x1e, 0x05, 0x70, 0x20, 0xc2, 0x1a, 0x67, 0x00, 0x27,
        0x07, 0x0d, 0x06, 0x22, 0x07, 0x1e, 0x05, 0x71, 0x10, 0xff, 0x48, 0x06, 0x00, 0x0c, 0x06,
        0x70, 0x20, 0xc2, 0x1a, 0x67, 0x00, 0x27, 0x07, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x0c,
        0x00, 0x01, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0a, 0x00, 0x33, 0x00, 0x00, 0x00,
        0x19, 0x00, 0x01, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x08, 0x00, 0x17, 0x00, 0x57, 0x00, 0x00,
        0x00, 0x41, 0x00, 0x01, 0x00, 0xca, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x23, 0x00, 0x01, 0x01,
        0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x04, 0x02, 0xc7, 0x08, 0x8e, 0x02, 0xd9, 0x09, 0x87,
        0x02, 0x03, 0xb4, 0x01, 0x80, 0x02, 0xc7, 0x08, 0x8e, 0x02, 0xd9, 0x09, 0x87, 0x02, 0x03,
        0xe9, 0x46, 0x56, 0xc7, 0x08, 0x8e, 0x02, 0xd9, 0x09, 0x87, 0x02, 0x01, 0xc7, 0x08, 0xee,
        0x01,
    ];

    const ENCODED_CATCH_HANDLER_LIST_1: &[u8] = &[0x01, 0x01, 0xe9, 0x46, 0x06];
    const ENCODED_CATCH_HANDLER_LIST_2: &[u8] = &[
        0x04, 0x02, 0xc7, 0x08, 0x8e, 0x02, 0xd9, 0x09, 0x87, 0x02, 0x03, 0xb4, 0x01, 0x80, 0x02,
        0xc7, 0x08, 0x8e, 0x02, 0xd9, 0x09, 0x87, 0x02, 0x03, 0xe9, 0x46, 0x56, 0xc7, 0x08, 0x8e,
        0x02, 0xd9, 0x09, 0x87, 0x02, 0x01, 0xc7, 0x08, 0xee, 0x01,
    ];

    fn insns_from_bin(raw: &[u16]) -> Vec<Instruction> {
        let mut insns = vec![];
        let raw: Vec<u8> = raw
            .iter()
            .map(|w| w.to_le_bytes().into_iter())
            .flatten()
            .collect();
        let len = raw.len() as u64;
        let mut buffer = std::io::Cursor::new(raw);
        while buffer.position() < len {
            insns.push(Instruction::deserialize(&mut buffer).unwrap());
        }
        insns
    }

    #[test]
    fn test_deserialize_code_item() {
        assert_eq!(
            CodeItem::deserialize_from_slice(CODE_ITEM_RAW_1).unwrap(),
            CodeItem {
                registers_size: 4,
                ins_size: 1,
                outs_size: 2,
                debug_info_off: 5186877,
                insns: insns_from_bin(&[
                    0x3054, 0x16c, 0x1071, 0xcb1, 0x0, 0xe28, 0xd, 0x106e, 0x8526, 0x0, 0x10c,
                    0x21a, 0x15cb, 0x2071, 0x5e3, 0x21, 0x10a, 0x138, 0x3, 0xe, 0x27
                ]),
                tries: vec![TryItem {
                    start_addr: 0,
                    insn_count: 5,
                    handler_off: 1,
                },],
                handlers: Some(EncodedCatchHandlerList {
                    list: vec![EncodedCatchHandler {
                        handlers: vec![EncodedTypeAddrPair {
                            type_idx: Uleb128(9065),
                            addr: Uleb128(6)
                        }],
                        catch_all_addr: None,
                    }]
                })
            }
        );
        assert_eq!(
            CodeItem::deserialize_from_slice(CODE_ITEM_RAW_2).unwrap(),
            CodeItem {
                registers_size: 9,
                ins_size: 4,
                outs_size: 3,
                debug_info_off: 5187799,
                insns: insns_from_bin(&[
                    0x1070, 0x848b, 0x0005, 0x0022, 0x242d, 0x1070, 0x8751, 0x0000, 0x505b, 0x0654,
                    0x575b, 0x0658, 0x0022, 0x0584, 0x1070, 0x1c09, 0x0000, 0x505b, 0x0656, 0x7754,
                    0x09cc, 0x2071, 0x18ed, 0x0076, 0x070c, 0x575b, 0x0655, 0x1071, 0x17b9, 0x0006,
                    0x060c, 0x565b, 0x0657, 0x0622, 0x241e, 0x1070, 0x86a1, 0x0006, 0x7054, 0x0801,
                    0x001f, 0x047a, 0x106e, 0x848e, 0x0000, 0x0054, 0x0804, 0x106e, 0x042a, 0x0000,
                    0x000c, 0x1071, 0x86bc, 0x0000, 0x000c, 0x0839, 0x0016, 0x1072, 0x878d, 0x0000,
                    0x070c, 0x1072, 0x876c, 0x0007, 0x080a, 0x0838, 0x0058, 0x1072, 0x876d, 0x0007,
                    0x080c, 0x081f, 0x2387, 0x206e, 0x86a5, 0x0086, 0xf128, 0x106e, 0x19f3, 0x0008,
                    0x010c, 0x3071, 0x1773, 0x0017, 0x070c, 0x0228, 0x0712, 0x0122, 0x241e, 0x1070,
                    0x86a1, 0x0001, 0x1072, 0x878d, 0x0000, 0x000c, 0x1072, 0x876c, 0x0000, 0x020a,
                    0x0238, 0x0017, 0x1072, 0x876d, 0x0000, 0x020c, 0x021f, 0x2387, 0x206e, 0x84b5,
                    0x0072, 0x030a, 0x0338, 0x0003, 0xee28, 0x206e, 0x168f, 0x0025, 0x020c, 0x206e,
                    0x86a5, 0x0021, 0xe628, 0x206e, 0x19f2, 0x0018, 0x070c, 0x1072, 0x878d, 0x0007,
                    0x070c, 0x1072, 0x876c, 0x0007, 0x080a, 0x0838, 0x0012, 0x1072, 0x876d, 0x0007,
                    0x080c, 0x081f, 0x04d4, 0x081f, 0x057d, 0x1072, 0x1bf3, 0x0008, 0x080c, 0x206e,
                    0x86a5, 0x0086, 0xeb28, 0x0722, 0x241e, 0x1070, 0x86a1, 0x0007, 0x106e, 0x86af,
                    0x0006, 0x060c, 0x1072, 0x876c, 0x0006, 0x080a, 0x0838, 0x0057, 0x1072, 0x876d,
                    0x0006, 0x080c, 0x081f, 0x2387, 0x001a, 0x0db5, 0x206e, 0x84b5, 0x0008, 0x000a,
                    0x0039, 0x0045, 0x001a, 0x0dd0, 0x206e, 0x84b5, 0x0008, 0x000a, 0x0038, 0x0003,
                    0x3b28, 0x0062, 0x00e2, 0x011a, 0xc049, 0x206e, 0x84b5, 0x0001, 0x000a, 0x0038,
                    0x0003, 0x1a28, 0x5054, 0x0655, 0x206e, 0x18ee, 0x0080, 0x000c, 0x0162, 0x00b6,
                    0x206e, 0x18c4, 0x0010, 0x000c, 0x001f, 0x2e9c, 0x0112, 0x0038, 0x000f, 0x0221,
                    0x1301, 0x2335, 0x000b, 0x0444, 0x0300, 0x0439, 0x0004, 0x1112, 0x0428, 0x03d8,
                    0x0103, 0xf628, 0x0138, 0xffba, 0x206e, 0x86a5, 0x0087, 0xb528, 0x060d, 0x0722,
                    0x051e, 0x1071, 0x48ff, 0x0006, 0x060c, 0x2070, 0x1ac2, 0x0067, 0x0727, 0x206e,
                    0x86a5, 0x0087, 0xa628, 0x575b, 0x0653, 0x000e, 0x060d, 0x0722, 0x0447, 0x2070,
                    0x1884, 0x0067, 0x0727, 0x060d, 0x0722, 0x051e, 0x2070, 0x1ac2, 0x0067, 0x0727,
                    0x060d, 0x0722, 0x051e, 0x1071, 0x48ff, 0x0006, 0x060c, 0x2070, 0x1ac2, 0x0067,
                    0x0727,
                ]),
                tries: vec![
                    TryItem {
                        start_addr: 33,
                        insn_count: 12,
                        handler_off: 1
                    },
                    TryItem {
                        start_addr: 45,
                        insn_count: 6,
                        handler_off: 10
                    },
                    TryItem {
                        start_addr: 51,
                        insn_count: 25,
                        handler_off: 1
                    },
                    TryItem {
                        start_addr: 77,
                        insn_count: 8,
                        handler_off: 23
                    },
                    TryItem {
                        start_addr: 87,
                        insn_count: 65,
                        handler_off: 1
                    },
                    TryItem {
                        start_addr: 202,
                        insn_count: 14,
                        handler_off: 35
                    },
                    TryItem {
                        start_addr: 257,
                        insn_count: 6,
                        handler_off: 1
                    },
                ],
                handlers: Some(EncodedCatchHandlerList {
                    list: vec![
                        EncodedCatchHandler {
                            handlers: vec![
                                EncodedTypeAddrPair {
                                    type_idx: Uleb128(1095),
                                    addr: Uleb128(0x10e),
                                },
                                EncodedTypeAddrPair {
                                    type_idx: Uleb128(1241),
                                    addr: Uleb128(0x107),
                                },
                            ],
                            catch_all_addr: None,
                        },
                        EncodedCatchHandler {
                            handlers: vec![
                                EncodedTypeAddrPair {
                                    type_idx: Uleb128(180),
                                    addr: Uleb128(0x100),
                                },
                                EncodedTypeAddrPair {
                                    type_idx: Uleb128(1095),
                                    addr: Uleb128(0x10e),
                                },
                                EncodedTypeAddrPair {
                                    type_idx: Uleb128(1241),
                                    addr: Uleb128(0x107),
                                },
                            ],
                            catch_all_addr: None,
                        },
                        EncodedCatchHandler {
                            handlers: vec![
                                EncodedTypeAddrPair {
                                    type_idx: Uleb128(9065),
                                    addr: Uleb128(0x56),
                                },
                                EncodedTypeAddrPair {
                                    type_idx: Uleb128(1095),
                                    addr: Uleb128(0x10e),
                                },
                                EncodedTypeAddrPair {
                                    type_idx: Uleb128(1241),
                                    addr: Uleb128(0x107),
                                },
                            ],
                            catch_all_addr: None,
                        },
                        EncodedCatchHandler {
                            handlers: vec![EncodedTypeAddrPair {
                                type_idx: Uleb128(1095),
                                addr: Uleb128(0xee),
                            }],
                            catch_all_addr: None,
                        },
                    ],
                }),
            }
        );
    }

    #[test]
    fn test_deserialize_catch_handler_list() {
        assert_eq!(
            EncodedCatchHandlerList::deserialize_from_slice(ENCODED_CATCH_HANDLER_LIST_1).unwrap(),
            EncodedCatchHandlerList {
                list: vec![EncodedCatchHandler {
                    handlers: vec![EncodedTypeAddrPair {
                        type_idx: Uleb128(9065),
                        addr: Uleb128(6)
                    }],
                    catch_all_addr: None,
                }]
            }
        );

        assert_eq!(
            EncodedCatchHandlerList::deserialize_from_slice(ENCODED_CATCH_HANDLER_LIST_2).unwrap(),
            EncodedCatchHandlerList {
                list: vec![
                    EncodedCatchHandler {
                        handlers: vec![
                            EncodedTypeAddrPair {
                                type_idx: Uleb128(1095),
                                addr: Uleb128(0x10e),
                            },
                            EncodedTypeAddrPair {
                                type_idx: Uleb128(1241),
                                addr: Uleb128(0x107),
                            },
                        ],
                        catch_all_addr: None,
                    },
                    EncodedCatchHandler {
                        handlers: vec![
                            EncodedTypeAddrPair {
                                type_idx: Uleb128(180),
                                addr: Uleb128(0x100),
                            },
                            EncodedTypeAddrPair {
                                type_idx: Uleb128(1095),
                                addr: Uleb128(0x10e),
                            },
                            EncodedTypeAddrPair {
                                type_idx: Uleb128(1241),
                                addr: Uleb128(0x107),
                            },
                        ],
                        catch_all_addr: None,
                    },
                    EncodedCatchHandler {
                        handlers: vec![
                            EncodedTypeAddrPair {
                                type_idx: Uleb128(9065),
                                addr: Uleb128(0x56),
                            },
                            EncodedTypeAddrPair {
                                type_idx: Uleb128(1095),
                                addr: Uleb128(0x10e),
                            },
                            EncodedTypeAddrPair {
                                type_idx: Uleb128(1241),
                                addr: Uleb128(0x107),
                            },
                        ],
                        catch_all_addr: None,
                    },
                    EncodedCatchHandler {
                        handlers: vec![EncodedTypeAddrPair {
                            type_idx: Uleb128(1095),
                            addr: Uleb128(0xee),
                        }],
                        catch_all_addr: None,
                    },
                ],
            }
        );
    }

    #[test]
    fn test_get_handler_at_offset() {
        let list = EncodedCatchHandlerList {
            list: vec![
                EncodedCatchHandler {
                    handlers: vec![
                        EncodedTypeAddrPair {
                            type_idx: Uleb128(1095),
                            addr: Uleb128(0x10e),
                        },
                        EncodedTypeAddrPair {
                            type_idx: Uleb128(1241),
                            addr: Uleb128(0x107),
                        },
                    ],
                    catch_all_addr: None,
                },
                EncodedCatchHandler {
                    handlers: vec![
                        EncodedTypeAddrPair {
                            type_idx: Uleb128(180),
                            addr: Uleb128(0x100),
                        },
                        EncodedTypeAddrPair {
                            type_idx: Uleb128(1095),
                            addr: Uleb128(0x10e),
                        },
                        EncodedTypeAddrPair {
                            type_idx: Uleb128(1241),
                            addr: Uleb128(0x107),
                        },
                    ],
                    catch_all_addr: None,
                },
                EncodedCatchHandler {
                    handlers: vec![
                        EncodedTypeAddrPair {
                            type_idx: Uleb128(9065),
                            addr: Uleb128(0x56),
                        },
                        EncodedTypeAddrPair {
                            type_idx: Uleb128(1095),
                            addr: Uleb128(0x10e),
                        },
                        EncodedTypeAddrPair {
                            type_idx: Uleb128(1241),
                            addr: Uleb128(0x107),
                        },
                    ],
                    catch_all_addr: None,
                },
                EncodedCatchHandler {
                    handlers: vec![EncodedTypeAddrPair {
                        type_idx: Uleb128(1095),
                        addr: Uleb128(0xee),
                    }],
                    catch_all_addr: None,
                },
            ],
        };
        assert_eq!(
            list.get_handler_at_offset(1).unwrap(),
            &EncodedCatchHandler {
                handlers: vec![
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1095),
                        addr: Uleb128(0x10e),
                    },
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1241),
                        addr: Uleb128(0x107),
                    },
                ],
                catch_all_addr: None,
            }
        );
        assert_eq!(
            list.get_handler_at_offset(10).unwrap(),
            &EncodedCatchHandler {
                handlers: vec![
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(180),
                        addr: Uleb128(0x100),
                    },
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1095),
                        addr: Uleb128(0x10e),
                    },
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1241),
                        addr: Uleb128(0x107),
                    },
                ],
                catch_all_addr: None,
            },
        );
        assert_eq!(
            list.get_handler_at_offset(23).unwrap(),
            &EncodedCatchHandler {
                handlers: vec![
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(9065),
                        addr: Uleb128(0x56),
                    },
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1095),
                        addr: Uleb128(0x10e),
                    },
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1241),
                        addr: Uleb128(0x107),
                    },
                ],
                catch_all_addr: None,
            },
        );
        assert_eq!(
            list.get_handler_at_offset(35).unwrap(),
            &EncodedCatchHandler {
                handlers: vec![EncodedTypeAddrPair {
                    type_idx: Uleb128(1095),
                    addr: Uleb128(0xee),
                }],
                catch_all_addr: None,
            },
        );
    }

    #[test]
    fn test_encoded_catch_handler_size() {
        assert_eq!(
            EncodedCatchHandler {
                handlers: vec![
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1095),
                        addr: Uleb128(0x10e),
                    },
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1241),
                        addr: Uleb128(0x107),
                    },
                ],
                catch_all_addr: None,
            }
            .size(),
            9
        );
        assert_eq!(
            EncodedCatchHandler {
                handlers: vec![
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(180),
                        addr: Uleb128(0x100),
                    },
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1095),
                        addr: Uleb128(0x10e),
                    },
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1241),
                        addr: Uleb128(0x107),
                    },
                ],
                catch_all_addr: None,
            }
            .size(),
            13
        );
        assert_eq!(
            EncodedCatchHandler {
                handlers: vec![
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(9065),
                        addr: Uleb128(0x56),
                    },
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1095),
                        addr: Uleb128(0x10e),
                    },
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1241),
                        addr: Uleb128(0x107),
                    },
                ],
                catch_all_addr: None,
            }
            .size(),
            12
        );
        assert_eq!(
            EncodedCatchHandler {
                handlers: vec![EncodedTypeAddrPair {
                    type_idx: Uleb128(1095),
                    addr: Uleb128(0xee),
                },],
                catch_all_addr: None,
            }
            .size(),
            5
        );
    }

    #[test]
    fn test_encoded_catch_handler_serialize() {
        assert_eq!(
            EncodedCatchHandler {
                handlers: vec![
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1095),
                        addr: Uleb128(0x10e),
                    },
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1241),
                        addr: Uleb128(0x107),
                    },
                ],
                catch_all_addr: None,
            }
            .serialize_to_vec()
            .unwrap(),
            vec![0x02, 0xc7, 0x08, 0x8e, 0x02, 0xd9, 0x09, 0x87, 0x02,],
        );
        assert_eq!(
            EncodedCatchHandler {
                handlers: vec![
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(180),
                        addr: Uleb128(0x100),
                    },
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1095),
                        addr: Uleb128(0x10e),
                    },
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1241),
                        addr: Uleb128(0x107),
                    },
                ],
                catch_all_addr: None,
            }
            .serialize_to_vec()
            .unwrap(),
            vec![0x03, 0xb4, 0x01, 0x80, 0x02, 0xc7, 0x08, 0x8e, 0x02, 0xd9, 0x09, 0x87, 0x02,]
        );
        assert_eq!(
            EncodedCatchHandler {
                handlers: vec![
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(9065),
                        addr: Uleb128(0x56),
                    },
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1095),
                        addr: Uleb128(0x10e),
                    },
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1241),
                        addr: Uleb128(0x107),
                    },
                ],
                catch_all_addr: None,
            }
            .serialize_to_vec()
            .unwrap(),
            vec![0x03, 0xe9, 0x46, 0x56, 0xc7, 0x08, 0x8e, 0x02, 0xd9, 0x09, 0x87, 0x02,]
        );
        assert_eq!(
            EncodedCatchHandler {
                handlers: vec![EncodedTypeAddrPair {
                    type_idx: Uleb128(1095),
                    addr: Uleb128(0xee),
                },],
                catch_all_addr: None,
            }
            .serialize_to_vec()
            .unwrap(),
            vec![0x01, 0xc7, 0x08, 0xee, 0x01,]
        );
    }

    #[test]
    fn test_encoded_catch_handler_deserialize() {
        assert_eq!(
            EncodedCatchHandler {
                handlers: vec![
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1095),
                        addr: Uleb128(0x10e),
                    },
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1241),
                        addr: Uleb128(0x107),
                    },
                ],
                catch_all_addr: None,
            },
            EncodedCatchHandler::deserialize_from_slice(&[
                0x02, 0xc7, 0x08, 0x8e, 0x02, 0xd9, 0x09, 0x87, 0x02,
            ])
            .unwrap()
        );
        assert_eq!(
            EncodedCatchHandler {
                handlers: vec![
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(180),
                        addr: Uleb128(0x100),
                    },
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1095),
                        addr: Uleb128(0x10e),
                    },
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1241),
                        addr: Uleb128(0x107),
                    },
                ],
                catch_all_addr: None,
            },
            EncodedCatchHandler::deserialize_from_slice(&[
                0x03, 0xb4, 0x01, 0x80, 0x02, 0xc7, 0x08, 0x8e, 0x02, 0xd9, 0x09, 0x87, 0x02,
            ])
            .unwrap()
        );
        assert_eq!(
            EncodedCatchHandler {
                handlers: vec![
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(9065),
                        addr: Uleb128(0x56),
                    },
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1095),
                        addr: Uleb128(0x10e),
                    },
                    EncodedTypeAddrPair {
                        type_idx: Uleb128(1241),
                        addr: Uleb128(0x107),
                    },
                ],
                catch_all_addr: None,
            },
            EncodedCatchHandler::deserialize_from_slice(&[
                0x03, 0xe9, 0x46, 0x56, 0xc7, 0x08, 0x8e, 0x02, 0xd9, 0x09, 0x87, 0x02,
            ])
            .unwrap()
        );
        assert_eq!(
            EncodedCatchHandler {
                handlers: vec![EncodedTypeAddrPair {
                    type_idx: Uleb128(1095),
                    addr: Uleb128(0xee),
                },],
                catch_all_addr: None,
            },
            EncodedCatchHandler::deserialize_from_slice(&[0x01, 0xc7, 0x08, 0xee, 0x01,]).unwrap()
        );
    }

    const _INSN_RAW_1: &[u8] = &[
        0x70, 0x10, 0x8b, 0x84, 0x05, 0x00, 0x22, 0x00, 0x2d, 0x24, 0x70, 0x10, 0x51, 0x87, 0x00,
        0x00, 0x5b, 0x50, 0x54, 0x06, 0x5b, 0x57, 0x58, 0x06, 0x22, 0x00, 0x84, 0x05, 0x70, 0x10,
        0x09, 0x1c, 0x00, 0x00, 0x5b, 0x50, 0x56, 0x06, 0x54, 0x77, 0xcc, 0x09, 0x71, 0x20, 0xed,
        0x18, 0x76, 0x00, 0x0c, 0x07, 0x5b, 0x57, 0x55, 0x06, 0x71, 0x10, 0xb9, 0x17, 0x06, 0x00,
        0x0c, 0x06, 0x5b, 0x56, 0x57, 0x06, 0x22, 0x06, 0x1e, 0x24, 0x70, 0x10, 0xa1, 0x86, 0x06,
        0x00, 0x54, 0x70, 0x01, 0x08, 0x1f, 0x00, 0x7a, 0x04, 0x6e, 0x10, 0x8e, 0x84, 0x00, 0x00,
        0x54, 0x00, 0x04, 0x08, 0x6e, 0x10, 0x2a, 0x04, 0x00, 0x00, 0x0c, 0x00, 0x71, 0x10, 0xbc,
        0x86, 0x00, 0x00, 0x0c, 0x00, 0x39, 0x08, 0x16, 0x00, 0x72, 0x10, 0x8d, 0x87, 0x00, 0x00,
        0x0c, 0x07, 0x72, 0x10, 0x6c, 0x87, 0x07, 0x00, 0x0a, 0x08, 0x38, 0x08, 0x58, 0x00, 0x72,
        0x10, 0x6d, 0x87, 0x07, 0x00, 0x0c, 0x08, 0x1f, 0x08, 0x87, 0x23, 0x6e, 0x20, 0xa5, 0x86,
        0x86, 0x00, 0x28, 0xf1, 0x6e, 0x10, 0xf3, 0x19, 0x08, 0x00, 0x0c, 0x01, 0x71, 0x30, 0x73,
        0x17, 0x17, 0x00, 0x0c, 0x07, 0x28, 0x02, 0x12, 0x07, 0x22, 0x01, 0x1e, 0x24, 0x70, 0x10,
        0xa1, 0x86, 0x01, 0x00, 0x72, 0x10, 0x8d, 0x87, 0x00, 0x00, 0x0c, 0x00, 0x72, 0x10, 0x6c,
        0x87, 0x00, 0x00, 0x0a, 0x02, 0x38, 0x02, 0x17, 0x00, 0x72, 0x10, 0x6d, 0x87, 0x00, 0x00,
        0x0c, 0x02, 0x1f, 0x02, 0x87, 0x23, 0x6e, 0x20, 0xb5, 0x84, 0x72, 0x00, 0x0a, 0x03, 0x38,
        0x03, 0x03, 0x00, 0x28, 0xee, 0x6e, 0x20, 0x8f, 0x16, 0x25, 0x00, 0x0c, 0x02, 0x6e, 0x20,
        0xa5, 0x86, 0x21, 0x00, 0x28, 0xe6, 0x6e, 0x20, 0xf2, 0x19, 0x18, 0x00, 0x0c, 0x07, 0x72,
        0x10, 0x8d, 0x87, 0x07, 0x00, 0x0c, 0x07, 0x72, 0x10, 0x6c, 0x87, 0x07, 0x00, 0x0a, 0x08,
        0x38, 0x08, 0x12, 0x00, 0x72, 0x10, 0x6d, 0x87, 0x07, 0x00, 0x0c, 0x08, 0x1f, 0x08, 0xd4,
        0x04, 0x1f, 0x08, 0x7d, 0x05, 0x72, 0x10, 0xf3, 0x1b, 0x08, 0x00, 0x0c, 0x08, 0x6e, 0x20,
        0xa5, 0x86, 0x86, 0x00, 0x28, 0xeb, 0x22, 0x07, 0x1e, 0x24, 0x70, 0x10, 0xa1, 0x86, 0x07,
        0x00, 0x6e, 0x10, 0xaf, 0x86, 0x06, 0x00, 0x0c, 0x06, 0x72, 0x10, 0x6c, 0x87, 0x06, 0x00,
        0x0a, 0x08, 0x38, 0x08, 0x57, 0x00, 0x72, 0x10, 0x6d, 0x87, 0x06, 0x00, 0x0c, 0x08, 0x1f,
        0x08, 0x87, 0x23, 0x1a, 0x00, 0xb5, 0x0d, 0x6e, 0x20, 0xb5, 0x84, 0x08, 0x00, 0x0a, 0x00,
        0x39, 0x00, 0x45, 0x00, 0x1a, 0x00, 0xd0, 0x0d, 0x6e, 0x20, 0xb5, 0x84, 0x08, 0x00, 0x0a,
        0x00, 0x38, 0x00, 0x03, 0x00, 0x28, 0x3b, 0x62, 0x00, 0xe2, 0x00, 0x1a, 0x01, 0x49, 0xc0,
        0x6e, 0x20, 0xb5, 0x84, 0x01, 0x00, 0x0a, 0x00, 0x38, 0x00, 0x03, 0x00, 0x28, 0x1a, 0x54,
        0x50, 0x55, 0x06, 0x6e, 0x20, 0xee, 0x18, 0x80, 0x00, 0x0c, 0x00, 0x62, 0x01, 0xb6, 0x00,
        0x6e, 0x20, 0xc4, 0x18, 0x10, 0x00, 0x0c, 0x00, 0x1f, 0x00, 0x9c, 0x2e, 0x12, 0x01, 0x38,
        0x00, 0x0f, 0x00, 0x21, 0x02, 0x01, 0x13, 0x35, 0x23, 0x0b, 0x00, 0x44, 0x04, 0x00, 0x03,
        0x39, 0x04, 0x04, 0x00, 0x12, 0x11, 0x28, 0x04, 0xd8, 0x03, 0x03, 0x01, 0x28, 0xf6, 0x38,
        0x01, 0xba, 0xff, 0x6e, 0x20, 0xa5, 0x86, 0x87, 0x00, 0x28, 0xb5, 0x0d, 0x06, 0x22, 0x07,
        0x1e, 0x05, 0x71, 0x10, 0xff, 0x48, 0x06, 0x00, 0x0c, 0x06, 0x70, 0x20, 0xc2, 0x1a, 0x67,
        0x00, 0x27, 0x07, 0x6e, 0x20, 0xa5, 0x86, 0x87, 0x00, 0x28, 0xa6, 0x5b, 0x57, 0x53, 0x06,
        0x0e, 0x00, 0x0d, 0x06, 0x22, 0x07, 0x47, 0x04, 0x70, 0x20, 0x84, 0x18, 0x67, 0x00, 0x27,
        0x07, 0x0d, 0x06, 0x22, 0x07, 0x1e, 0x05, 0x70, 0x20, 0xc2, 0x1a, 0x67, 0x00, 0x27, 0x07,
        0x0d, 0x06, 0x22, 0x07, 0x1e, 0x05, 0x71, 0x10, 0xff, 0x48, 0x06, 0x00, 0x0c, 0x06, 0x70,
        0x20, 0xc2, 0x1a, 0x67, 0x00, 0x27, 0x07,
    ];

    #[test]
    fn test_code() {
        let code = CodeItem {
            registers_size: 3,
            ins_size: 1,
            outs_size: 2,
            debug_info_off: 1205,
            insns: vec![
                Format35C {
                    a: 1,
                    vg: 0,
                    op: 112,
                    b: 2,
                    vf: 0,
                    ve: 0,
                    vd: 0,
                    vc: 2,
                },
                Format21C {
                    va: 0,
                    op: 34,
                    b: 2,
                },
                Format35C {
                    a: 1,
                    vg: 0,
                    op: 112,
                    b: 0,
                    vf: 0,
                    ve: 0,
                    vd: 0,
                    vc: 0,
                },
                Format22C {
                    vb: 2,
                    va: 0,
                    op: 91,
                    c: 1,
                },
                Format21C {
                    va: 1,
                    op: 26,
                    b: 18,
                },
                Format35C {
                    a: 2,
                    vg: 0,
                    op: 110,
                    b: 1,
                    vf: 0,
                    ve: 0,
                    vd: 1,
                    vc: 0,
                },
                Format10X { op: 14 },
            ],
            tries: vec![],
            handlers: None,
        };
        let raw = vec![
            0x03, 0x00, // registers_size
            0x01, 0x00, // ins_size
            0x02, 0x00, // outs_size
            0x00, 0x00, // tries_size
            0xb5, 0x04, 0x00, 0x00, // debug_info_off
            0x10, 0x00, 0x00, 0x00, // insns_size
            0x70, 0x10, 0x02, 0x00, 0x02, 0x00, // Format35C
            0x22, 0x00, 0x02, 0x00, // Format21C
            0x70, 0x10, 0x00, 0x00, 0x00, 0x00, // Format35C
            0x5b, 0x20, 0x01, 0x00, // Format22C
            0x1a, 0x01, 0x12, 0x00, // Format21C
            0x6e, 0x20, 0x01, 0x00, 0x10, 0x00, // Format35C
            0x0e, 0x00, // Format10X
        ];
        assert_eq!(code.serialize_to_vec().unwrap(), raw);
        assert_eq!(code, CodeItem::deserialize_from_slice(&raw).unwrap());
        assert_eq!(code.size(), raw.len());
    }

    #[test]
    fn test_code_with_handler() {
        let code = CodeItem {
            registers_size: 6,
            ins_size: 0,
            outs_size: 1,
            debug_info_off: 27,
            insns: vec![
                Format35C {
                    a: 0,
                    vg: 0,
                    op: 113,
                    b: 4,
                    vf: 0,
                    ve: 0,
                    vd: 0,
                    vc: 0,
                },
                Format11X { va: 0, op: 12 },
                Format12X {
                    vb: 0,
                    va: 0,
                    op: 33,
                },
                Format22C {
                    vb: 0,
                    va: 0,
                    op: 35,
                    c: 27,
                },
                Format21C {
                    va: 0,
                    op: 105,
                    b: 10,
                },
                Format11N {
                    b: 1,
                    va: 1,
                    op: 18,
                },
                Format21C {
                    va: 2,
                    op: 98,
                    b: 11,
                },
                Format35C {
                    a: 1,
                    vg: 0,
                    op: 110,
                    b: 3,
                    vf: 0,
                    ve: 0,
                    vd: 0,
                    vc: 2,
                },
                Format11X { va: 2, op: 10 },
                Format23X {
                    va: 1,
                    op: 75,
                    vc: 2,
                    vb: 0,
                },
                Format11N {
                    b: 2,
                    va: 0,
                    op: 18,
                },
                Format21C {
                    va: 2,
                    op: 98,
                    b: 10,
                },
                Format21C {
                    va: 3,
                    op: 98,
                    b: 14,
                },
                Format35C {
                    a: 1,
                    vg: 0,
                    op: 110,
                    b: 3,
                    vf: 0,
                    ve: 0,
                    vd: 0,
                    vc: 3,
                },
                Format11X { va: 3, op: 10 },
                Format23X {
                    va: 0,
                    op: 75,
                    vc: 3,
                    vb: 2,
                },
                Format11N {
                    b: 3,
                    va: 2,
                    op: 18,
                },
                Format21C {
                    va: 3,
                    op: 98,
                    b: 10,
                },
                Format21C {
                    va: 4,
                    op: 98,
                    b: 13,
                },
                Format35C {
                    a: 1,
                    vg: 0,
                    op: 110,
                    b: 3,
                    vf: 0,
                    ve: 0,
                    vd: 0,
                    vc: 4,
                },
                Format11X { va: 4, op: 10 },
                Format23X {
                    va: 2,
                    op: 75,
                    vc: 4,
                    vb: 3,
                },
                Format11N {
                    b: 4,
                    va: 3,
                    op: 18,
                },
                Format21C {
                    va: 4,
                    op: 98,
                    b: 10,
                },
                Format21C {
                    va: 5,
                    op: 98,
                    b: 12,
                },
                Format35C {
                    a: 1,
                    vg: 0,
                    op: 110,
                    b: 3,
                    vf: 0,
                    ve: 0,
                    vd: 0,
                    vc: 5,
                },
                Format11X { va: 5, op: 10 },
                Format23X {
                    va: 3,
                    op: 75,
                    vc: 5,
                    vb: 4,
                },
                Format35C {
                    a: 0,
                    vg: 0,
                    op: 113,
                    b: 1,
                    vf: 0,
                    ve: 0,
                    vd: 0,
                    vc: 0,
                },
                Format11X { va: 4, op: 12 },
                Format12X {
                    vb: 4,
                    va: 4,
                    op: 33,
                },
                Format22C {
                    vb: 4,
                    va: 4,
                    op: 35,
                    c: 27,
                },
                Format21C {
                    va: 4,
                    op: 105,
                    b: 9,
                },
                Format21C {
                    va: 5,
                    op: 98,
                    b: 5,
                },
                Format35C {
                    a: 1,
                    vg: 0,
                    op: 110,
                    b: 0,
                    vf: 0,
                    ve: 0,
                    vd: 0,
                    vc: 5,
                },
                Format11X { va: 5, op: 10 },
                Format23X {
                    va: 1,
                    op: 75,
                    vc: 5,
                    vb: 4,
                },
                Format21C {
                    va: 1,
                    op: 98,
                    b: 9,
                },
                Format21C {
                    va: 4,
                    op: 98,
                    b: 8,
                },
                Format35C {
                    a: 1,
                    vg: 0,
                    op: 110,
                    b: 0,
                    vf: 0,
                    ve: 0,
                    vd: 0,
                    vc: 4,
                },
                Format11X { va: 4, op: 10 },
                Format23X {
                    va: 0,
                    op: 75,
                    vc: 4,
                    vb: 1,
                },
                Format21C {
                    va: 0,
                    op: 98,
                    b: 9,
                },
                Format21C {
                    va: 1,
                    op: 98,
                    b: 7,
                },
                Format35C {
                    a: 1,
                    vg: 0,
                    op: 110,
                    b: 0,
                    vf: 0,
                    ve: 0,
                    vd: 0,
                    vc: 1,
                },
                Format11X { va: 1, op: 10 },
                Format23X {
                    va: 2,
                    op: 75,
                    vc: 1,
                    vb: 0,
                },
                Format21C {
                    va: 0,
                    op: 98,
                    b: 9,
                },
                Format21C {
                    va: 1,
                    op: 98,
                    b: 1,
                },
                Format35C {
                    a: 1,
                    vg: 0,
                    op: 110,
                    b: 0,
                    vf: 0,
                    ve: 0,
                    vd: 0,
                    vc: 1,
                },
                Format11X { va: 1, op: 10 },
                Format23X {
                    va: 3,
                    op: 75,
                    vc: 1,
                    vb: 0,
                },
                Format21C {
                    va: 0,
                    op: 98,
                    b: 9,
                },
                Format21C {
                    va: 1,
                    op: 98,
                    b: 0,
                },
                Format35C {
                    a: 1,
                    vg: 0,
                    op: 110,
                    b: 0,
                    vf: 0,
                    ve: 0,
                    vd: 0,
                    vc: 1,
                },
                Format11X { va: 1, op: 10 },
                Format11N {
                    b: 5,
                    va: 2,
                    op: 18,
                },
                Format23X {
                    va: 2,
                    op: 75,
                    vc: 1,
                    vb: 0,
                },
                Format21C {
                    va: 0,
                    op: 98,
                    b: 9,
                },
                Format21C {
                    va: 1,
                    op: 98,
                    b: 2,
                },
                Format35C {
                    a: 1,
                    vg: 0,
                    op: 110,
                    b: 0,
                    vf: 0,
                    ve: 0,
                    vd: 0,
                    vc: 1,
                },
                Format11X { va: 1, op: 10 },
                Format11N {
                    b: 6,
                    va: 2,
                    op: 18,
                },
                Format23X {
                    va: 2,
                    op: 75,
                    vc: 1,
                    vb: 0,
                },
                Format21C {
                    va: 0,
                    op: 98,
                    b: 9,
                },
                Format21C {
                    va: 1,
                    op: 98,
                    b: 3,
                },
                Format35C {
                    a: 1,
                    vg: 0,
                    op: 110,
                    b: 0,
                    vf: 0,
                    ve: 0,
                    vd: 0,
                    vc: 1,
                },
                Format11X { va: 1, op: 10 },
                Format11N {
                    b: 7,
                    va: 2,
                    op: 18,
                },
                Format23X {
                    va: 2,
                    op: 75,
                    vc: 1,
                    vb: 0,
                },
                Format21C {
                    va: 0,
                    op: 98,
                    b: 9,
                },
                Format21C {
                    va: 1,
                    op: 98,
                    b: 4,
                },
                Format35C {
                    a: 1,
                    vg: 0,
                    op: 110,
                    b: 0,
                    vf: 0,
                    ve: 0,
                    vd: 0,
                    vc: 1,
                },
                Format11X { va: 1, op: 10 },
                Format21S {
                    va: 2,
                    op: 19,
                    b: 8,
                },
                Format23X {
                    va: 2,
                    op: 75,
                    vc: 1,
                    vb: 0,
                },
                Format21C {
                    va: 0,
                    op: 98,
                    b: 9,
                },
                Format21C {
                    va: 1,
                    op: 98,
                    b: 6,
                },
                Format35C {
                    a: 1,
                    vg: 0,
                    op: 110,
                    b: 0,
                    vf: 0,
                    ve: 0,
                    vd: 0,
                    vc: 1,
                },
                Format11X { va: 1, op: 10 },
                Format21S {
                    va: 2,
                    op: 19,
                    b: 9,
                },
                Format23X {
                    va: 2,
                    op: 75,
                    vc: 1,
                    vb: 0,
                },
                Format10X { op: 14 },
            ],
            tries: vec![
                TryItem {
                    start_addr: 10,
                    insn_count: 8,
                    handler_off: 1,
                },
                TryItem {
                    start_addr: 19,
                    insn_count: 10,
                    handler_off: 4,
                },
                TryItem {
                    start_addr: 30,
                    insn_count: 10,
                    handler_off: 7,
                },
                TryItem {
                    start_addr: 41,
                    insn_count: 10,
                    handler_off: 10,
                },
                TryItem {
                    start_addr: 60,
                    insn_count: 8,
                    handler_off: 13,
                },
                TryItem {
                    start_addr: 68,
                    insn_count: 10,
                    handler_off: 16,
                },
                TryItem {
                    start_addr: 78,
                    insn_count: 10,
                    handler_off: 19,
                },
                TryItem {
                    start_addr: 88,
                    insn_count: 10,
                    handler_off: 22,
                },
                TryItem {
                    start_addr: 98,
                    insn_count: 11,
                    handler_off: 25,
                },
                TryItem {
                    start_addr: 109,
                    insn_count: 11,
                    handler_off: 28,
                },
                TryItem {
                    start_addr: 120,
                    insn_count: 11,
                    handler_off: 31,
                },
                TryItem {
                    start_addr: 131,
                    insn_count: 12,
                    handler_off: 35,
                },
                TryItem {
                    start_addr: 143,
                    insn_count: 12,
                    handler_off: 39,
                },
            ],
            handlers: Some(EncodedCatchHandlerList {
                list: vec![
                    EncodedCatchHandler {
                        handlers: vec![EncodedTypeAddrPair {
                            type_idx: Uleb128(19),
                            addr: Uleb128(18),
                        }],
                        catch_all_addr: None,
                    },
                    EncodedCatchHandler {
                        handlers: vec![EncodedTypeAddrPair {
                            type_idx: Uleb128(19),
                            addr: Uleb128(29),
                        }],
                        catch_all_addr: None,
                    },
                    EncodedCatchHandler {
                        handlers: vec![EncodedTypeAddrPair {
                            type_idx: Uleb128(19),
                            addr: Uleb128(40),
                        }],
                        catch_all_addr: None,
                    },
                    EncodedCatchHandler {
                        handlers: vec![EncodedTypeAddrPair {
                            type_idx: Uleb128(19),
                            addr: Uleb128(51),
                        }],
                        catch_all_addr: None,
                    },
                    EncodedCatchHandler {
                        handlers: vec![EncodedTypeAddrPair {
                            type_idx: Uleb128(19),
                            addr: Uleb128(68),
                        }],
                        catch_all_addr: None,
                    },
                    EncodedCatchHandler {
                        handlers: vec![EncodedTypeAddrPair {
                            type_idx: Uleb128(19),
                            addr: Uleb128(78),
                        }],
                        catch_all_addr: None,
                    },
                    EncodedCatchHandler {
                        handlers: vec![EncodedTypeAddrPair {
                            type_idx: Uleb128(19),
                            addr: Uleb128(88),
                        }],
                        catch_all_addr: None,
                    },
                    EncodedCatchHandler {
                        handlers: vec![EncodedTypeAddrPair {
                            type_idx: Uleb128(19),
                            addr: Uleb128(98),
                        }],
                        catch_all_addr: None,
                    },
                    EncodedCatchHandler {
                        handlers: vec![EncodedTypeAddrPair {
                            type_idx: Uleb128(19),
                            addr: Uleb128(109),
                        }],
                        catch_all_addr: None,
                    },
                    EncodedCatchHandler {
                        handlers: vec![EncodedTypeAddrPair {
                            type_idx: Uleb128(19),
                            addr: Uleb128(120),
                        }],
                        catch_all_addr: None,
                    },
                    EncodedCatchHandler {
                        handlers: vec![EncodedTypeAddrPair {
                            type_idx: Uleb128(19),
                            addr: Uleb128(131),
                        }],
                        catch_all_addr: None,
                    },
                    EncodedCatchHandler {
                        handlers: vec![EncodedTypeAddrPair {
                            type_idx: Uleb128(19),
                            addr: Uleb128(143),
                        }],
                        catch_all_addr: None,
                    },
                    EncodedCatchHandler {
                        handlers: vec![EncodedTypeAddrPair {
                            type_idx: Uleb128(19),
                            addr: Uleb128(155),
                        }],
                        catch_all_addr: None,
                    },
                ],
            }),
        };
        let raw = vec![
            0x06, 0x00, // registers_size
            0x00, 0x00, // ins_size
            0x01, 0x00, // outs_size
            0x0d, 0x00, // tries_size
            0x1b, 0x00, 0x00, 0x00, // debug_info_off
            0x9c, 0x00, 0x00, 0x00, // insns_size
            0x71, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x21, 0x00, 0x23, 0x00, 0x1b, 0x00,
            0x69, 0x00, 0x0a, 0x00, 0x12, 0x11, 0x62, 0x02, 0x0b, 0x00, 0x6e, 0x10, 0x03, 0x00,
            0x02, 0x00, 0x0a, 0x02, 0x4b, 0x01, 0x00, 0x02, 0x12, 0x20, 0x62, 0x02, 0x0a, 0x00,
            0x62, 0x03, 0x0e, 0x00, 0x6e, 0x10, 0x03, 0x00, 0x03, 0x00, 0x0a, 0x03, 0x4b, 0x00,
            0x02, 0x03, 0x12, 0x32, 0x62, 0x03, 0x0a, 0x00, 0x62, 0x04, 0x0d, 0x00, 0x6e, 0x10,
            0x03, 0x00, 0x04, 0x00, 0x0a, 0x04, 0x4b, 0x02, 0x03, 0x04, 0x12, 0x43, 0x62, 0x04,
            0x0a, 0x00, 0x62, 0x05, 0x0c, 0x00, 0x6e, 0x10, 0x03, 0x00, 0x05, 0x00, 0x0a, 0x05,
            0x4b, 0x03, 0x04, 0x05, 0x71, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x04, 0x21, 0x44,
            0x23, 0x44, 0x1b, 0x00, 0x69, 0x04, 0x09, 0x00, 0x62, 0x05, 0x05, 0x00, 0x6e, 0x10,
            0x00, 0x00, 0x05, 0x00, 0x0a, 0x05, 0x4b, 0x01, 0x04, 0x05, 0x62, 0x01, 0x09, 0x00,
            0x62, 0x04, 0x08, 0x00, 0x6e, 0x10, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x04, 0x4b, 0x00,
            0x01, 0x04, 0x62, 0x00, 0x09, 0x00, 0x62, 0x01, 0x07, 0x00, 0x6e, 0x10, 0x00, 0x00,
            0x01, 0x00, 0x0a, 0x01, 0x4b, 0x02, 0x00, 0x01, 0x62, 0x00, 0x09, 0x00, 0x62, 0x01,
            0x01, 0x00, 0x6e, 0x10, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x01, 0x4b, 0x03, 0x00, 0x01,
            0x62, 0x00, 0x09, 0x00, 0x62, 0x01, 0x00, 0x00, 0x6e, 0x10, 0x00, 0x00, 0x01, 0x00,
            0x0a, 0x01, 0x12, 0x52, 0x4b, 0x02, 0x00, 0x01, 0x62, 0x00, 0x09, 0x00, 0x62, 0x01,
            0x02, 0x00, 0x6e, 0x10, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x01, 0x12, 0x62, 0x4b, 0x02,
            0x00, 0x01, 0x62, 0x00, 0x09, 0x00, 0x62, 0x01, 0x03, 0x00, 0x6e, 0x10, 0x00, 0x00,
            0x01, 0x00, 0x0a, 0x01, 0x12, 0x72, 0x4b, 0x02, 0x00, 0x01, 0x62, 0x00, 0x09, 0x00,
            0x62, 0x01, 0x04, 0x00, 0x6e, 0x10, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x01, 0x13, 0x02,
            0x08, 0x00, 0x4b, 0x02, 0x00, 0x01, 0x62, 0x00, 0x09, 0x00, 0x62, 0x01, 0x06, 0x00,
            0x6e, 0x10, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x01, 0x13, 0x02, 0x09, 0x00, 0x4b, 0x02,
            0x00, 0x01, 0x0e, 0x00, // insns
            // no padding: insns_size % 2 == 0
            //try_item 0x00
            0x0a, 0x00, 0x00, 0x00, // start_addr
            0x08, 0x00, // insn_count
            0x01, 0x00, // handler_off
            //try_item 0x01
            0x13, 0x00, 0x00, 0x00, // start_addr
            0x0a, 0x00, // insn_count
            0x04, 0x00, // handler_off
            //try_item 0x02
            0x1e, 0x00, 0x00, 0x00, // start_addr
            0x0a, 0x00, // insn_count
            0x07, 0x00, // handler_off
            //try_item 0x03
            0x29, 0x00, 0x00, 0x00, // start_addr
            0x0a, 0x00, // insn_count
            0x0a, 0x00, // handler_off
            //try_item 0x04
            0x3c, 0x00, 0x00, 0x00, // start_addr
            0x08, 0x00, // insn_count
            0x0d, 0x00, // handler_off
            //try_item 0x05
            0x44, 0x00, 0x00, 0x00, // start_addr
            0x0a, 0x00, // insn_count
            0x10, 0x00, // handler_off
            //try_item 0x06
            0x4e, 0x00, 0x00, 0x00, // start_addr
            0x0a, 0x00, // insn_count
            0x13, 0x00, // handler_off
            //try_item 0x07
            0x58, 0x00, 0x00, 0x00, // start_addr
            0x0a, 0x00, // insn_count
            0x16, 0x00, // handler_off
            //try_item 0x08
            0x62, 0x00, 0x00, 0x00, // start_addr
            0x0b, 0x00, // insn_count
            0x19, 0x00, // handler_off
            //try_item 0x09
            0x6d, 0x00, 0x00, 0x00, // start_addr
            0x0b, 0x00, // insn_count
            0x1c, 0x00, // handler_off
            //try_item 0x0a
            0x78, 0x00, 0x00, 0x00, // start_addr
            0x0b, 0x00, // insn_count
            0x1f, 0x00, // handler_off
            //try_item 0x0b
            0x83, 0x00, 0x00, 0x00, // start_addr
            0x0c, 0x00, // insn_count
            0x23, 0x00, // handler_off
            //try_item 0x0c
            0x8f, 0x00, 0x00, 0x00, // start_addr
            0x0c, 0x00, // insn_count
            0x27, 0x00, // handler_off
            // encoded_catch_handler_list
            0x0d, // size
            0x01, 0x13, 0x12, // encoded_catch_handler 0x00
            0x01, 0x13, 0x1d, // encoded_catch_handler 0x01
            0x01, 0x13, 0x28, // encoded_catch_handler 0x02
            0x01, 0x13, 0x33, // encoded_catch_handler 0x03
            0x01, 0x13, 0x44, // encoded_catch_handler 0x04
            0x01, 0x13, 0x4e, // encoded_catch_handler 0x05
            0x01, 0x13, 0x58, // encoded_catch_handler 0x06
            0x01, 0x13, 0x62, // encoded_catch_handler 0x07
            0x01, 0x13, 0x6d, // encoded_catch_handler 0x08
            0x01, 0x13, 0x78, // encoded_catch_handler 0x09
            0x01, 0x13, 0x83, 0x01, // encoded_catch_handler 0x0a
            0x01, 0x13, 0x8f, 0x01, // encoded_catch_handler 0x0b
            0x01, 0x13, 0x9b, 0x01, // encoded_catch_handler 0x0c
        ];
        assert_eq!(raw, code.serialize_to_vec().unwrap());
        assert_eq!(code, CodeItem::deserialize_from_slice(&raw).unwrap());
        assert_eq!(code.size(), raw.len());
    }
}
