cfsp 1.0.1

A JVM Bytecode Manipulation Framework inspired by ASM.
Documentation
use std::cell::RefCell;
use std::io::Read;

use byteorder::{BigEndian, ReadBytesExt};

use crate::node::constant;
use crate::node::constant::{
    Class, Constant, ConstantPool, Double, Dynamic, FieldRef, Float, Integer, InterfaceMethodRef,
    InvokeDynamic, Long, MethodHandle, MethodRef, MethodType, Module, NameAndType, Package, Utf8,
};
use crate::parse::error::{ParseError, ParseResult};

pub(super) fn constant_pool<R: Read>(input: &mut R) -> ParseResult<(u16, ConstantPool)> {
    let len = input.read_u16::<BigEndian>()?;
    let mut constant_pool = ConstantPool::with_capacity(len);
    let mut constant_counter = 0;

    while constant_counter < len - 1 {
        let constant = constant(input)?;

        if constant.occupies_2_slots() {
            constant_counter += 2;
        } else {
            constant_counter += 1;
        }

        constant_pool.add(constant);
    }

    Ok((len, constant_pool))
}

fn constant<R: Read>(input: &mut R) -> ParseResult<Constant> {
    let tag = input.read_u8()?;

    let constant = match tag {
        1 => {
            let length = input.read_u16::<BigEndian>()?;
            let mut bytes = vec![0; length as usize];

            input.read_exact(&mut bytes)?;

            Constant::Utf8(Utf8 {
                length,
                bytes,
                string: RefCell::new(None),
            })
        }
        3 => {
            let mut bytes = [0; 4];

            input.read_exact(&mut bytes)?;

            Constant::Integer(Integer { bytes })
        }
        4 => {
            let mut bytes = [0; 4];

            input.read_exact(&mut bytes)?;

            Constant::Float(Float { bytes })
        }
        5 => {
            let mut high_bytes = [0; 4];
            let mut low_bytes = [0; 4];

            input.read_exact(&mut high_bytes)?;
            input.read_exact(&mut low_bytes)?;

            Constant::Long(Long {
                high_bytes,
                low_bytes,
            })
        }
        6 => {
            let mut high_bytes = [0; 4];
            let mut low_bytes = [0; 4];

            input.read_exact(&mut high_bytes)?;
            input.read_exact(&mut low_bytes)?;

            Constant::Double(Double {
                high_bytes,
                low_bytes,
            })
        }
        7 => {
            let name_index = input.read_u16::<BigEndian>()?;

            Constant::Class(Class { name_index })
        }
        8 => {
            let string_index = input.read_u16::<BigEndian>()?;

            Constant::String(constant::String { string_index })
        }
        9 => {
            let class_index = input.read_u16::<BigEndian>()?;
            let name_and_type_index = input.read_u16::<BigEndian>()?;

            Constant::FieldRef(FieldRef {
                class_index,
                name_and_type_index,
            })
        }
        10 => {
            let class_index = input.read_u16::<BigEndian>()?;
            let name_and_type_index = input.read_u16::<BigEndian>()?;

            Constant::MethodRef(MethodRef {
                class_index,
                name_and_type_index,
            })
        }
        11 => {
            let class_index = input.read_u16::<BigEndian>()?;
            let name_and_type_index = input.read_u16::<BigEndian>()?;

            Constant::InterfaceMethodRef(InterfaceMethodRef {
                class_index,
                name_and_type_index,
            })
        }
        12 => {
            let name_index = input.read_u16::<BigEndian>()?;
            let type_index = input.read_u16::<BigEndian>()?;

            Constant::NameAndType(NameAndType {
                name_index,
                type_index,
            })
        }
        15 => {
            let reference_kind = input.read_u8()?;
            let reference_index = input.read_u16::<BigEndian>()?;

            Constant::MethodHandle(MethodHandle {
                reference_kind,
                reference_index,
            })
        }
        16 => {
            let descriptor_index = input.read_u16::<BigEndian>()?;

            Constant::MethodType(MethodType { descriptor_index })
        }
        17 => {
            let bootstrap_method_attr_index = input.read_u16::<BigEndian>()?;
            let name_and_type_index = input.read_u16::<BigEndian>()?;

            Constant::Dynamic(Dynamic {
                bootstrap_method_attr_index,
                name_and_type_index,
            })
        }
        18 => {
            let bootstrap_method_attr_index = input.read_u16::<BigEndian>()?;
            let name_and_type_index = input.read_u16::<BigEndian>()?;

            Constant::InvokeDynamic(InvokeDynamic {
                bootstrap_method_attr_index,
                name_and_type_index,
            })
        }
        19 => {
            let name_index = input.read_u16::<BigEndian>()?;

            Constant::Module(Module { name_index })
        }
        20 => {
            let name_index = input.read_u16::<BigEndian>()?;

            Constant::Package(Package { name_index })
        }
        _ => {
            return Err(ParseError::MatchOutOfBoundUsize(
                "constant tag",
                vec!["1..=20"],
                tag as usize,
            ))
        }
    };

    Ok(constant)
}