wasmparser_nostd/readers/core/
types.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::limits::{MAX_WASM_FUNCTION_PARAMS, MAX_WASM_FUNCTION_RETURNS};
17use crate::{BinaryReader, FromReader, Result, SectionLimited};
18use ::alloc::boxed::Box;
19use ::alloc::vec::Vec;
20use ::core::fmt::Debug;
21
22/// Represents the types of values in a WebAssembly module.
23#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
24pub enum ValType {
25    /// The value type is i32.
26    I32,
27    /// The value type is i64.
28    I64,
29    /// The value type is f32.
30    F32,
31    /// The value type is f64.
32    F64,
33    /// The value type is v128.
34    V128,
35    /// The value type is a function reference.
36    FuncRef,
37    /// The value type is an extern reference.
38    ExternRef,
39}
40
41impl ValType {
42    /// Returns whether this value type is a "reference type".
43    ///
44    /// Only reference types are allowed in tables, for example, and with some
45    /// instructions. Current reference types include `funcref` and `externref`.
46    pub fn is_reference_type(&self) -> bool {
47        matches!(self, ValType::FuncRef | ValType::ExternRef)
48    }
49
50    pub(crate) fn from_byte(byte: u8) -> Option<ValType> {
51        match byte {
52            0x7F => Some(ValType::I32),
53            0x7E => Some(ValType::I64),
54            0x7D => Some(ValType::F32),
55            0x7C => Some(ValType::F64),
56            0x7B => Some(ValType::V128),
57            0x70 => Some(ValType::FuncRef),
58            0x6F => Some(ValType::ExternRef),
59            _ => None,
60        }
61    }
62}
63
64impl<'a> FromReader<'a> for ValType {
65    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
66        match ValType::from_byte(reader.peek()?) {
67            Some(ty) => {
68                reader.position += 1;
69                Ok(ty)
70            }
71            None => bail!(reader.original_position(), "invalid value type"),
72        }
73    }
74}
75
76/// Represents a type in a WebAssembly module.
77#[derive(Debug, Clone)]
78pub enum Type {
79    /// The type is for a function.
80    Func(FuncType),
81}
82
83/// Represents a type of a function in a WebAssembly module.
84#[derive(Clone, Eq, PartialEq, Hash)]
85pub struct FuncType {
86    /// The combined parameters and result types.
87    params_results: Box<[ValType]>,
88    /// The number of parameter types.
89    len_params: usize,
90}
91
92impl Debug for FuncType {
93    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
94        f.debug_struct("FuncType")
95            .field("params", &self.params())
96            .field("returns", &self.results())
97            .finish()
98    }
99}
100
101impl FuncType {
102    /// Creates a new [`FuncType`] from the given `params` and `results`.
103    pub fn new<P, R>(params: P, results: R) -> Self
104    where
105        P: IntoIterator<Item = ValType>,
106        R: IntoIterator<Item = ValType>,
107    {
108        let mut buffer = params.into_iter().collect::<Vec<_>>();
109        let len_params = buffer.len();
110        buffer.extend(results);
111        Self {
112            params_results: buffer.into(),
113            len_params,
114        }
115    }
116
117    /// Creates a new [`FuncType`] fom its raw parts.
118    ///
119    /// # Panics
120    ///
121    /// If `len_params` is greater than the length of `params_results` combined.
122    pub(crate) fn from_raw_parts(params_results: Box<[ValType]>, len_params: usize) -> Self {
123        assert!(len_params <= params_results.len());
124        Self {
125            params_results,
126            len_params,
127        }
128    }
129
130    /// Returns a shared slice to the parameter types of the [`FuncType`].
131    #[inline]
132    pub fn params(&self) -> &[ValType] {
133        &self.params_results[..self.len_params]
134    }
135
136    /// Returns a shared slice to the result types of the [`FuncType`].
137    #[inline]
138    pub fn results(&self) -> &[ValType] {
139        &self.params_results[self.len_params..]
140    }
141}
142
143/// Represents a table's type.
144#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
145pub struct TableType {
146    /// The table's element type.
147    pub element_type: ValType,
148    /// Initial size of this table, in elements.
149    pub initial: u32,
150    /// Optional maximum size of the table, in elements.
151    pub maximum: Option<u32>,
152}
153
154/// Represents a memory's type.
155#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
156pub struct MemoryType {
157    /// Whether or not this is a 64-bit memory, using i64 as an index. If this
158    /// is false it's a 32-bit memory using i32 as an index.
159    ///
160    /// This is part of the memory64 proposal in WebAssembly.
161    pub memory64: bool,
162
163    /// Whether or not this is a "shared" memory, indicating that it should be
164    /// send-able across threads and the `maximum` field is always present for
165    /// valid types.
166    ///
167    /// This is part of the threads proposal in WebAssembly.
168    pub shared: bool,
169
170    /// Initial size of this memory, in wasm pages.
171    ///
172    /// For 32-bit memories (when `memory64` is `false`) this is guaranteed to
173    /// be at most `u32::MAX` for valid types.
174    pub initial: u64,
175
176    /// Optional maximum size of this memory, in wasm pages.
177    ///
178    /// For 32-bit memories (when `memory64` is `false`) this is guaranteed to
179    /// be at most `u32::MAX` for valid types. This field is always present for
180    /// valid wasm memories when `shared` is `true`.
181    pub maximum: Option<u64>,
182}
183
184impl MemoryType {
185    /// Gets the index type for the memory.
186    pub fn index_type(&self) -> ValType {
187        if self.memory64 {
188            ValType::I64
189        } else {
190            ValType::I32
191        }
192    }
193}
194
195/// Represents a global's type.
196#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
197pub struct GlobalType {
198    /// The global's type.
199    pub content_type: ValType,
200    /// Whether or not the global is mutable.
201    pub mutable: bool,
202}
203
204/// Represents a tag kind.
205#[derive(Clone, Copy, Debug)]
206pub enum TagKind {
207    /// The tag is an exception type.
208    Exception,
209}
210
211/// A tag's type.
212#[derive(Clone, Copy, Debug)]
213pub struct TagType {
214    /// The kind of tag
215    pub kind: TagKind,
216    /// The function type this tag uses.
217    pub func_type_idx: u32,
218}
219
220/// A reader for the type section of a WebAssembly module.
221pub type TypeSectionReader<'a> = SectionLimited<'a, Type>;
222
223impl<'a> FromReader<'a> for Type {
224    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
225        Ok(match reader.read_u8()? {
226            0x60 => Type::Func(reader.read()?),
227            x => return reader.invalid_leading_byte(x, "type"),
228        })
229    }
230}
231
232impl<'a> FromReader<'a> for FuncType {
233    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
234        let mut params_results = reader
235            .read_iter(MAX_WASM_FUNCTION_PARAMS, "function params")?
236            .collect::<Result<Vec<_>>>()?;
237        let len_params = params_results.len();
238        let results = reader.read_iter(MAX_WASM_FUNCTION_RETURNS, "function returns")?;
239        params_results.reserve(results.size_hint().0);
240        for result in results {
241            params_results.push(result?);
242        }
243        Ok(FuncType::from_raw_parts(params_results.into(), len_params))
244    }
245}