Skip to main content

lvm_class/attribute/
annotation.rs

1//! Java annotation types for class file attributes.
2//!
3//! https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-4.html#jvms-4.7.16
4
5use crate::ClassFormatErr;
6use lvm_common::utils::cursor::ByteCursor;
7use num_enum::TryFromPrimitive;
8
9/// A runtime annotation on a class, field, method, or record component.
10///
11/// https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-4.html#jvms-4.7.16
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct Annotation {
14    pub type_index: u16,
15    pub element_value_pairs: Vec<ElementValuePair>,
16}
17
18impl<'a> Annotation {
19    pub(crate) fn read(cursor: &mut ByteCursor<'a>) -> Result<Self, ClassFormatErr> {
20        let type_index = cursor.u16()?;
21        let num_element_value_pairs = cursor.u16()?;
22        let mut element_value_pairs = Vec::with_capacity(num_element_value_pairs as usize);
23
24        for _ in 0..num_element_value_pairs {
25            element_value_pairs.push(ElementValuePair::read(cursor)?)
26        }
27
28        Ok(Self {
29            type_index,
30            element_value_pairs,
31        })
32    }
33}
34
35/// A name-value pair in an annotation.
36///
37/// https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-4.html#jvms-4.7.16
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct ElementValuePair {
40    pub element_name_index: u16,
41    pub value: ElementValue,
42}
43
44impl<'a> ElementValuePair {
45    pub(crate) fn read(cursor: &mut ByteCursor<'a>) -> Result<Self, ClassFormatErr> {
46        Ok(Self {
47            element_name_index: cursor.u16()?,
48            value: ElementValue::read(cursor)?,
49        })
50    }
51}
52
53/// Tag identifying the type of an element value in an annotation.
54///
55/// https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-4.html#jvms-4.7.16.1
56#[derive(Debug, Clone, PartialEq, Eq, TryFromPrimitive)]
57#[repr(u8)]
58pub enum ElementKind {
59    Byte = b'B',
60    Char = b'C',
61    Double = b'D',
62    Float = b'F',
63    Int = b'I',
64    Long = b'J',
65    Short = b'S',
66    Boolean = b'Z',
67    String = b's',
68    EnumClass = b'e',
69    Class = b'c',
70    AnnotationInterface = b'@',
71    ArrayType = b'[',
72}
73
74/// The value of an element in an annotation.
75///
76/// https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-4.html#jvms-4.7.16.1
77#[derive(Debug, Clone, PartialEq, Eq)]
78pub enum ElementValue {
79    Byte(u16),
80    Char(u16),
81    Double(u16),
82    Float(u16),
83    Int(u16),
84    Long(u16),
85    Short(u16),
86    Boolean(u16),
87    String(u16),
88    EnumConstValue {
89        type_name_index: u16,
90        const_name_index: u16,
91    },
92    Class(u16),
93    AnnotationValue(Annotation),
94    Array(Vec<ElementValue>),
95}
96
97impl<'a> ElementValue {
98    pub(crate) fn read(cursor: &mut ByteCursor<'a>) -> Result<Self, ClassFormatErr> {
99        let raw_tag = cursor.u8()?;
100        let tag = ElementKind::try_from_primitive(raw_tag)
101            .map_err(|_| ClassFormatErr::UnknownTag(raw_tag))?;
102
103        let ev = match tag {
104            ElementKind::Byte => Self::Byte(cursor.u16()?),
105            ElementKind::Char => Self::Char(cursor.u16()?),
106            ElementKind::Double => Self::Double(cursor.u16()?),
107            ElementKind::Float => Self::Float(cursor.u16()?),
108            ElementKind::Int => Self::Int(cursor.u16()?),
109            ElementKind::Long => Self::Long(cursor.u16()?),
110            ElementKind::Short => Self::Short(cursor.u16()?),
111            ElementKind::Boolean => Self::Boolean(cursor.u16()?),
112            ElementKind::String => Self::String(cursor.u16()?),
113            ElementKind::EnumClass => Self::EnumConstValue {
114                type_name_index: cursor.u16()?,
115                const_name_index: cursor.u16()?,
116            },
117            ElementKind::Class => Self::Class(cursor.u16()?),
118            ElementKind::AnnotationInterface => Self::AnnotationValue(Annotation::read(cursor)?),
119            ElementKind::ArrayType => {
120                let element_types = cursor.u16()?;
121                let mut elements = Vec::with_capacity(element_types as usize);
122                for _ in 0..element_types {
123                    elements.push(Self::read(cursor)?)
124                }
125                ElementValue::Array(elements)
126            }
127        };
128
129        Ok(ev)
130    }
131}