Skip to main content

lvm_class/bytecode/
operand.rs

1//! Bytecode instruction operand types.
2//!
3//! Contains data structures for complex instruction operands like switch tables
4//! and array type codes.
5
6use num_enum::TryFromPrimitive;
7use std::fmt::Formatter;
8
9/// Operand data for the `lookupswitch` instruction.
10///
11/// https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-6.html#jvms-6.5.lookupswitch
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct LookupSwitchData {
14    pub padding: u8,
15    pub default_offset: i32,
16    pub pairs: Vec<(i32, i32)>,
17}
18
19/// Operand data for the `tableswitch` instruction.
20///
21/// https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-6.html#jvms-6.5.tableswitch
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct TableSwitchData {
24    pub padding: u8,
25    pub default_offset: i32,
26    pub low: i32,
27    pub high: i32,
28    pub offsets: Vec<i32>,
29}
30
31/// Array element type codes for the `newarray` instruction.
32///
33/// https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-6.html#jvms-6.5.newarray
34/// Table 6.5-A. Newarray type codes
35#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive)]
36#[repr(u8)]
37pub enum ArrayType {
38    Boolean = 4,
39    Char = 5,
40    Float = 6,
41    Double = 7,
42    Byte = 8,
43    Short = 9,
44    Int = 10,
45    Long = 11,
46}
47
48impl ArrayType {
49    pub fn get_byte_size(&self) -> u8 {
50        match self {
51            ArrayType::Boolean | ArrayType::Byte => 1,
52            ArrayType::Char | ArrayType::Short => 2,
53            ArrayType::Int | ArrayType::Float => 4,
54            ArrayType::Long | ArrayType::Double => 8,
55        }
56    }
57
58    pub fn descriptor(&self) -> &str {
59        match self {
60            ArrayType::Boolean => "[Z",
61            ArrayType::Byte => "[B",
62            ArrayType::Char => "[C",
63            ArrayType::Short => "[S",
64            ArrayType::Int => "[I",
65            ArrayType::Long => "[J",
66            ArrayType::Float => "[F",
67            ArrayType::Double => "[D",
68        }
69    }
70
71    pub const fn as_str(&self) -> &'static str {
72        match self {
73            ArrayType::Boolean => "boolean",
74            ArrayType::Char => "char",
75            ArrayType::Float => "float",
76            ArrayType::Double => "double",
77            ArrayType::Byte => "byte",
78            ArrayType::Short => "short",
79            ArrayType::Int => "int",
80            ArrayType::Long => "long",
81        }
82    }
83}
84
85impl TryFrom<&str> for ArrayType {
86    type Error = ();
87
88    fn try_from(value: &str) -> Result<Self, Self::Error> {
89        match value {
90            "[Z" => Ok(ArrayType::Boolean),
91            "[B" => Ok(ArrayType::Byte),
92            "[C" => Ok(ArrayType::Char),
93            "[S" => Ok(ArrayType::Short),
94            "[I" => Ok(ArrayType::Int),
95            "[J" => Ok(ArrayType::Long),
96            "[F" => Ok(ArrayType::Float),
97            "[D" => Ok(ArrayType::Double),
98            _ => Err(()),
99        }
100    }
101}
102
103impl std::fmt::Display for ArrayType {
104    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
105        f.write_str(self.as_str())
106    }
107}