From 2a85d1fdfd6ef348f1a71d3078042f97f2052ef0 Mon Sep 17 00:00:00 2001 From: Nilstrieb Date: Wed, 25 Aug 2021 22:04:32 +0200 Subject: [PATCH] Actually good handling of the Constant Pool indecies The code does not compile yet, because `FromCpInfo<'_>` needs to be implemented for some more types. --- crates/file-info/src/ui.rs | 26 ++- crates/file-parser/src/lib.rs | 221 ++++++++++++------------ crates/file-parser/src/model/cp_info.rs | 93 ++++++---- crates/file-parser/src/model/mod.rs | 1 - 4 files changed, 188 insertions(+), 153 deletions(-) diff --git a/crates/file-info/src/ui.rs b/crates/file-info/src/ui.rs index 779e74a..fc0aead 100644 --- a/crates/file-info/src/ui.rs +++ b/crates/file-info/src/ui.rs @@ -1,4 +1,4 @@ -use file_parser::{ClassFile, ParseErr}; +use file_parser::ClassFile; use std::error::Error; use std::io::Write; @@ -16,7 +16,11 @@ pub fn display_class(mut w: W, class: &ClassFile) -> Result<(), Box "", + Some(class) => &class.name_index.get(cp), + }, if class.interfaces.len() == 0 { "".to_string() } else { @@ -27,22 +31,16 @@ pub fn display_class(mut w: W, class: &ClassFile) -> Result<(), Box, ParseErr>>()? - .iter() .map(|i| i.name_index.get(cp)) - .collect::, ParseErr>>()? + .collect::>() .join(",") ) }, - match class.super_class.get(cp)? { - None => "", - Some(class) => &class.name_index.get(cp)?, - } )?; writeln!(w, " Attributes:")?; for attr in &class.attributes { - writeln!(w, " {}", &attr.attribute_name_index.get(cp)?)?; + writeln!(w, " {}", &attr.attribute_name_index.get(cp))?; } writeln!(w)?; @@ -51,8 +49,8 @@ pub fn display_class(mut w: W, class: &ClassFile) -> Result<(), Box(mut w: W, class: &ClassFile) -> Result<(), Box { pub fn parse_class_file(data: &[u1]) -> Result { let mut data = Data::new(data); - ClassFile::parse(&mut data) + ClassFile::parse(&mut data, &[]) } impl<'a> Data<'a> { @@ -44,8 +45,11 @@ impl<'a> Data<'a> { Ok(((self.u1()? as u2) << 8) | self.u1()? as u2) } - fn cp(&mut self) -> Result> { - Ok(self.u2()?.into()) + /// Parses a u2 and validates it in the constant pool + fn cp<'pool, T: FromCpInfo<'pool>>(&mut self, pool: &'pool [CpInfo]) -> Result> { + let index = self.u2()?; + let _ = T::try_from_cp_info(pool, index)?; + Ok(index.into()) } fn u4(&mut self) -> Result { @@ -84,16 +88,16 @@ impl<'a> Data<'a> { } trait Parse { - fn parse(data: &mut Data) -> Result + fn parse(data: &mut Data, cp: &[CpInfo]) -> Result where Self: Sized; } -fn parse_vec>(len: S, data: &mut Data) -> Result> { +fn parse_vec>(len: S, data: &mut Data, cp: &[CpInfo]) -> Result> { let len = len.into(); let mut vec = Vec::with_capacity(len); for _ in 0..len { - vec.push(T::parse(data)?); + vec.push(T::parse(data, cp)?); } Ok(vec) } @@ -101,7 +105,7 @@ fn parse_vec>(len: S, data: &mut Data) -> Result macro_rules! parse_primitive { ($($value:ident),*) => { $(impl Parse for $value { - fn parse(data: &mut Data) -> Result + fn parse(data: &mut Data, _cp: &[CpInfo]) -> Result where Self: Sized, { @@ -114,25 +118,26 @@ macro_rules! parse_primitive { parse_primitive!(u1, u2, u4); impl Parse for FromPool { - fn parse(data: &mut Data) -> Result { + fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { Ok(data.u2()?.into()) } } impl Parse for ClassFile { - fn parse(data: &mut Data) -> Result { + fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { let magic = data.u4()?; assert_eq!(magic, 0xCAFEBABE); let minor_version = data.u2()?; let major_version = data.u2()?; - let constant_pool = parse_vec(data.u2()? - 1, data)?; // the minus one is important + let constant_pool = parse_vec(data.u2()? - 1, data, cp)?; // the minus one is important + let cp = &constant_pool; let access_flags = data.u2()?; - let this_class = data.cp()?; - let super_class = data.cp()?; - let interfaces = parse_vec(data.u2()?, data)?; - let fields = parse_vec(data.u2()?, data)?; - let methods = parse_vec(data.u2()?, data)?; - let attributes = parse_vec(data.u2()?, data)?; + let this_class = data.cp(cp)?; + let super_class = data.cp(cp)?; + let interfaces = parse_vec(data.u2()?, data, cp)?; + let fields = parse_vec(data.u2()?, data, cp)?; + let methods = parse_vec(data.u2()?, data, cp)?; + let attributes = parse_vec(data.u2()?, data, cp)?; let mut class = Self { magic, @@ -153,41 +158,41 @@ impl Parse for ClassFile { } impl Parse for CpInfo { - fn parse(data: &mut Data) -> Result { + fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { let tag = data.u1()?; Ok(match tag { 7 => Self { tag, inner: CpInfoInner::Class(cp_info::Class { - name_index: data.cp()?, + name_index: data.cp(cp)?, }), }, 9 => Self { tag, inner: CpInfoInner::Fieldref(cp_info::Fieldref { - class_index: data.cp()?, - name_and_type_index: data.cp()?, + class_index: data.cp(cp)?, + name_and_type_index: data.cp(cp)?, }), }, 10 => Self { tag, inner: CpInfoInner::MethodRef(cp_info::MethodRef { - class_index: data.cp()?, - name_and_type_index: data.cp()?, + class_index: data.cp(cp)?, + name_and_type_index: data.cp(cp)?, }), }, 11 => Self { tag, inner: CpInfoInner::InterfaceMethodref(cp_info::InterfaceMethodref { - class_index: data.cp()?, - name_and_type_index: data.cp()?, + class_index: data.cp(cp)?, + name_and_type_index: data.cp(cp)?, }), }, 8 => Self { tag, inner: CpInfoInner::String(cp_info::String { - string_index: data.cp()?, + string_index: data.cp(cp)?, }), }, 3 => Self { @@ -215,14 +220,14 @@ impl Parse for CpInfo { 12 => Self { tag, inner: CpInfoInner::NameAndType(cp_info::NameAndType { - name_index: data.cp()?, - descriptor_index: data.cp()?, + name_index: data.cp(cp)?, + descriptor_index: data.cp(cp)?, }), }, 1 => Self { tag, inner: CpInfoInner::Utf8(cp_info::Utf8 { - bytes: String::from_utf8(parse_vec(data.u2()?, data)?).map_err(|err| { + bytes: String::from_utf8(parse_vec(data.u2()?, data, cp)?).map_err(|err| { ParseErr(format!("Invalid utf8 in CpInfo::Utf8: {}", err)) })?, }), @@ -232,9 +237,9 @@ impl Parse for CpInfo { inner: CpInfoInner::MethodHandle(cp_info::MethodHandle { reference_kind: data.u1()?, reference_index: match data.last_u1()? { - 1..=4 => cp_info::MethodHandleIndex::Field(data.cp()?), - 5..=8 => cp_info::MethodHandleIndex::Method(data.cp()?), - 9 => cp_info::MethodHandleIndex::Interface(data.cp()?), + 1..=4 => cp_info::MethodHandleIndex::Field(data.cp(cp)?), + 5..=8 => cp_info::MethodHandleIndex::Method(data.cp(cp)?), + 9 => cp_info::MethodHandleIndex::Interface(data.cp(cp)?), n => { return Err(ParseErr(format!( "Invalid MethodHandle reference kind: {}", @@ -247,14 +252,14 @@ impl Parse for CpInfo { 16 => Self { tag, inner: CpInfoInner::MethodType(cp_info::MethodType { - descriptor_index: data.cp()?, + descriptor_index: data.cp(cp)?, }), }, 18 => Self { tag, inner: CpInfoInner::InvokeDynamic(cp_info::InvokeDynamic { bootstrap_method_attr_index: data.u2()?, - name_and_type_index: data.cp()?, + name_and_type_index: data.cp(cp)?, }), }, _ => Err(ParseErr(format!("Invalid CPInfo tag: {}", tag)))?, @@ -263,41 +268,41 @@ impl Parse for CpInfo { } impl Parse for FieldInfo { - fn parse(data: &mut Data) -> Result { + fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { Ok(Self { access_flags: data.u2()?, - name_index: data.cp()?, - descriptor_index: data.cp()?, - attributes: parse_vec(data.u2()?, data)?, + name_index: data.cp(cp)?, + descriptor_index: data.cp(cp)?, + attributes: parse_vec(data.u2()?, data, cp)?, }) } } impl Parse for MethodInfo { - fn parse(data: &mut Data) -> Result { + fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { Ok(Self { access_flags: data.u2()?, - name_index: data.cp()?, - descriptor_index: data.cp()?, - attributes: parse_vec(data.u2()?, data)?, + name_index: data.cp(cp)?, + descriptor_index: data.cp(cp)?, + attributes: parse_vec(data.u2()?, data, cp)?, }) } } impl Parse for AttributeInfo { - fn parse(data: &mut Data) -> Result { + fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { Ok(Self { - attribute_name_index: data.cp()?, + attribute_name_index: data.cp(cp)?, attribute_length: data.u4()?, inner: AttributeInfoInner::Unknown { - attribute_content: parse_vec(data.last_u4()? as usize, data)?, + attribute_content: parse_vec(data.last_u4()? as usize, data, cp)?, }, }) } } impl Parse for AttributeCodeException { - fn parse(data: &mut Data) -> Result { + fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { Ok(Self { start_pc: data.last_u2()?, end_pc: data.last_u2()?, @@ -308,19 +313,19 @@ impl Parse for AttributeCodeException { } impl Parse for StackMapFrame { - fn parse(data: &mut Data) -> Result { + fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { let frame_type = data.u1()?; Ok(match frame_type { 0..=63 => Self::SameFrame { frame_type }, 64..=127 => Self::SameLocals1StackItemFrame { frame_type, - stack: VerificationTypeInfo::parse(data)?, + stack: VerificationTypeInfo::parse(data, cp)?, }, 247 => Self::SameLocals1StackItemFrameExtended { frame_type, offset_delta: data.u2()?, - stack: VerificationTypeInfo::parse(data)?, + stack: VerificationTypeInfo::parse(data, cp)?, }, 246..=250 => Self::ChopFrame { frame_type, @@ -333,13 +338,13 @@ impl Parse for StackMapFrame { 252..=254 => Self::AppendFrame { frame_type, offset_delta: data.u2()?, - locals: parse_vec(data.last_u2()?, data)?, + locals: parse_vec(data.last_u2()?, data, cp)?, }, 255 => Self::FullFrame { frame_type, offset_delta: data.u2()?, - locals: parse_vec(data.u2()?, data)?, - stack: parse_vec(data.u2()?, data)?, + locals: parse_vec(data.u2()?, data, cp)?, + stack: parse_vec(data.u2()?, data, cp)?, }, _ => Err(ParseErr(format!( "Invalid StackMapFrame type: {}", @@ -350,7 +355,7 @@ impl Parse for StackMapFrame { } impl Parse for VerificationTypeInfo { - fn parse(data: &mut Data) -> Result { + fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { let tag = data.u1()?; Ok(match tag { 0 => Self::Top { tag }, @@ -377,18 +382,18 @@ impl Parse for VerificationTypeInfo { } impl Parse for AttributeInnerClass { - fn parse(data: &mut Data) -> Result { + fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { Ok(Self { - inner_class_info_index: data.cp()?, - outer_class_info_index: data.cp()?, - inner_class_name_index: data.cp()?, + inner_class_info_index: data.cp(cp)?, + outer_class_info_index: data.cp(cp)?, + inner_class_name_index: data.cp(cp)?, inner_class_access_flags: data.u2()?, }) } } impl Parse for AttributeLineNumber { - fn parse(data: &mut Data) -> Result { + fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { Ok(Self { start_pc: data.u2()?, line_number: data.u2()?, @@ -397,62 +402,64 @@ impl Parse for AttributeLineNumber { } impl Parse for AttributeLocalVariableTable { - fn parse(data: &mut Data) -> Result { + fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { Ok(Self { start_pc: data.u2()?, length: data.u2()?, - name_index: data.cp()?, - descriptor_or_signature_index: data.cp()?, + name_index: data.cp(cp)?, + descriptor_or_signature_index: data.cp(cp)?, index: data.u2()?, }) } } impl Parse for Annotation { - fn parse(data: &mut Data) -> Result { + fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { Ok(Self { - type_index: data.cp()?, + type_index: data.cp(cp)?, num_element_value_pairs: data.u2()?, - element_value_pairs: parse_vec(data.last_u2()?, data)?, + element_value_pairs: parse_vec(data.last_u2()?, data, cp)?, }) } } impl Parse for AnnotationElementValuePair { - fn parse(data: &mut Data) -> Result { + fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { Ok(Self { - element_name_index: data.cp()?, - element_name_name: AnnotationElementValue::parse(data)?, + element_name_index: data.cp(cp)?, + element_name_name: AnnotationElementValue::parse(data, cp)?, }) } } impl Parse for AnnotationElementValue { - fn parse(data: &mut Data) -> Result { + fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { Ok(Self { tag: data.u1()?, - value: AnnotationElementValueValue::parse(data)?, + value: AnnotationElementValueValue::parse(data, cp)?, }) } } impl Parse for AnnotationElementValueValue { - fn parse(data: &mut Data) -> Result { + fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { let tag = data.last_u1()? as char; Ok(match tag { - 'B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'S' | 'Z' | 's' => { - Self::ConstValueIndex { index: data.cp()? } - } - 'e' => Self::EnumConstValue { - type_name_index: data.cp()?, - const_name_index: data.cp()?, + 'B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'S' | 'Z' | 's' => Self::ConstValueIndex { + index: data.u2()?.into(), + }, + 'e' => Self::EnumConstValue { + type_name_index: data.cp(cp)?, + const_name_index: data.cp(cp)?, + }, + 'c' => Self::ClassInfoIndex { + index: data.cp(cp)?, }, - 'c' => Self::ClassInfoIndex { index: data.cp()? }, '@' => Self::AnnotationValue { - annotation: Box::new(Annotation::parse(data)?), + annotation: Box::new(Annotation::parse(data, cp)?), }, '[' => Self::ArrayValue { - values: parse_vec(data.u2()?, data)?, + values: parse_vec(data.u2()?, data, cp)?, }, _ => Err(ParseErr(format!( "Invalid AnnotationElementValueValue tag: {}", @@ -463,18 +470,18 @@ impl Parse for AnnotationElementValueValue { } impl Parse for ParameterAnnotation { - fn parse(data: &mut Data) -> Result { + fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { Ok(Self { - annotations: parse_vec(data.u2()?, data)?, + annotations: parse_vec(data.u2()?, data, cp)?, }) } } impl Parse for BootstrapMethod { - fn parse(data: &mut Data) -> Result { + fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { Ok(Self { - bootstrap_method_ref: data.cp()?, - bootstrap_arguments: parse_vec(data.u2()?, data)?, + bootstrap_method_ref: data.cp(cp)?, + bootstrap_arguments: parse_vec(data.u2()?, data, cp)?, }) } } @@ -535,7 +542,7 @@ impl AttributeInfo { } => (attribute_name_index, attribute_length, attribute_content), _ => unreachable!("Attribute already resolved"), }; - let info = match pool.get((*index) as usize - 1) { + let info = match pool.get((index.inner()) as usize - 1) { Some(CpInfo { inner: CpInfoInner::Utf8(cp_info::Utf8 { bytes, .. }), .. @@ -554,7 +561,7 @@ impl AttributeInfo { attribute_length: u32, name: &str, data: &mut Data, - pool: &[CpInfo], + cp: &[CpInfo], ) -> Result<()> { let _ = std::mem::replace( self, @@ -563,7 +570,7 @@ impl AttributeInfo { attribute_name_index, attribute_length, inner: AttributeInfoInner::ConstantValue { - constantvalue_index: data.cp()?, + constantvalue_index: data.cp(cp)?, }, }, "Code" => { @@ -573,9 +580,9 @@ impl AttributeInfo { inner: AttributeInfoInner::Code { max_stack: data.u2()?, max_locals: data.u2()?, - code: parse_vec(data.u4()? as usize, data)?, - exception_table: parse_vec(data.u2()?, data)?, - attributes: parse_vec(data.u2()?, data)?, + code: parse_vec(data.u4()? as usize, data, cp)?, + exception_table: parse_vec(data.u2()?, data, cp)?, + attributes: parse_vec(data.u2()?, data, cp)?, }, }; if let AttributeInfoInner::Code { @@ -584,7 +591,7 @@ impl AttributeInfo { { attributes .iter_mut() - .map(|attr| attr.resolve_attribute(pool)) + .map(|attr| attr.resolve_attribute(cp)) .collect::>>()?; } else { unreachable!() @@ -596,29 +603,29 @@ impl AttributeInfo { attribute_length, inner: AttributeInfoInner::StackMapTable { number_of_entries: data.u2()?, - entries: parse_vec(data.last_u2()?, data)?, + entries: parse_vec(data.last_u2()?, data, cp)?, }, }, "Exceptions" => Self { attribute_name_index, attribute_length, inner: AttributeInfoInner::Exceptions { - exception_index_table: parse_vec(data.u2()?, data)?, + exception_index_table: parse_vec(data.u2()?, data, cp)?, }, }, "InnerClasses" => Self { attribute_name_index, attribute_length, inner: AttributeInfoInner::InnerClasses { - classes: parse_vec(data.u2()?, data)?, + classes: parse_vec(data.u2()?, data, cp)?, }, }, "EnclosingMethod" => Self { attribute_name_index, attribute_length, inner: AttributeInfoInner::EnclosingMethod { - class_index: data.cp()?, - method_index: data.cp()?, + class_index: data.cp(cp)?, + method_index: data.cp(cp)?, }, }, "Synthetic" => Self { @@ -630,42 +637,42 @@ impl AttributeInfo { attribute_name_index, attribute_length, inner: AttributeInfoInner::Signature { - signature_index: data.cp()?, + signature_index: data.cp(cp)?, }, }, "SourceFile" => Self { attribute_name_index, attribute_length, inner: AttributeInfoInner::SourceFile { - sourcefile_index: data.cp()?, + sourcefile_index: data.cp(cp)?, }, }, "SourceDebugExtension" => Self { attribute_name_index, attribute_length, inner: AttributeInfoInner::SourceDebugExtension { - debug_extension: parse_vec(data.last_u2()?, data)?, + debug_extension: parse_vec(data.last_u2()?, data, cp)?, }, }, "LineNumberTable" => Self { attribute_name_index, attribute_length, inner: AttributeInfoInner::LineNumberTable { - line_number_table: parse_vec(data.u2()?, data)?, + line_number_table: parse_vec(data.u2()?, data, cp)?, }, }, "LocalVariableTable" => Self { attribute_name_index, attribute_length, inner: AttributeInfoInner::LocalVariableTable { - local_variable_table: parse_vec(data.u2()?, data)?, + local_variable_table: parse_vec(data.u2()?, data, cp)?, }, }, "LocalVariableTypeTable" => Self { attribute_name_index, attribute_length, inner: AttributeInfoInner::LocalVariableTypeTable { - local_variable_table: parse_vec(data.u2()?, data)?, + local_variable_table: parse_vec(data.u2()?, data, cp)?, }, }, "Deprecated" => Self { @@ -677,28 +684,28 @@ impl AttributeInfo { attribute_name_index, attribute_length, inner: AttributeInfoInner::RuntimeVisibleAnnotations { - annotations: parse_vec(data.u2()?, data)?, + annotations: parse_vec(data.u2()?, data, cp)?, }, }, "RuntimeInvisibleAnnotations" => Self { attribute_name_index, attribute_length, inner: AttributeInfoInner::RuntimeInvisibleAnnotations { - annotations: parse_vec(data.u2()?, data)?, + annotations: parse_vec(data.u2()?, data, cp)?, }, }, "RuntimeVisibleParameterAnnotations" => Self { attribute_name_index, attribute_length, inner: AttributeInfoInner::RuntimeVisibleParameterAnnotations { - parameter_annotations: parse_vec(data.u1()?, data)?, + parameter_annotations: parse_vec(data.u1()?, data, cp)?, }, }, "RuntimeInvisibleParameterAnnotations" => Self { attribute_name_index, attribute_length, inner: AttributeInfoInner::RuntimeInvisibleParameterAnnotations { - parameter_annotations: parse_vec(data.u1()?, data)?, + parameter_annotations: parse_vec(data.u1()?, data, cp)?, }, }, "AnnotationDefault" => Self { @@ -707,7 +714,7 @@ impl AttributeInfo { inner: AttributeInfoInner::AnnotationDefault { default_value: AnnotationElementValue { tag: data.u1()?, - value: AnnotationElementValueValue::parse(data)?, + value: AnnotationElementValueValue::parse(data, cp)?, }, }, }, @@ -715,7 +722,7 @@ impl AttributeInfo { attribute_name_index, attribute_length, inner: AttributeInfoInner::BootstrapMethods { - bootstrap_methods: parse_vec(data.u2()?, data)?, + bootstrap_methods: parse_vec(data.u2()?, data, cp)?, }, }, name => return Err(ParseErr(format!("Invalid Attribute name: {}", name))), diff --git a/crates/file-parser/src/model/cp_info.rs b/crates/file-parser/src/model/cp_info.rs index b4abf1b..53aa005 100644 --- a/crates/file-parser/src/model/cp_info.rs +++ b/crates/file-parser/src/model/cp_info.rs @@ -1,8 +1,12 @@ use super::*; +use crate::ParseErr; /// /// An index into the constant pool of the class /// `T` -> What type the target value is supposed to be. Create an enum if multiple values can be there +/// +/// The value this is pointing at must *always* be a entry of the correct type T +/// Type checking is done at parse time, so that the value can be get with minimal overhead #[repr(transparent)] #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct FromPool { @@ -13,14 +17,6 @@ pub struct FromPool { // could probably be derived if I chose a better marker impl Copy for FromPool {} -impl std::ops::Deref for FromPool { - type Target = u2; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - impl From for FromPool { fn from(n: u2) -> Self { Self { @@ -30,40 +26,63 @@ impl From for FromPool { } } -pub trait FromCpInfo<'a> { - type Target; - fn from_cp_info(info: &'a CpInfo) -> Result; -} - -impl<'a, T> FromCpInfo<'a> for Option -where - T: FromCpInfo<'a, Target = &'a T>, - T: 'a, -{ - type Target = Option<&'a T>; - - fn from_cp_info(info: &'a CpInfo) -> Result { - Ok(T::from_cp_info(info).ok()) +impl FromPool { + #[inline] + pub const fn inner(&self) -> u2 { + self.inner } } -impl<'a, T> FromPool +impl<'pool, T> FromPool where - T: FromCpInfo<'a>, + T: FromCpInfo<'pool>, { - pub fn get(&self, pool: &'a [CpInfo]) -> Result { + #[inline] + pub fn get(&self, pool: &'pool [CpInfo]) -> T::Target { T::from_cp_info(&pool[self.inner as usize - 1]) } } +impl<'pool, T> FromPool> +where + T: FromCpInfo<'pool>, +{ + #[inline] + pub fn maybe_get(&self, pool: &'pool [CpInfo]) -> Option { + if self.inner == 0 { + None + } else { + Some(T::from_cp_info(&pool[self.inner as usize - 1])) + } + } +} + +pub trait FromCpInfo<'pool> { + type Target; + fn from_cp_info(info: &'pool CpInfo) -> Self::Target; + fn try_from_cp_info(info: &'pool [CpInfo], index: u2) -> Result; +} + macro_rules! impl_try_from_cp { ($($name:ident),*) => { $( - impl<'a> FromCpInfo<'a> for $name { - type Target = &'a Self; + impl<'pool> FromCpInfo<'pool> for $name { + type Target = &'pool Self; - fn from_cp_info(info: &'a CpInfo) -> Result { + #[inline] + fn from_cp_info(info: &'pool CpInfo) -> Self::Target { match &info.inner { + CpInfoInner::$name(class) => class, + _kind => unreachable!(), + } + } + + #[inline] + fn try_from_cp_info(info: &'pool [CpInfo], index: u2) -> Result { + if index == 0 { + return Err(ParseErr("Index must not be 0".to_string())); + } + match &info[index as usize - 1].inner { CpInfoInner::$name(class) => Ok(class), kind => Err(ParseErr(format!( concat!("Expected '", stringify!($name), "', found '{:?}'"), @@ -206,11 +225,23 @@ impl_try_from_cp!( ); // custom implementations -impl<'a> FromCpInfo<'a> for Utf8 { - type Target = &'a str; +impl<'pool> FromCpInfo<'pool> for Utf8 { + type Target = &'pool str; - fn from_cp_info(info: &'a CpInfo) -> Result { + #[inline] + fn from_cp_info(info: &'pool CpInfo) -> Self::Target { match &info.inner { + CpInfoInner::Utf8(class) => &class.bytes, + _ => unreachable!(), + } + } + + #[inline] + fn try_from_cp_info(info: &'pool [CpInfo], index: u2) -> Result { + if index == 0 { + return Err(ParseErr("Index must not be 0".to_string())); + } + match &info[index as usize - 1].inner { CpInfoInner::Utf8(class) => Ok(&class.bytes), kind => Err(ParseErr(format!( concat!("Expected '", stringify!($name), "', found '{:?}'"), diff --git a/crates/file-parser/src/model/mod.rs b/crates/file-parser/src/model/mod.rs index e17d4f0..7e935f5 100644 --- a/crates/file-parser/src/model/mod.rs +++ b/crates/file-parser/src/model/mod.rs @@ -4,7 +4,6 @@ //! [The .class specs](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html) #![allow(dead_code)] -use crate::ParseErr; use std::marker::PhantomData; /// All of the Constants in the Constant Pool