baedeker_core/binary/
globalsec.rs1use alloc::vec::Vec;
10
11use crate::binary::leb128::{self, Cursor};
12use crate::binary::section::RawSection;
13use crate::binary::typeparser::parse_val_type as parse_binary_val_type;
14use crate::error::{ByteOffset, DecodeContext, DecodeError, DecodeErrorKind};
15use crate::types::{Global, GlobalType, Mutability, ValType};
16
17pub fn parse_global_section<'a>(section: &RawSection<'a>) -> Result<Vec<Global<'a>>, DecodeError> {
18 let mut cursor = Cursor::new(section.data);
19 let count = decode_u32_in_section(&mut cursor, section.offset)?;
20
21 let mut globals = Vec::with_capacity(cursor.capacity_hint(count));
22 for _ in 0..count {
23 let global_type = parse_global_type(&mut cursor, section.offset)?;
24 let init_offset = section.offset + cursor.position();
25 let init_expr = parse_init_expr(&mut cursor, section.offset)?;
26 globals.push(Global {
27 global_type,
28 init_expr,
29 init_offset,
30 });
31 }
32
33 if !cursor.is_empty() {
34 return Err(DecodeError {
35 offset: ByteOffset(section.offset + cursor.position()),
36 context: DecodeContext::GlobalSection,
37 kind: DecodeErrorKind::SectionSizeMismatch {
38 expected: section.data.len() as u32,
39 consumed: cursor.position() as u32,
40 },
41 });
42 }
43
44 Ok(globals)
45}
46
47fn parse_global_type(
48 cursor: &mut Cursor<'_>,
49 base_offset: usize,
50) -> Result<GlobalType, DecodeError> {
51 let val_type = parse_val_type(cursor, base_offset)?;
52 let mutability = parse_mutability(cursor, base_offset)?;
53 Ok(GlobalType {
54 val_type,
55 mutability,
56 })
57}
58
59fn parse_val_type(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<ValType, DecodeError> {
60 parse_binary_val_type(cursor, base_offset, DecodeContext::GlobalSection)
61}
62
63fn parse_mutability(
64 cursor: &mut Cursor<'_>,
65 base_offset: usize,
66) -> Result<Mutability, DecodeError> {
67 let offset = cursor.position();
68 let byte = cursor.read_byte().map_err(|_| DecodeError {
69 offset: ByteOffset(base_offset + offset),
70 context: DecodeContext::GlobalSection,
71 kind: DecodeErrorKind::UnexpectedEof,
72 })?;
73
74 match byte {
75 0x00 => Ok(Mutability::Const),
76 0x01 => Ok(Mutability::Var),
77 _ => Err(DecodeError {
78 offset: ByteOffset(base_offset + offset),
79 context: DecodeContext::GlobalSection,
80 kind: DecodeErrorKind::InvalidMutability { byte },
81 }),
82 }
83}
84
85fn parse_init_expr<'a>(
86 cursor: &mut Cursor<'a>,
87 base_offset: usize,
88) -> Result<&'a [u8], DecodeError> {
89 let start = cursor.position();
90 loop {
91 let opcode_offset = cursor.position();
92 let byte = cursor.read_byte().map_err(|_| DecodeError {
93 offset: ByteOffset(base_offset + opcode_offset),
94 context: DecodeContext::GlobalSection,
95 kind: DecodeErrorKind::UnexpectedEof,
96 })?;
97
98 if byte == 0x0B {
99 let end = cursor.position();
100 return Ok(&cursor.original()[start..end]);
101 }
102 }
103}
104
105fn decode_u32_in_section(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<u32, DecodeError> {
106 leb128::decode_u32(cursor).map_err(|mut e| {
107 e.context = DecodeContext::GlobalSection;
108 e.offset = ByteOffset(base_offset + e.offset.0);
109 e
110 })
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116 use crate::binary::section::SectionId;
117 use crate::types::NumType;
118
119 fn raw_global_section(data: &[u8]) -> RawSection<'_> {
120 RawSection {
121 id: SectionId::Global,
122 offset: 30,
123 data,
124 }
125 }
126
127 #[test]
128 fn parse_empty_global_section() {
129 let section = raw_global_section(&[0x00]);
130 let globals = parse_global_section(§ion).unwrap();
131 assert!(globals.is_empty());
132 }
133
134 #[test]
135 fn parse_single_i32_global() {
136 let section = raw_global_section(&[0x01, 0x7F, 0x00, 0x41, 0x2A, 0x0B]);
137 let globals = parse_global_section(§ion).unwrap();
138 assert_eq!(globals.len(), 1);
139 assert_eq!(globals[0].global_type.val_type, ValType::Num(NumType::I32));
140 assert_eq!(globals[0].global_type.mutability, Mutability::Const);
141 assert_eq!(globals[0].init_expr, &[0x41, 0x2A, 0x0B]);
142 assert_eq!(globals[0].init_offset, 33);
143 }
144
145 #[test]
146 fn reject_invalid_mutability() {
147 let section = raw_global_section(&[0x01, 0x7F, 0x02, 0x41, 0x00, 0x0B]);
148 let err = parse_global_section(§ion).unwrap_err();
149 assert!(matches!(
150 err.kind,
151 DecodeErrorKind::InvalidMutability { byte: 0x02 }
152 ));
153 }
154
155 #[test]
156 fn reject_unterminated_init_expr() {
157 let section = raw_global_section(&[0x01, 0x7F, 0x00, 0x41, 0x00]);
158 let err = parse_global_section(§ion).unwrap_err();
159 assert_eq!(err.kind, DecodeErrorKind::UnexpectedEof);
160 }
161}