Skip to main content

lvm_class/attribute/
type_annotation.rs

1//! Type annotation types for class file attributes.
2//!
3//! https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-4.html#jvms-4.7.20
4
5use super::annotation::ElementValuePair;
6use crate::ClassFormatErr;
7use lvm_common::utils::cursor::ByteCursor;
8
9/// Target information for a type annotation, identifying where the type is used.
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum TargetInfo {
12    TypeParameter {
13        type_parameter_index: u8,
14    },
15    Supertype {
16        supertype_index: u16,
17    },
18    TypeParameterBound {
19        type_parameter_index: u8,
20        bound_index: u8,
21    },
22    Empty,
23    MethodFormalParameter {
24        formal_parameter_index: u8,
25    },
26    Throws {
27        throws_type_index: u16,
28    },
29    LocalVar {
30        localvar_table: Vec<LocalVarEntry>,
31    },
32    Catch {
33        exception_table_index: u16,
34    },
35    Offset {
36        offset: u16,
37    },
38    TypeArgument {
39        offset: u16,
40        type_argument_index: u8,
41    },
42}
43
44/// An entry in the local variable table for type annotations.
45#[derive(Debug, Clone, PartialEq, Eq)]
46pub struct LocalVarEntry {
47    pub start_pc: u16,
48    pub length: u16,
49    pub index: u16,
50}
51
52/// A path to a specific nested type within a compound type.
53#[derive(Debug, Clone, PartialEq, Eq)]
54pub struct TypePath {
55    pub path: Vec<TypePathEntry>,
56}
57
58/// A single step in a type path.
59#[derive(Debug, Clone, PartialEq, Eq)]
60pub struct TypePathEntry {
61    pub type_path_kind: u8,
62    pub type_argument_index: u8,
63}
64
65/// A type annotation with its target and path information.
66///
67/// https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-4.html#jvms-4.7.20
68#[derive(Debug, Clone, PartialEq, Eq)]
69pub struct TypeAnnotation {
70    pub target_info: TargetInfo,
71    pub target_path: TypePath,
72    pub type_index: u16,
73    pub element_value_pairs: Vec<ElementValuePair>,
74}
75
76impl<'a> TypeAnnotation {
77    pub(crate) fn read(cursor: &mut ByteCursor<'a>) -> Result<Self, ClassFormatErr> {
78        let target_type = cursor.u8()?;
79
80        let target_info = match target_type {
81            0x00 => TargetInfo::TypeParameter {
82                type_parameter_index: cursor.u8()?,
83            },
84            0x01 => TargetInfo::Supertype {
85                supertype_index: cursor.u16()?,
86            },
87            0x10 => TargetInfo::TypeParameterBound {
88                type_parameter_index: cursor.u8()?,
89                bound_index: cursor.u8()?,
90            },
91            0x11 => TargetInfo::Empty,
92            0x12 => TargetInfo::MethodFormalParameter {
93                formal_parameter_index: cursor.u8()?,
94            },
95            0x13 => TargetInfo::Throws {
96                throws_type_index: cursor.u16()?,
97            },
98            0x14 => {
99                let table_length = cursor.u16()?;
100                let mut localvar_table = Vec::with_capacity(table_length as usize);
101                for _ in 0..table_length {
102                    localvar_table.push(LocalVarEntry {
103                        start_pc: cursor.u16()?,
104                        length: cursor.u16()?,
105                        index: cursor.u16()?,
106                    });
107                }
108                TargetInfo::LocalVar { localvar_table }
109            }
110            0x15 => TargetInfo::Catch {
111                exception_table_index: cursor.u16()?,
112            },
113            0x16 => TargetInfo::Offset {
114                offset: cursor.u16()?,
115            },
116            0x17 => TargetInfo::TypeArgument {
117                offset: cursor.u16()?,
118                type_argument_index: cursor.u8()?,
119            },
120            _ => unimplemented!(),
121        };
122
123        // Read type_path
124        let path_length = cursor.u8()?;
125        let mut path = Vec::with_capacity(path_length as usize);
126        for _ in 0..path_length {
127            path.push(TypePathEntry {
128                type_path_kind: cursor.u8()?,
129                type_argument_index: cursor.u8()?,
130            });
131        }
132        let target_path = TypePath { path };
133
134        // Read annotation data
135        let type_index = cursor.u16()?;
136        let num_element_value_pairs = cursor.u16()?;
137        let mut element_value_pairs = Vec::with_capacity(num_element_value_pairs as usize);
138        for _ in 0..num_element_value_pairs {
139            element_value_pairs.push(ElementValuePair::read(cursor)?);
140        }
141
142        Ok(Self {
143            target_info,
144            target_path,
145            type_index,
146            element_value_pairs,
147        })
148    }
149}