wasmparser/readers/core/
code.rs

1/* Copyright 2018 Mozilla Foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16use crate::{BinaryReader, FromReader, OperatorsReader, Result, SectionLimited, ValType};
17use core::ops::Range;
18
19/// A reader for the code section of a WebAssembly module.
20pub type CodeSectionReader<'a> = SectionLimited<'a, FunctionBody<'a>>;
21
22/// Represents a WebAssembly function body.
23#[derive(Debug, Clone)]
24pub struct FunctionBody<'a> {
25    reader: BinaryReader<'a>,
26}
27
28impl<'a> FunctionBody<'a> {
29    /// Constructs a new `FunctionBody` for the given data and offset.
30    pub fn new(reader: BinaryReader<'a>) -> Self {
31        Self { reader }
32    }
33
34    /// Gets a binary reader for this function body.
35    pub fn get_binary_reader(&self) -> BinaryReader<'a> {
36        self.reader.clone()
37    }
38
39    fn skip_locals(reader: &mut BinaryReader) -> Result<()> {
40        let count = reader.read_var_u32()?;
41        for _ in 0..count {
42            reader.read_var_u32()?;
43            reader.read::<ValType>()?;
44        }
45        Ok(())
46    }
47
48    /// Gets the locals reader for this function body.
49    pub fn get_locals_reader(&self) -> Result<LocalsReader<'a>> {
50        let mut reader = self.reader.clone();
51        let count = reader.read_var_u32()?;
52        Ok(LocalsReader { reader, count })
53    }
54
55    /// Gets the operators reader for this function body.
56    pub fn get_operators_reader(&self) -> Result<OperatorsReader<'a>> {
57        let mut reader = self.reader.clone();
58        Self::skip_locals(&mut reader)?;
59        Ok(OperatorsReader::new(reader))
60    }
61
62    /// Gets the range of the function body.
63    pub fn range(&self) -> Range<usize> {
64        self.reader.range()
65    }
66
67    /// Returns the body of this function as a list of bytes.
68    ///
69    /// Note that the returned bytes start with the function locals declaration.
70    pub fn as_bytes(&self) -> &'a [u8] {
71        self.reader.remaining_buffer()
72    }
73}
74
75impl<'a> FromReader<'a> for FunctionBody<'a> {
76    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
77        let reader = reader.read_reader()?;
78        Ok(FunctionBody { reader })
79    }
80}
81
82/// A reader for a function body's locals.
83pub struct LocalsReader<'a> {
84    reader: BinaryReader<'a>,
85    count: u32,
86}
87
88impl<'a> LocalsReader<'a> {
89    /// Gets the count of locals in the function body.
90    pub fn get_count(&self) -> u32 {
91        self.count
92    }
93
94    /// Gets the original position of the reader.
95    pub fn original_position(&self) -> usize {
96        self.reader.original_position()
97    }
98
99    /// Reads an item from the reader.
100    pub fn read(&mut self) -> Result<(u32, ValType)> {
101        let count = self.reader.read()?;
102        let value_type = self.reader.read()?;
103        Ok((count, value_type))
104    }
105}
106
107impl<'a> IntoIterator for LocalsReader<'a> {
108    type Item = Result<(u32, ValType)>;
109    type IntoIter = LocalsIterator<'a>;
110    fn into_iter(self) -> Self::IntoIter {
111        let count = self.count;
112        LocalsIterator {
113            reader: self,
114            left: count,
115            err: false,
116        }
117    }
118}
119
120/// An iterator over locals in a function body.
121pub struct LocalsIterator<'a> {
122    reader: LocalsReader<'a>,
123    left: u32,
124    err: bool,
125}
126
127impl<'a> Iterator for LocalsIterator<'a> {
128    type Item = Result<(u32, ValType)>;
129    fn next(&mut self) -> Option<Self::Item> {
130        if self.err || self.left == 0 {
131            return None;
132        }
133        let result = self.reader.read();
134        self.err = result.is_err();
135        self.left -= 1;
136        Some(result)
137    }
138    fn size_hint(&self) -> (usize, Option<usize>) {
139        let count = self.reader.get_count() as usize;
140        (count, Some(count))
141    }
142}