1use crate::core::reader::span::Span;
2use crate::{Error, Result};
3
4pub mod section_header;
5pub mod types;
6
7#[derive(Clone)]
11pub struct WasmReader<'a> {
12 pub full_wasm_binary: &'a [u8],
14
15 pub pc: usize,
31}
32
33impl<'a> WasmReader<'a> {
34 pub const fn new(wasm: &'a [u8]) -> Self {
36 Self {
37 full_wasm_binary: wasm,
38 pc: 0,
39 }
40 }
41
42 pub fn move_start_to(&mut self, span: Span) -> Result<()> {
50 if span.from + span.len > self.full_wasm_binary.len() {
51 return Err(Error::Eof);
52 }
53
54 self.pc = span.from;
55
56 Ok(())
57 }
58
59 pub fn remaining_bytes(&self) -> &[u8] {
61 &self.full_wasm_binary[self.pc..]
62 }
63
64 pub fn make_span(&self, len: usize) -> Result<Span> {
69 if self.pc + len > self.full_wasm_binary.len() {
70 return Err(Error::Eof);
71 }
72 Ok(Span::new(self.pc, len))
73 }
74
75 pub fn strip_bytes<const N: usize>(&mut self) -> Result<[u8; N]> {
86 if N > self.full_wasm_binary.len() - self.pc {
87 return Err(Error::Eof);
88 }
89
90 let bytes = &self.full_wasm_binary[self.pc..(self.pc + N)];
91 self.pc += N;
92
93 Ok(bytes.try_into().expect("the slice length to be exactly N"))
94 }
95
96 pub fn peek_u8(&self) -> Result<u8> {
100 self.full_wasm_binary
101 .get(self.pc)
102 .copied()
103 .ok_or(Error::Eof)
104 }
105
106 pub fn measure_num_read_bytes<T>(
116 &mut self,
117 f: impl FnOnce(&mut WasmReader) -> Result<T>,
118 ) -> Result<(T, usize)> {
119 let before = self.pc;
120 let ret = f(self)?;
121
122 debug_assert!(
124 self.pc >= before,
125 "pc was advanced backwards towards the start"
126 );
127
128 let num_read_bytes = self.pc - before;
129 Ok((ret, num_read_bytes))
130 }
131
132 #[allow(dead_code)]
141 pub fn skip(&mut self, num_bytes: usize) -> Result<()> {
142 if num_bytes > self.full_wasm_binary.len() - self.pc {
143 return Err(Error::Eof);
144 }
145 self.pc += num_bytes;
146 Ok(())
147 }
148
149 pub fn into_inner(self) -> &'a [u8] {
151 self.full_wasm_binary
152 }
153
154 #[allow(dead_code)]
159 pub fn handle_transaction<T, E>(
160 &mut self,
161 f: impl FnOnce(&mut WasmReader<'a>) -> core::result::Result<T, E>,
162 ) -> core::result::Result<T, E> {
163 let original = self.clone();
164 f(self).inspect_err(|_| {
165 *self = original;
166 })
167 }
168}
169
170pub trait WasmReadable: Sized {
171 fn read(wasm: &mut WasmReader) -> Result<Self>;
177
178 fn read_unvalidated(wasm: &mut WasmReader) -> Self;
187}
188
189pub mod span {
190 use core::ops::Index;
191
192 use crate::core::reader::WasmReader;
193
194 #[derive(Copy, Clone, Debug, Hash)]
200 pub struct Span {
201 pub from: usize,
202 pub len: usize,
203 }
204
205 impl Span {
206 pub const fn new(from: usize, len: usize) -> Self {
208 Self { from, len }
209 }
210
211 pub const fn len(&self) -> usize {
213 self.len
214 }
215
216 pub const fn from(&self) -> usize {
217 self.from
218 }
219 }
220
221 impl<'a> Index<Span> for WasmReader<'a> {
222 type Output = [u8];
223
224 fn index(&self, index: Span) -> &'a Self::Output {
225 &self.full_wasm_binary[index.from..(index.from + index.len)]
226 }
227 }
228}
229
230#[cfg(test)]
231mod test {
232 use crate::ValType;
233
234 use super::*;
235 use alloc::vec;
236
237 #[test]
238 fn move_start_to() {
239 let my_bytes = vec![0x11, 0x12, 0x13, 0x14, 0x15];
240 let mut wasm_reader = WasmReader::new(&my_bytes);
241
242 let span = Span::new(0, 0);
243 wasm_reader.move_start_to(span).unwrap();
244 wasm_reader.peek_u8().unwrap();
246
247 let span = Span::new(0, my_bytes.len());
248 wasm_reader.move_start_to(span).unwrap();
249 wasm_reader.peek_u8().unwrap();
250 assert_eq!(wasm_reader[span], my_bytes);
251
252 let span = Span::new(my_bytes.len(), 0);
253 wasm_reader.move_start_to(span).unwrap();
254 let span = Span::new(my_bytes.len() - 1, 1);
257 wasm_reader.move_start_to(span).unwrap();
258
259 assert_eq!(wasm_reader.peek_u8().unwrap(), *my_bytes.last().unwrap());
260 }
261
262 #[test]
263 fn move_start_to_out_of_bounds_1() {
264 let my_bytes = vec![0x11, 0x12, 0x13, 0x14, 0x15];
265 let mut wasm_reader = WasmReader::new(&my_bytes);
266
267 let span = Span::new(my_bytes.len(), 1);
268 assert_eq!(wasm_reader.move_start_to(span), Err(Error::Eof));
269 }
270
271 #[test]
272 fn move_start_to_out_of_bounds_2() {
273 let my_bytes = vec![0x11, 0x12, 0x13, 0x14, 0x15];
274 let mut wasm_reader = WasmReader::new(&my_bytes);
275
276 let span = Span::new(0, my_bytes.len() + 1);
277 assert_eq!(wasm_reader.move_start_to(span), Err(Error::Eof));
278 }
279
280 #[test]
281 fn remaining_bytes_1() {
282 let my_bytes = vec![0x11, 0x12, 0x13, 0x14, 0x15];
283 let mut wasm_reader = WasmReader::new(&my_bytes);
284
285 assert_eq!(wasm_reader.remaining_bytes(), my_bytes);
286 wasm_reader.skip(4).unwrap();
287 assert_eq!(wasm_reader.peek_u8().unwrap(), 0x15);
288
289 assert_eq!(wasm_reader.remaining_bytes(), &my_bytes[4..]);
290 }
291
292 #[test]
293 fn remaining_bytes_2() {
294 let my_bytes = vec![0x11, 0x12, 0x13, 0x14, 0x15];
295 let mut wasm_reader = WasmReader::new(&my_bytes);
296
297 assert_eq!(wasm_reader.remaining_bytes(), my_bytes);
298 wasm_reader.skip(5).unwrap();
299 assert_eq!(wasm_reader.remaining_bytes(), &my_bytes[5..]);
300 assert_eq!(wasm_reader.remaining_bytes(), &[]);
301 }
302
303 #[test]
304 fn strip_bytes_1() {
305 let my_bytes = vec![0x11, 0x12, 0x13, 0x14, 0x15];
306 let mut wasm_reader = WasmReader::new(&my_bytes);
307
308 assert_eq!(wasm_reader.remaining_bytes(), my_bytes);
309 let stripped_bytes = wasm_reader.strip_bytes::<4>().unwrap();
310 assert_eq!(&stripped_bytes, &my_bytes[..4]);
311 assert_eq!(wasm_reader.remaining_bytes(), &[0x15]);
312 }
313
314 #[test]
315 fn strip_bytes_2() {
316 let my_bytes = vec![0x11, 0x12, 0x13, 0x14, 0x15];
317 let mut wasm_reader = WasmReader::new(&my_bytes);
318
319 assert_eq!(wasm_reader.remaining_bytes(), my_bytes);
320 wasm_reader.skip(1).unwrap();
321 let stripped_bytes = wasm_reader.strip_bytes::<4>().unwrap();
322 assert_eq!(&stripped_bytes, &my_bytes[1..5]);
323 assert_eq!(wasm_reader.remaining_bytes(), &[]);
324 }
325
326 #[test]
327 fn strip_bytes_3() {
328 let my_bytes = vec![0x11, 0x12, 0x13, 0x14, 0x15];
329 let mut wasm_reader = WasmReader::new(&my_bytes);
330
331 assert_eq!(wasm_reader.remaining_bytes(), my_bytes);
332 wasm_reader.skip(2).unwrap();
333 let stripped_bytes = wasm_reader.strip_bytes::<4>();
334 assert_eq!(stripped_bytes, Err(Error::Eof));
335 }
336
337 #[test]
338 fn strip_bytes_4() {
339 let my_bytes = vec![0x11, 0x12, 0x13, 0x14, 0x15];
340 let mut wasm_reader = WasmReader::new(&my_bytes);
341
342 assert_eq!(wasm_reader.remaining_bytes(), my_bytes);
343 wasm_reader.skip(5).unwrap();
344 let stripped_bytes = wasm_reader.strip_bytes::<0>().unwrap();
345 assert_eq!(stripped_bytes, [0u8; 0]);
346 }
347
348 #[test]
349 fn skip_1() {
350 let my_bytes = vec![0x11, 0x12, 0x13, 0x14, 0x15];
351 let mut wasm_reader = WasmReader::new(&my_bytes);
352 assert_eq!(wasm_reader.remaining_bytes(), my_bytes);
353 assert_eq!(wasm_reader.skip(6), Err(Error::Eof));
354 }
355
356 #[test]
357 fn reader_transaction() {
358 let bytes = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6];
359 let mut reader = WasmReader::new(&bytes);
360
361 assert_eq!(
362 reader.handle_transaction(|reader| { reader.strip_bytes::<2>() }),
363 Ok([0x1, 0x2]),
364 );
365
366 let transaction_result: Result<()> = reader.handle_transaction(|reader| {
367 assert_eq!(reader.strip_bytes::<2>(), Ok([0x3, 0x4]));
368
369 Err(Error::InvalidMagic)
371 });
372 assert_eq!(transaction_result, Err(Error::InvalidMagic));
373
374 assert_eq!(reader.strip_bytes::<3>(), Ok([0x3, 0x4, 0x5]));
375 }
376
377 #[test]
378 fn reader_transaction_ergonomics() {
379 let bytes = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6];
380 let mut reader = WasmReader::new(&bytes);
381
382 assert_eq!(reader.handle_transaction(WasmReader::read_u8), Ok(0x1));
383
384 assert_eq!(
385 reader.handle_transaction(ValType::read),
386 Err(Error::InvalidValType)
387 );
388 }
389}