1use std::hash::{Hash, Hasher};
2use std::collections::HashMap;
3use std::cmp::{Eq, PartialEq};
4use std::rc::Rc;
5use std::slice::Iter;
6
7use result::*;
8
9#[derive(Debug, Clone)]
11pub enum Item {
12 UTF8(String),
15 Integer(i32),
17 Float(f32),
19 Long(i64),
22 Double(f64),
25 Class(u16),
28 String(u16),
30 FieldRef {
32 class: u16,
35 name_and_type: u16,
37 },
38 MethodRef {
40 class: u16,
43 name_and_type: u16,
45 },
46 InterfaceMethodRef {
48 class: u16,
51 name_and_type: u16,
53 },
54 NameAndType {
56 name: u16,
59 desc: u16,
62 },
63 MethodHandle {
65 kind: ReferenceKind,
67 index: u16,
79 },
80 MethodType(u16),
84 InvokeDynamic {
87 bootstrap_method: u16,
89 name_and_type: u16,
91 },
92 Module(u16),
96 Package(u16),
101}
102
103impl Item {
104 fn is_double(&self) -> bool {
106 match *self {
107 Item::Long(_) | Item::Double(_) => true,
108 _ => false,
109 }
110 }
111}
112
113impl Hash for Item {
120 fn hash<H: Hasher>(&self, state: &mut H) {
121 match *self {
122 Item::UTF8(ref s) => {
123 state.write_u8(1);
124 s.hash(state);
125 }
126 Item::Integer(i) => {
127 state.write_u8(3);
128 i.hash(state);
129 }
130 Item::Float(f) => {
131 state.write_u8(4);
132 f.to_bits().hash(state);
133 }
134 Item::Long(i) => {
135 state.write_u8(5);
136 i.hash(state);
137 }
138 Item::Double(f) => {
139 state.write_u8(6);
140 f.to_bits().hash(state);
141 }
142 Item::Class(ptr) => {
143 state.write_u8(7);
144 ptr.hash(state);
145 }
146 Item::String(ptr) => {
147 state.write_u8(8);
148 ptr.hash(state);
149 }
150 Item::FieldRef {
151 class,
152 name_and_type,
153 } => {
154 state.write_u8(9);
155 class.hash(state);
156 name_and_type.hash(state);
157 }
158 Item::MethodRef {
159 class,
160 name_and_type,
161 } => {
162 state.write_u8(10);
163 class.hash(state);
164 name_and_type.hash(state);
165 }
166 Item::InterfaceMethodRef {
167 class,
168 name_and_type,
169 } => {
170 state.write_u8(11);
171 class.hash(state);
172 name_and_type.hash(state);
173 }
174 Item::NameAndType { name, desc } => {
175 state.write_u8(12);
176 name.hash(state);
177 desc.hash(state);
178 }
179 Item::MethodHandle { ref kind, index } => {
180 state.write_u8(15);
181 kind.hash(state);
182 index.hash(state);
183 }
184 Item::MethodType(ptr) => {
185 state.write_u8(16);
186 ptr.hash(state);
187 }
188 Item::InvokeDynamic {
189 bootstrap_method,
190 name_and_type,
191 } => {
192 state.write_u8(18);
193 bootstrap_method.hash(state);
194 name_and_type.hash(state);
195 }
196 Item::Module(ptr) => {
197 state.write_u8(19);
198 ptr.hash(state);
199 }
200 Item::Package(ptr) => {
201 state.write_u8(20);
202 ptr.hash(state);
203 }
204 }
205 }
206}
207
208impl PartialEq for Item {
209 fn eq(&self, other: &Item) -> bool {
210 match (self, other) {
211 (&Item::UTF8(ref str1), &Item::UTF8(ref str2)) => *str1 == *str2,
212 (&Item::Integer(i1), &Item::Integer(i2)) => i1 == i2,
213 (&Item::Float(f1), &Item::Float(f2)) => f1.to_bits() == f2.to_bits(),
214 (&Item::Long(i1), &Item::Long(i2)) => i1 == i2,
215 (&Item::Double(f1), &Item::Double(f2)) => f1.to_bits() == f2.to_bits(),
216 (&Item::Class(i1), &Item::Class(i2)) | (&Item::String(i1), &Item::String(i2)) => {
217 i1 == i2
218 }
219 (
220 &Item::FieldRef {
221 class: class1,
222 name_and_type: nat1,
223 },
224 &Item::FieldRef {
225 class: class2,
226 name_and_type: nat2,
227 },
228 )
229 | (
230 &Item::MethodRef {
231 class: class1,
232 name_and_type: nat1,
233 },
234 &Item::MethodRef {
235 class: class2,
236 name_and_type: nat2,
237 },
238 )
239 | (
240 &Item::InterfaceMethodRef {
241 class: class1,
242 name_and_type: nat1,
243 },
244 &Item::InterfaceMethodRef {
245 class: class2,
246 name_and_type: nat2,
247 },
248 ) => class1 == class2 && nat1 == nat2,
249 (
250 &Item::NameAndType {
251 name: name1,
252 desc: desc1,
253 },
254 &Item::NameAndType {
255 name: name2,
256 desc: desc2,
257 },
258 ) => name1 == name2 && desc1 == desc2,
259 (
260 &Item::MethodHandle {
261 kind: ref kind1,
262 index: index1,
263 },
264 &Item::MethodHandle {
265 kind: ref kind2,
266 index: index2,
267 },
268 ) => kind1 == kind2 && index1 == index2,
269 (
270 &Item::InvokeDynamic {
271 bootstrap_method: bma1,
272 name_and_type: nat1,
273 },
274 &Item::InvokeDynamic {
275 bootstrap_method: bma2,
276 name_and_type: nat2,
277 },
278 ) => bma1 == bma2 && nat1 == nat2,
279 (&Item::Package(index1), &Item::Package(index2))
280 | (&Item::Module(index1), &Item::Module(index2))
281 | (&Item::MethodType(index1), &Item::MethodType(index2)) => index1 == index2,
282
283 _ => false,
284 }
285 }
286}
287
288impl Eq for Item {}
289
290#[derive(Eq, PartialEq, Hash, Debug, Clone)]
291pub enum ReferenceKind {
292 GetField,
293 GetStatic,
294 PutField,
295 PutStatic,
296 InvokeVirtual,
297 InvokeStatic,
298 InvokeSpecial,
299 NewInvokeSpecial,
300 InvokeInterface,
301}
302
303#[derive(Default)]
313pub struct Pool {
314 length: u16,
315 by_index: Vec<Option<Rc<Item>>>,
316 by_entry: HashMap<Rc<Item>, u16>,
317}
318
319impl Pool {
320 pub fn new() -> Self {
321 Pool {
322 length: 1,
323 by_index: Vec::new(),
324 by_entry: HashMap::new(),
325 }
326 }
327
328 pub fn with_capacity(cap: u16) -> Self {
329 Pool {
330 length: 1,
331 by_index: Vec::with_capacity(cap as usize),
332 by_entry: HashMap::with_capacity(cap as usize),
333 }
334 }
335
336 #[inline]
338 pub fn len(&self) -> u16 {
339 self.length
340 }
341
342 #[inline]
344 pub fn is_empty(&self) -> bool {
345 self.len() == 1
346 }
347
348 pub fn get(&self, index: u16) -> Result<&Item> {
351 if index != 0 && index <= self.len() {
353 if let Some(ref item) = self.by_index[index as usize - 1] {
354 return Ok(item);
355 }
356 }
357
358 Err(Error::InvalidCPItem(index))
359 }
360
361 pub fn get_utf8(&self, index: u16) -> Result<String> {
363 if let Item::UTF8(ref s) = *self.get(index)? {
364 Ok(s.clone())
365 } else {
366 Err(Error::InvalidCPItem(index))
367 }
368 }
369
370 pub fn get_class_name_opt(&self, index: u16) -> Result<Option<String>> {
373 if let Item::Class(utf_index) = *self.get(index)? {
374 if utf_index == 0 {
375 Ok(None)
376 } else {
377 Ok(Some(self.get_utf8(utf_index)?))
378 }
379 } else {
380 Err(Error::InvalidCPItem(index))
381 }
382 }
383
384 pub fn get_class_name(&self, index: u16) -> Result<String> {
386 if let Item::Class(utf_index) = *self.get(index)? {
387 self.get_utf8(utf_index)
388 } else {
389 Err(Error::InvalidCPItem(index))
390 }
391 }
392
393 pub fn push(&mut self, item: Item) -> Result<u16> {
395 if self.len() == u16::max_value() {
396 return Err(Error::CPTooLarge);
397 }
398
399 let double = item.is_double();
400 let length = &mut self.length;
401
402 let rc_item = Rc::new(item);
403 let rc_item1 = Rc::clone(&rc_item);
404
405 let by_index = &mut self.by_index;
406
407 Ok(*self.by_entry.entry(rc_item).or_insert_with(move || {
409 by_index.push(Some(Rc::clone(&rc_item1)));
410
411 let prev_length = *length;
412 if double {
413 by_index.push(None);
415 *length += 2;
416 } else {
417 *length += 1;
418 }
419 prev_length
420 }))
421 }
422
423 pub fn push_duplicate(&mut self, item: Item) -> Result<u16> {
428 if self.len() == u16::max_value() {
429 return Err(Error::CPTooLarge);
430 }
431
432 let double = item.is_double();
433 let length = self.length;
434 let rc_item = Rc::new(item);
435
436 self.by_index.push(Some(Rc::clone(&rc_item)));
437 if double {
438 self.by_index.push(None);
439 self.length += 2;
440 } else {
441 self.length += 1;
442 }
443
444 self.by_entry.insert(rc_item, length);
445 Ok(length)
446 }
447
448 pub fn push_utf8(&mut self, content: String) -> Result<u16> {
450 self.push(Item::UTF8(content))
451 }
452
453 pub fn push_class(&mut self, name: String) -> Result<u16> {
455 let name_index = self.push_utf8(name)?;
456 self.push(Item::Class(name_index))
457 }
458
459 pub fn iter(&self) -> PoolIter {
460 PoolIter {
461 iter: self.by_index.iter(),
462 index: 0,
463 }
464 }
465}
466
467pub struct PoolIter<'a> {
479 iter: Iter<'a, Option<Rc<Item>>>,
480 index: u16,
481}
482
483impl<'a> Iterator for PoolIter<'a> {
484 type Item = (u16, &'a Item);
485
486 fn next(&mut self) -> Option<Self::Item> {
487 self.index += 1;
488 if let Some(rc_item) = self.iter.next() {
489 if let Some(ref item) = *rc_item {
490 Some((self.index, item))
491 } else {
492 self.next()
493 }
494 } else {
495 None
496 }
497 }
498}
499
500#[cfg(test)]
501mod tests {
502 use super::*;
503
504 #[test]
505 fn push_and_get() {
506 let mut pool = Pool::new();
507 assert_eq!(pool.push(Item::Integer(123)).unwrap(), 1);
508 assert_eq!(pool.push(Item::Long(32767)).unwrap(), 2);
509 assert_eq!(pool.push(Item::Long(65535)).unwrap(), 4);
510 assert_eq!(pool.push(Item::Float(3.8)).unwrap(), 6);
511 assert_eq!(pool.len(), 7);
512 assert_eq!(pool.push(Item::Integer(123)).unwrap(), 1);
513 assert_eq!(pool.len(), 7);
514
515 assert_eq!(pool.get(1).unwrap(), &Item::Integer(123));
516 assert_eq!(pool.get(2).unwrap(), &Item::Long(32767));
517 assert_eq!(pool.get(4).unwrap(), &Item::Long(65535));
518 assert_eq!(pool.get(6).unwrap(), &Item::Float(3.8));
519
520 let mut iter = pool.iter();
521 assert_eq!(iter.next(), Some((1, &Item::Integer(123))));
522 assert_eq!(iter.next(), Some((2, &Item::Long(32767))));
523 assert_eq!(iter.next(), Some((4, &Item::Long(65535))));
524 assert_eq!(iter.next(), Some((6, &Item::Float(3.8))));
525 assert_eq!(iter.next(), None);
526 }
527
528 #[test]
529 fn push_duplicate() {
530 let mut pool = Pool::new();
531 assert_eq!(pool.push_duplicate(Item::Integer(123)).unwrap(), 1);
532 assert_eq!(pool.push_duplicate(Item::Long(32767)).unwrap(), 2);
533 assert_eq!(pool.push_duplicate(Item::Long(65535)).unwrap(), 4);
534 assert_eq!(pool.push_duplicate(Item::Float(3.8)).unwrap(), 6);
535 assert_eq!(pool.len(), 7);
536 assert_eq!(pool.push_duplicate(Item::Integer(123)).unwrap(), 7);
537 assert_eq!(pool.len(), 8);
538
539 assert_eq!(pool.get(1).unwrap(), &Item::Integer(123));
540 assert_eq!(pool.get(2).unwrap(), &Item::Long(32767));
541 assert_eq!(pool.get(4).unwrap(), &Item::Long(65535));
542 assert_eq!(pool.get(6).unwrap(), &Item::Float(3.8));
543 assert_eq!(pool.get(7).unwrap(), &Item::Integer(123));
544 }
545}