java_asm 0.1.3

Java bytecode reader & writer in rust
Documentation
use crate::constants::Constants;
use crate::err::{AsmErr, AsmResult};
use crate::impls::node::r::node_reader::{ClassNodeContext, ConstPool};
use crate::impls::ToStringRef;
use crate::jvms::element::Const;
use crate::node::values::{ConstValue, Handle};
use crate::*;
use std::ops::Deref;
use std::sync::Arc;

impl ComputableSizedVecOwner<ConstValue> for ConstPool {
    fn computable_vec(&self) -> &ComputableSizedVec<ConstValue> {
        &self.pool
    }

    fn compute(&self, index: usize) -> AsmResult<ConstValue> {
        self.read_const(index as u16)
    }
}

macro_rules! read_const {
    {
        $($name:ident -> $ret:ty {
            $variant:ident($($arg:ident),*)
        })*
    } => {
        $(pub fn $name(&self, index: u16) -> AsmResult<$ret> {
            let constant = self.get_res(index)?;
            let ConstValue::$variant( $($arg),* ) = constant.as_ref() else {
                return AsmErr::IllegalFormat(
                    format!("cannot read const value from constant pool, cp_index: {}, constant: {:?}, required: ConstValue::{}",
                        index, constant, stringify!($variant))
                ).e();
            };
            Ok(($(Arc::clone($arg)),*))
        })*
    };
}

macro_rules! read_const_curly {
    {
        $($name:ident -> $ret:ty {
            $variant:ident { $($arg:ident),* }
        })*
    } => {
        $(pub fn $name(&self, index: u16) -> AsmResult<$ret> {
            let constant = self.get_res(index)?;
            let ConstValue::$variant{ $($arg),* } = constant.as_ref() else {
                return AsmErr::IllegalFormat(
                    format!("cannot read const value from constant pool, cp_index: {}, constant: {:?}, required: ConstValue::{}",
                        index, constant, stringify!($variant))
                ).e();
            };
            Ok(($($arg.clone()),*))
        })*
    };
}

/// impls for const reads
impl ConstPool {
    pub fn name(&self) -> AsmResult<StrRef> {
        self.read_class_info(self.jvms_file.this_class)
    }

    read_const! {
        read_class_info -> InternalNameRef { Class(name) }
        read_utf8 -> StrRef { String(s) }
        read_module -> StrRef { Module(s) }
        read_package -> StrRef { Package(s) }
    }

    read_const_curly! {
        read_name_and_type -> (StrRef, DescriptorRef) {
            NameAndType { name, desc }
        }
        read_member -> (StrRef, StrRef, DescriptorRef) {
            Member { class, name, desc }
        }
        read_dynamic -> (u16, StrRef, DescriptorRef) {
            Dynamic { bootstrap_method_attr_index, name, desc }
        }
    }

    #[inline]
    pub fn read_class_info_or_default(&self, index: u16) -> StrRef {
        self.read_class_info(index)
            .unwrap_or_else(|_| Constants::OBJECT_INTERNAL_NAME.to_ref())
    }

    #[inline]
    pub fn get_res(&self, index: u16) -> AsmResult<Arc<ConstValue>> {
        self.get_or_compute(index as usize)
    }

    fn read_const(&self, index: u16) -> AsmResult<ConstValue> {
        let raw_const = self.jvms_file.constant_pool[index as usize].info.clone();
        let const_value = match raw_const {
            Const::Invalid => { ConstValue::Invalid }
            Const::Class { name_index } => {
                ConstValue::Class(self.read_utf8(name_index)?)
            }
            Const::Field { class_index, name_and_type_index }
            | Const::Method { class_index, name_and_type_index }
            | Const::InterfaceMethod { class_index, name_and_type_index } => {
                let class = self.read_class_info(class_index)?;
                let (name, desc) = self.read_name_and_type(name_and_type_index)?;
                ConstValue::Member { class, name, desc }
            }
            Const::String { string_index } => {
                ConstValue::String(self.read_utf8(string_index)?)
            }
            Const::Integer { bytes } => ConstValue::Integer(bytes as i32),
            Const::Float { bytes } => ConstValue::Float(f32::from_bits(bytes)),
            Const::Long { high_bytes, low_bytes } => {
                let value = ((high_bytes as u64) << 32) | (low_bytes as u64);
                ConstValue::Long(value as i64)
            }
            Const::Double { high_bytes, low_bytes } => {
                let value = ((high_bytes as u64) << 32) | (low_bytes as u64);
                ConstValue::Double(f64::from_bits(value))
            }
            Const::NameAndType { name_index, descriptor_index } => {
                let name = self.read_utf8(name_index)?;
                let desc = self.read_utf8(descriptor_index)?;
                ConstValue::NameAndType { name, desc }
            }
            Const::Utf8 { bytes, .. } => {
                ConstValue::String(mutf8_to_string(&bytes)?)
            }
            Const::MethodHandle { reference_kind, reference_index } => {
                let (owner, name, desc) = self.read_member(reference_index)?;
                let handle = Handle { reference_kind, owner, name, desc };
                ConstValue::MethodHandle(handle)
            }
            Const::MethodType { descriptor_index } => {
                ConstValue::MethodType(self.read_utf8(descriptor_index)?)
            }
            Const::Dynamic { bootstrap_method_attr_index, name_and_type_index }
            | Const::InvokeDynamic { bootstrap_method_attr_index, name_and_type_index } => {
                let (name, desc) = self.read_name_and_type(name_and_type_index)?;
                ConstValue::Dynamic { bootstrap_method_attr_index, name, desc }
            }
            Const::Module { name_index } => ConstValue::Module(self.read_utf8(name_index)?),
            Const::Package { name_index } => ConstValue::Package(self.read_utf8(name_index)?),
        };
        Ok(const_value)
    }
}

impl Deref for ClassNodeContext {
    type Target = ConstPool;
    #[inline]
    fn deref(&self) -> &ConstPool { &self.cp }
}