Skip to content

Commit 9fdfc28

Browse files
committed
refactor attributes to a concrete attribute set which can be filtered
and reused across class/method/etc
1 parent ab5af77 commit 9fdfc28

File tree

8 files changed

+76
-63
lines changed

8 files changed

+76
-63
lines changed

src/attribute.rs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
use std::io;
1+
use std::{convert::TryInto, io};
22

33
use bytecode::*;
4+
5+
use crate::ClassFile;
46
use {parsing, ConstantPoolIndex};
57

68
const EXCEPTION_ENTRY_LENGTH: usize = 8;
@@ -11,13 +13,46 @@ pub struct Attribute {
1113
pub info: Vec<u8>,
1214
}
1315

16+
#[derive(Debug, Eq, PartialEq, Clone)]
17+
pub struct AttributeSet {
18+
pub attributes: Vec<Attribute>,
19+
}
20+
21+
impl AttributeSet {
22+
/// Find an attribute with the specified name
23+
pub fn find_attribute<T: AsRef<str>>(
24+
&self,
25+
class_file: &ClassFile,
26+
attribute_name: T,
27+
) -> Option<&Attribute> {
28+
// we can index this more efficiently
29+
self.attributes.iter().find(|attr| {
30+
class_file.get_constant_utf8(attr.attribute_name_index) == attribute_name.as_ref()
31+
})
32+
}
33+
34+
pub fn get_signature(&self, class_file: &ClassFile) -> Option<String> {
35+
self.find_attribute(class_file, "Signature").map(|attr| {
36+
// why is this such a PITA
37+
let boxed_slice = attr.info.clone().into_boxed_slice();
38+
let boxed_array: Box<[u8; 2]> = match boxed_slice.try_into() {
39+
Ok(ba) => ba,
40+
Err(o) => panic!("Expected a Vec of length {} but it was {}", 2, o.len()),
41+
};
42+
let index = u16::from_be_bytes(*boxed_array);
43+
44+
class_file.get_constant_utf8(index as usize).to_string()
45+
})
46+
}
47+
}
48+
1449
#[derive(Debug, PartialEq)]
1550
pub struct Code {
1651
pub max_stack: u16,
1752
pub max_locals: u16,
1853
pub code: Vec<(usize, Bytecode)>,
1954
pub exception_table: Vec<ExceptionTableEntry>,
20-
pub attributes: Vec<Attribute>,
55+
pub attributes: AttributeSet,
2156
}
2257

2358
impl Code {

src/class_file.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub struct ClassFile {
2828
pub interfaces: Vec<ConstantPoolIndex>,
2929
pub fields: Vec<Field>,
3030
pub methods: Vec<Method>,
31-
pub attributes: Vec<Attribute>,
31+
pub attributes: AttributeSet,
3232
}
3333

3434
impl ClassFile {
@@ -100,7 +100,7 @@ impl ClassFile {
100100
pub fn get_source_file_name(&self) -> Option<&str> {
101101
use ConstantPoolEntry::*;
102102

103-
for attr in self.attributes.iter() {
103+
for attr in self.attributes.attributes.iter() {
104104
let name_constant = self.get_constant(attr.attribute_name_index as usize);
105105

106106
if let ConstantUtf8 { ref string } = *name_constant.deref() {

src/field.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ pub struct Field {
99
pub access_flags: HashSet<FieldAccess>,
1010
pub name_index: ConstantPoolIndex,
1111
pub descriptor_index: ConstantPoolIndex,
12-
pub attributes: Vec<Attribute>,
12+
pub attributes: AttributeSet,
1313
}

src/main.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ use std::io;
88
use std::ops::Deref;
99
use std::path::PathBuf;
1010

11-
use jvm_class_file_parser::{
12-
Attribute, Bytecode, ClassAccess, ClassFile, ConstantPoolEntry, ExceptionTableEntry, Method,
13-
};
11+
use jvm_class_file_parser::{Attribute, AttributeSet, Bytecode, ClassAccess, ClassFile, ConstantPoolEntry, ExceptionTableEntry, Method};
1412

1513
const CONSTRUCTOR_NAME: &str = "<init>";
1614

@@ -86,12 +84,12 @@ fn print_access_flags(access_flags: &HashSet<ClassAccess>) -> String {
8684

8785
fn print_attributes(
8886
class_file: &ClassFile,
89-
attributes: &Vec<Attribute>,
87+
attributes: &AttributeSet,
9088
prefix: &'static str,
9189
) -> String {
9290
let mut output = format!("{}Attributes:\n", prefix);
9391

94-
attributes.iter().for_each(|attr| {
92+
attributes.attributes.iter().for_each(|attr| {
9593
output.push_str(format!("{} {}\n", prefix, format_attribute(class_file, attr)).as_ref());
9694
});
9795

@@ -311,7 +309,7 @@ fn print_method(class_file: &ClassFile, method: &Method, print_code: bool) -> St
311309
)
312310
.as_ref();
313311

314-
if let Some(sig) = method.get_signature(class_file) {
312+
if let Some(sig) = method.attributes.get_signature(class_file) {
315313
output = output + format!("{}signature: {}\n", PREFIX, sig).as_ref();
316314
}
317315

src/method.rs

Lines changed: 5 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{convert::TryInto, io};
1+
use std::io;
22

33
use attribute::*;
44
use class_file::ClassFile;
@@ -25,43 +25,14 @@ pub struct Method {
2525
pub access_flags: u16,
2626
pub name_index: ConstantPoolIndex,
2727
pub descriptor_index: ConstantPoolIndex,
28-
pub attributes: Vec<Attribute>,
28+
pub attributes: AttributeSet,
2929
}
3030

3131
impl Method {
32-
/// Find an attribute with the specified name
33-
fn find_attribute<T: AsRef<str>>(
34-
&self,
35-
class_file: &ClassFile,
36-
attribute_name: T,
37-
) -> Option<&Attribute> {
38-
// we can index this more efficiently
39-
self.attributes.iter().find(|attr| {
40-
class_file.get_constant_utf8(attr.attribute_name_index) == attribute_name.as_ref()
41-
})
42-
}
43-
4432
pub fn get_code(&self, class_file: &ClassFile) -> io::Result<Option<Code>> {
45-
for attr in self.attributes.iter() {
46-
if class_file.get_constant_utf8(attr.attribute_name_index) == "Code" {
47-
return Ok(Some(Code::from_bytes(&attr.info)?));
48-
}
33+
match self.attributes.find_attribute(class_file, "Code") {
34+
Some(attr) => Ok(Some(Code::from_bytes(&attr.info)?)),
35+
_ => Ok(None),
4936
}
50-
51-
Ok(None)
52-
}
53-
54-
pub fn get_signature(&self, class_file: &ClassFile) -> Option<String> {
55-
self.find_attribute(class_file, "Signature").map(|attr| {
56-
// why is this such a PITA
57-
let boxed_slice = attr.info.clone().into_boxed_slice();
58-
let boxed_array: Box<[u8; 2]> = match boxed_slice.try_into() {
59-
Ok(ba) => ba,
60-
Err(o) => panic!("Expected a Vec of length {} but it was {}", 2, o.len()),
61-
};
62-
let index = u16::from_be_bytes(*boxed_array);
63-
64-
class_file.get_constant_utf8(index as usize).to_string()
65-
})
6637
}
6738
}

src/parsing.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ fn read_method<R: Read>(file: &mut R) -> io::Result<Method> {
354354
})
355355
}
356356

357-
pub fn read_attributes<R: Read>(file: &mut R) -> io::Result<Vec<Attribute>> {
357+
pub fn read_attributes<R: Read>(file: &mut R) -> io::Result<AttributeSet> {
358358
let attributes_count = read_u16(file)?;
359359

360360
let mut attributes = Vec::<Attribute>::new();
@@ -365,7 +365,9 @@ pub fn read_attributes<R: Read>(file: &mut R) -> io::Result<Vec<Attribute>> {
365365
attributes.push(entry);
366366
}
367367

368-
Ok(attributes)
368+
Ok(AttributeSet {
369+
attributes
370+
})
369371
}
370372

371373
fn read_attribute<R: Read>(file: &mut R) -> io::Result<Attribute> {

src/writing.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub fn write_class_file<W: Write>(file: &mut W, class_file: &ClassFile) -> io::R
3030
write_u16(file, 0)?; // interfaces
3131
write_u16(file, 0)?; // fields
3232
write_methods(file, &class_file.methods)?;
33-
write_attributes(file, &class_file.attributes)?;
33+
write_attributes(file, &class_file.attributes.attributes)?;
3434

3535
Ok(())
3636
}
@@ -155,7 +155,7 @@ fn write_method<W: Write>(file: &mut W, method: &Method) -> io::Result<()> {
155155
write_cp_index(file, method.name_index)?;
156156
write_cp_index(file, method.descriptor_index)?;
157157

158-
write_attributes(file, &method.attributes)?;
158+
write_attributes(file, &method.attributes.attributes)?;
159159

160160
Ok(())
161161
}

tests/parse_classes.rs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use std::collections::HashSet;
44
use std::fs::File;
55

66
use jvm_class_file_parser::{
7-
Attribute, Bytecode, ClassAccess, ClassFile, Code, ConstantPoolEntry, Field, FieldAccess,
7+
Attribute, AttributeSet, Bytecode, ClassAccess, ClassFile, Code, ConstantPoolEntry, Field,
8+
FieldAccess,
89
};
910
use std::ops::Deref;
1011

@@ -35,10 +36,12 @@ fn parse_class_dummy() {
3536
max_locals: 1,
3637
code: vec![(0, Aload_0), (1, Invokespecial(1)), (4, Return),],
3738
exception_table: vec![],
38-
attributes: vec![Attribute {
39-
attribute_name_index: 7,
40-
info: vec![0, 1, 0, 0, 0, 1],
41-
}],
39+
attributes: AttributeSet {
40+
attributes: vec![Attribute {
41+
attribute_name_index: 7,
42+
info: vec![0, 1, 0, 0, 0, 1],
43+
}]
44+
},
4245
}),
4346
code.unwrap()
4447
);
@@ -69,7 +72,7 @@ fn parse_class_intbox() {
6972
access_flags: field_access_flags,
7073
name_index: 5,
7174
descriptor_index: 6,
72-
attributes: vec![],
75+
attributes: AttributeSet { attributes: vec![] },
7376
},
7477
*field
7578
);
@@ -93,10 +96,12 @@ fn parse_class_intbox() {
9396
(9, Return),
9497
],
9598
exception_table: vec![],
96-
attributes: vec![Attribute {
97-
attribute_name_index: 10,
98-
info: vec![0, 3, 0, 0, 0, 4, 0, 4, 0, 5, 0, 9, 0, 6],
99-
}],
99+
attributes: AttributeSet {
100+
attributes: vec![Attribute {
101+
attribute_name_index: 10,
102+
info: vec![0, 3, 0, 0, 0, 4, 0, 4, 0, 5, 0, 9, 0, 6],
103+
}]
104+
},
100105
}),
101106
constructor_code.unwrap()
102107
);
@@ -110,10 +115,12 @@ fn parse_class_intbox() {
110115
max_locals: 1,
111116
code: vec![(0, Aload_0), (1, Getfield(2)), (4, Ireturn),],
112117
exception_table: vec![],
113-
attributes: vec![Attribute {
114-
attribute_name_index: 10,
115-
info: vec![0, 1, 0, 0, 0, 9],
116-
}],
118+
attributes: AttributeSet {
119+
attributes: vec![Attribute {
120+
attribute_name_index: 10,
121+
info: vec![0, 1, 0, 0, 0, 9],
122+
}]
123+
},
117124
}),
118125
get_value_code.unwrap()
119126
);

0 commit comments

Comments
 (0)