1use crate::*;
2
3use strum_macros;
4use strum_macros::EnumIter;
5
6#[derive(CopyGetters)]
10pub struct PrimitiveArray<'a> {
11 #[get_copy = "pub"]
12 obj_id: Id,
13 #[get_copy = "pub"]
14 stack_trace_serial: Serial,
15 #[get_copy = "pub"]
21 primitive_type: PrimitiveArrayType,
22 num_elements: u32,
23 contents: &'a [u8],
24}
25
26macro_rules! iterator_method {
27 ($method_name:tt, $type_variant:tt, $iter_struct:tt) => {
28 pub fn $method_name(&self) -> Option<$iter_struct> {
30 match self.primitive_type {
31 PrimitiveArrayType::$type_variant => Some($iter_struct {
32 iter: ParsingIterator::new_stateless(self.contents, self.num_elements),
33 }),
34 _ => None,
35 }
36 }
37 };
38}
39
40impl<'a> PrimitiveArray<'a> {
41 pub(crate) fn parse(input: &[u8], id_size: IdSize) -> nom::IResult<&[u8], PrimitiveArray> {
42 let (input, obj_id) = Id::parse(input, id_size)?;
44 let (input, stack_trace_serial) = number::be_u32(input)?;
45 let (input, num_elements) = number::be_u32(input)?;
46 let (input, type_byte) = number::be_u8(input)?;
47
48 let array_type = match PrimitiveArrayType::from_type_code(type_byte) {
49 Some(t) => t,
50 None => panic!("Unexpected primitive array type {:#X}", type_byte),
51 };
52
53 let size: u32 = match array_type {
54 PrimitiveArrayType::Boolean => 1,
55 PrimitiveArrayType::Char => 2,
56 PrimitiveArrayType::Float => 4,
57 PrimitiveArrayType::Double => 8,
58 PrimitiveArrayType::Byte => 1,
59 PrimitiveArrayType::Short => 2,
60 PrimitiveArrayType::Int => 4,
61 PrimitiveArrayType::Long => 8,
62 };
63
64 let (input, contents) = bytes::take(num_elements * size)(input)?;
65
66 Ok((
67 input,
68 PrimitiveArray {
69 obj_id,
70 stack_trace_serial: stack_trace_serial.into(),
71 primitive_type: array_type,
72 num_elements,
73 contents,
74 },
75 ))
76 }
77
78 iterator_method!(booleans, Boolean, Booleans);
79 iterator_method!(chars, Char, Chars);
80 iterator_method!(floats, Float, Floats);
81 iterator_method!(doubles, Double, Doubles);
82 iterator_method!(bytes, Byte, Bytes);
83 iterator_method!(shorts, Short, Shorts);
84 iterator_method!(ints, Int, Ints);
85 iterator_method!(longs, Long, Longs);
86}
87
88impl StatelessParser for bool {
89 fn parse(input: &[u8]) -> nom::IResult<&[u8], bool> {
90 number::be_u8(input).map(|(input, b)| (input, b != 0))
91 }
92}
93
94macro_rules! parser_impl {
95 ($prim_type:tt, $parser_method:tt) => {
96 impl StatelessParser for $prim_type {
97 fn parse(input: &[u8]) -> nom::IResult<&[u8], $prim_type> {
98 number::$parser_method(input).map(|(input, c)| (input, c))
99 }
100 }
101 };
102}
103
104parser_impl!(u16, be_u16);
105parser_impl!(f32, be_f32);
106parser_impl!(f64, be_f64);
107parser_impl!(i8, be_i8);
108parser_impl!(i16, be_i16);
109parser_impl!(i32, be_i32);
110parser_impl!(i64, be_i64);
111
112macro_rules! iter_struct {
113 ($struct_name:ident, $item_type:ty) => {
114 pub struct $struct_name<'a> {
115 iter: ParsingIterator<'a, $item_type, StatelessParserWrapper<$item_type>>,
116 }
117
118 impl<'a> Iterator for $struct_name<'a> {
119 type Item = ParseResult<'a, $item_type>;
120
121 fn next(&mut self) -> Option<Self::Item> {
122 self.iter.next()
123 }
124 }
125 };
126}
127
128iter_struct!(Booleans, bool);
129iter_struct!(Chars, u16);
130iter_struct!(Floats, f32);
131iter_struct!(Doubles, f64);
132iter_struct!(Bytes, i8);
133iter_struct!(Shorts, i16);
134iter_struct!(Ints, i32);
135iter_struct!(Longs, i64);
136
137#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, EnumIter)]
138pub enum PrimitiveArrayType {
139 Boolean,
140 Char,
141 Float,
142 Double,
143 Byte,
144 Short,
145 Int,
146 Long,
147}
148
149impl PrimitiveArrayType {
150 pub fn java_type_name(&self) -> &'static str {
151 match self {
152 PrimitiveArrayType::Boolean => "boolean",
153 PrimitiveArrayType::Char => "char",
154 PrimitiveArrayType::Float => "float",
155 PrimitiveArrayType::Double => "double",
156 PrimitiveArrayType::Byte => "byte",
157 PrimitiveArrayType::Short => "short",
158 PrimitiveArrayType::Int => "int",
159 PrimitiveArrayType::Long => "long",
160 }
161 }
162
163 pub fn type_code(&self) -> u8 {
167 match self {
168 PrimitiveArrayType::Boolean => 0x04,
169 PrimitiveArrayType::Char => 0x05,
170 PrimitiveArrayType::Float => 0x06,
171 PrimitiveArrayType::Double => 0x07,
172 PrimitiveArrayType::Byte => 0x08,
173 PrimitiveArrayType::Short => 0x09,
174 PrimitiveArrayType::Int => 0x0A,
175 PrimitiveArrayType::Long => 0x0B,
176 }
177 }
178
179 pub fn from_type_code(type_byte: u8) -> Option<PrimitiveArrayType> {
183 match type_byte {
184 0x04 => Some(PrimitiveArrayType::Boolean),
185 0x05 => Some(PrimitiveArrayType::Char),
186 0x06 => Some(PrimitiveArrayType::Float),
187 0x07 => Some(PrimitiveArrayType::Double),
188 0x08 => Some(PrimitiveArrayType::Byte),
189 0x09 => Some(PrimitiveArrayType::Short),
190 0x0A => Some(PrimitiveArrayType::Int),
191 0x0B => Some(PrimitiveArrayType::Long),
192 _ => None,
193 }
194 }
195}