wasmtime/types.rs
1use std::fmt;
2use wasmtime_environ::{EntityType, Global, Memory, ModuleTypes, Table, WasmFuncType, WasmType};
3
4pub(crate) mod matching;
5
6// Type Representations
7
8// Type attributes
9
10/// Indicator of whether a global is mutable or not
11#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
12pub enum Mutability {
13 /// The global is constant and its value does not change
14 Const,
15 /// The value of the global can change over time
16 Var,
17}
18
19// Value Types
20
21/// A list of all possible value types in WebAssembly.
22#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
23pub enum ValType {
24 // NB: the ordering here is intended to match the ordering in
25 // `wasmtime_types::WasmType` to help improve codegen when converting.
26 /// Signed 32 bit integer.
27 I32,
28 /// Signed 64 bit integer.
29 I64,
30 /// Floating point 32 bit integer.
31 F32,
32 /// Floating point 64 bit integer.
33 F64,
34 /// A 128 bit number.
35 V128,
36 /// A reference to a Wasm function.
37 FuncRef,
38 /// A reference to opaque data in the Wasm instance.
39 ExternRef,
40}
41
42impl fmt::Display for ValType {
43 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
44 match self {
45 ValType::I32 => write!(f, "i32"),
46 ValType::I64 => write!(f, "i64"),
47 ValType::F32 => write!(f, "f32"),
48 ValType::F64 => write!(f, "f64"),
49 ValType::V128 => write!(f, "v128"),
50 ValType::ExternRef => write!(f, "externref"),
51 ValType::FuncRef => write!(f, "funcref"),
52 }
53 }
54}
55
56impl ValType {
57 /// Returns true if `ValType` matches any of the numeric types. (e.g. `I32`,
58 /// `I64`, `F32`, `F64`).
59 pub fn is_num(&self) -> bool {
60 match self {
61 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 => true,
62 _ => false,
63 }
64 }
65
66 /// Returns true if `ValType` matches either of the reference types.
67 pub fn is_ref(&self) -> bool {
68 match self {
69 ValType::ExternRef | ValType::FuncRef => true,
70 _ => false,
71 }
72 }
73
74 pub(crate) fn to_wasm_type(&self) -> WasmType {
75 match self {
76 Self::I32 => WasmType::I32,
77 Self::I64 => WasmType::I64,
78 Self::F32 => WasmType::F32,
79 Self::F64 => WasmType::F64,
80 Self::V128 => WasmType::V128,
81 Self::FuncRef => WasmType::FuncRef,
82 Self::ExternRef => WasmType::ExternRef,
83 }
84 }
85
86 pub(crate) fn from_wasm_type(ty: &WasmType) -> Self {
87 match ty {
88 WasmType::I32 => Self::I32,
89 WasmType::I64 => Self::I64,
90 WasmType::F32 => Self::F32,
91 WasmType::F64 => Self::F64,
92 WasmType::V128 => Self::V128,
93 WasmType::FuncRef => Self::FuncRef,
94 WasmType::ExternRef => Self::ExternRef,
95 }
96 }
97}
98
99// External Types
100
101/// A list of all possible types which can be externally referenced from a
102/// WebAssembly module.
103///
104/// This list can be found in [`ImportType`] or [`ExportType`], so these types
105/// can either be imported or exported.
106#[derive(Debug, Clone)]
107pub enum ExternType {
108 /// This external type is the type of a WebAssembly function.
109 Func(FuncType),
110 /// This external type is the type of a WebAssembly global.
111 Global(GlobalType),
112 /// This external type is the type of a WebAssembly table.
113 Table(TableType),
114 /// This external type is the type of a WebAssembly memory.
115 Memory(MemoryType),
116}
117
118macro_rules! accessors {
119 ($(($variant:ident($ty:ty) $get:ident $unwrap:ident))*) => ($(
120 /// Attempt to return the underlying type of this external type,
121 /// returning `None` if it is a different type.
122 pub fn $get(&self) -> Option<&$ty> {
123 if let ExternType::$variant(e) = self {
124 Some(e)
125 } else {
126 None
127 }
128 }
129
130 /// Returns the underlying descriptor of this [`ExternType`], panicking
131 /// if it is a different type.
132 ///
133 /// # Panics
134 ///
135 /// Panics if `self` is not of the right type.
136 pub fn $unwrap(&self) -> &$ty {
137 self.$get().expect(concat!("expected ", stringify!($ty)))
138 }
139 )*)
140}
141
142impl ExternType {
143 accessors! {
144 (Func(FuncType) func unwrap_func)
145 (Global(GlobalType) global unwrap_global)
146 (Table(TableType) table unwrap_table)
147 (Memory(MemoryType) memory unwrap_memory)
148 }
149
150 pub(crate) fn from_wasmtime(types: &ModuleTypes, ty: &EntityType) -> ExternType {
151 match ty {
152 EntityType::Function(idx) => FuncType::from_wasm_func_type(types[*idx].clone()).into(),
153 EntityType::Global(ty) => GlobalType::from_wasmtime_global(ty).into(),
154 EntityType::Memory(ty) => MemoryType::from_wasmtime_memory(ty).into(),
155 EntityType::Table(ty) => TableType::from_wasmtime_table(ty).into(),
156 EntityType::Tag(_) => unimplemented!("wasm tag support"),
157 }
158 }
159}
160
161impl From<FuncType> for ExternType {
162 fn from(ty: FuncType) -> ExternType {
163 ExternType::Func(ty)
164 }
165}
166
167impl From<GlobalType> for ExternType {
168 fn from(ty: GlobalType) -> ExternType {
169 ExternType::Global(ty)
170 }
171}
172
173impl From<MemoryType> for ExternType {
174 fn from(ty: MemoryType) -> ExternType {
175 ExternType::Memory(ty)
176 }
177}
178
179impl From<TableType> for ExternType {
180 fn from(ty: TableType) -> ExternType {
181 ExternType::Table(ty)
182 }
183}
184
185/// A descriptor for a function in a WebAssembly module.
186///
187/// WebAssembly functions can have 0 or more parameters and results.
188#[derive(Debug, Clone, Hash, Eq, PartialEq)]
189pub struct FuncType {
190 sig: WasmFuncType,
191}
192
193impl FuncType {
194 /// Creates a new function descriptor from the given parameters and results.
195 ///
196 /// The function descriptor returned will represent a function which takes
197 /// `params` as arguments and returns `results` when it is finished.
198 pub fn new(
199 params: impl IntoIterator<Item = ValType>,
200 results: impl IntoIterator<Item = ValType>,
201 ) -> FuncType {
202 FuncType {
203 sig: WasmFuncType::new(
204 params.into_iter().map(|t| t.to_wasm_type()).collect(),
205 results.into_iter().map(|t| t.to_wasm_type()).collect(),
206 ),
207 }
208 }
209
210 /// Returns the list of parameter types for this function.
211 #[inline]
212 pub fn params(&self) -> impl ExactSizeIterator<Item = ValType> + '_ {
213 self.sig.params().iter().map(ValType::from_wasm_type)
214 }
215
216 /// Returns the list of result types for this function.
217 #[inline]
218 pub fn results(&self) -> impl ExactSizeIterator<Item = ValType> + '_ {
219 self.sig.returns().iter().map(ValType::from_wasm_type)
220 }
221
222 pub(crate) fn as_wasm_func_type(&self) -> &WasmFuncType {
223 &self.sig
224 }
225
226 pub(crate) fn from_wasm_func_type(sig: WasmFuncType) -> FuncType {
227 Self { sig }
228 }
229}
230
231// Global Types
232
233/// A WebAssembly global descriptor.
234///
235/// This type describes an instance of a global in a WebAssembly module. Globals
236/// are local to an [`Instance`](crate::Instance) and are either immutable or
237/// mutable.
238#[derive(Debug, Clone, Hash, Eq, PartialEq)]
239pub struct GlobalType {
240 content: ValType,
241 mutability: Mutability,
242}
243
244impl GlobalType {
245 /// Creates a new global descriptor of the specified `content` type and
246 /// whether or not it's mutable.
247 pub fn new(content: ValType, mutability: Mutability) -> GlobalType {
248 GlobalType {
249 content,
250 mutability,
251 }
252 }
253
254 /// Returns the value type of this global descriptor.
255 pub fn content(&self) -> &ValType {
256 &self.content
257 }
258
259 /// Returns whether or not this global is mutable.
260 pub fn mutability(&self) -> Mutability {
261 self.mutability
262 }
263
264 /// Returns `None` if the wasmtime global has a type that we can't
265 /// represent, but that should only very rarely happen and indicate a bug.
266 pub(crate) fn from_wasmtime_global(global: &Global) -> GlobalType {
267 let ty = ValType::from_wasm_type(&global.wasm_ty);
268 let mutability = if global.mutability {
269 Mutability::Var
270 } else {
271 Mutability::Const
272 };
273 GlobalType::new(ty, mutability)
274 }
275}
276
277// Table Types
278
279/// A descriptor for a table in a WebAssembly module.
280///
281/// Tables are contiguous chunks of a specific element, typically a `funcref` or
282/// an `externref`. The most common use for tables is a function table through
283/// which `call_indirect` can invoke other functions.
284#[derive(Debug, Clone, Hash, Eq, PartialEq)]
285pub struct TableType {
286 ty: Table,
287}
288
289impl TableType {
290 /// Creates a new table descriptor which will contain the specified
291 /// `element` and have the `limits` applied to its length.
292 pub fn new(element: ValType, min: u32, max: Option<u32>) -> TableType {
293 TableType {
294 ty: Table {
295 wasm_ty: element.to_wasm_type(),
296 minimum: min,
297 maximum: max,
298 },
299 }
300 }
301
302 /// Returns the element value type of this table.
303 pub fn element(&self) -> ValType {
304 ValType::from_wasm_type(&self.ty.wasm_ty)
305 }
306
307 /// Returns minimum number of elements this table must have
308 pub fn minimum(&self) -> u32 {
309 self.ty.minimum
310 }
311
312 /// Returns the optionally-specified maximum number of elements this table
313 /// can have.
314 ///
315 /// If this returns `None` then the table is not limited in size.
316 pub fn maximum(&self) -> Option<u32> {
317 self.ty.maximum
318 }
319
320 pub(crate) fn from_wasmtime_table(table: &Table) -> TableType {
321 TableType { ty: table.clone() }
322 }
323
324 pub(crate) fn wasmtime_table(&self) -> &Table {
325 &self.ty
326 }
327}
328
329// Memory Types
330
331/// A descriptor for a WebAssembly memory type.
332///
333/// Memories are described in units of pages (64KB) and represent contiguous
334/// chunks of addressable memory.
335#[derive(Debug, Clone, Hash, Eq, PartialEq)]
336pub struct MemoryType {
337 ty: Memory,
338}
339
340impl MemoryType {
341 /// Creates a new descriptor for a 32-bit WebAssembly memory given the
342 /// specified limits of the memory.
343 ///
344 /// The `minimum` and `maximum` values here are specified in units of
345 /// WebAssembly pages, which are 64k.
346 pub fn new(minimum: u32, maximum: Option<u32>) -> MemoryType {
347 MemoryType {
348 ty: Memory {
349 memory64: false,
350 shared: false,
351 minimum: minimum.into(),
352 maximum: maximum.map(|i| i.into()),
353 },
354 }
355 }
356
357 /// Creates a new descriptor for a 64-bit WebAssembly memory given the
358 /// specified limits of the memory.
359 ///
360 /// The `minimum` and `maximum` values here are specified in units of
361 /// WebAssembly pages, which are 64k.
362 ///
363 /// Note that 64-bit memories are part of the memory64 proposal for
364 /// WebAssembly which is not standardized yet.
365 pub fn new64(minimum: u64, maximum: Option<u64>) -> MemoryType {
366 MemoryType {
367 ty: Memory {
368 memory64: true,
369 shared: false,
370 minimum,
371 maximum,
372 },
373 }
374 }
375
376 /// Creates a new descriptor for shared WebAssembly memory given the
377 /// specified limits of the memory.
378 ///
379 /// The `minimum` and `maximum` values here are specified in units of
380 /// WebAssembly pages, which are 64k.
381 ///
382 /// Note that shared memories are part of the threads proposal for
383 /// WebAssembly which is not standardized yet.
384 pub fn shared(minimum: u32, maximum: u32) -> MemoryType {
385 MemoryType {
386 ty: Memory {
387 memory64: false,
388 shared: true,
389 minimum: minimum.into(),
390 maximum: Some(maximum.into()),
391 },
392 }
393 }
394
395 /// Returns whether this is a 64-bit memory or not.
396 ///
397 /// Note that 64-bit memories are part of the memory64 proposal for
398 /// WebAssembly which is not standardized yet.
399 pub fn is_64(&self) -> bool {
400 self.ty.memory64
401 }
402
403 /// Returns whether this is a shared memory or not.
404 ///
405 /// Note that shared memories are part of the threads proposal for
406 /// WebAssembly which is not standardized yet.
407 pub fn is_shared(&self) -> bool {
408 self.ty.shared
409 }
410
411 /// Returns minimum number of WebAssembly pages this memory must have.
412 ///
413 /// Note that the return value, while a `u64`, will always fit into a `u32`
414 /// for 32-bit memories.
415 pub fn minimum(&self) -> u64 {
416 self.ty.minimum
417 }
418
419 /// Returns the optionally-specified maximum number of pages this memory
420 /// can have.
421 ///
422 /// If this returns `None` then the memory is not limited in size.
423 ///
424 /// Note that the return value, while a `u64`, will always fit into a `u32`
425 /// for 32-bit memories.
426 pub fn maximum(&self) -> Option<u64> {
427 self.ty.maximum
428 }
429
430 pub(crate) fn from_wasmtime_memory(memory: &Memory) -> MemoryType {
431 MemoryType { ty: memory.clone() }
432 }
433
434 pub(crate) fn wasmtime_memory(&self) -> &Memory {
435 &self.ty
436 }
437}
438
439// Import Types
440
441/// A descriptor for an imported value into a wasm module.
442///
443/// This type is primarily accessed from the
444/// [`Module::imports`](crate::Module::imports) API. Each [`ImportType`]
445/// describes an import into the wasm module with the module/name that it's
446/// imported from as well as the type of item that's being imported.
447#[derive(Clone)]
448pub struct ImportType<'module> {
449 /// The module of the import.
450 module: &'module str,
451
452 /// The field of the import.
453 name: &'module str,
454
455 /// The type of the import.
456 ty: EntityType,
457 types: &'module ModuleTypes,
458}
459
460impl<'module> ImportType<'module> {
461 /// Creates a new import descriptor which comes from `module` and `name` and
462 /// is of type `ty`.
463 pub(crate) fn new(
464 module: &'module str,
465 name: &'module str,
466 ty: EntityType,
467 types: &'module ModuleTypes,
468 ) -> ImportType<'module> {
469 ImportType {
470 module,
471 name,
472 ty,
473 types,
474 }
475 }
476
477 /// Returns the module name that this import is expected to come from.
478 pub fn module(&self) -> &'module str {
479 self.module
480 }
481
482 /// Returns the field name of the module that this import is expected to
483 /// come from.
484 pub fn name(&self) -> &'module str {
485 self.name
486 }
487
488 /// Returns the expected type of this import.
489 pub fn ty(&self) -> ExternType {
490 ExternType::from_wasmtime(self.types, &self.ty)
491 }
492}
493
494impl<'module> fmt::Debug for ImportType<'module> {
495 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
496 f.debug_struct("ImportType")
497 .field("module", &self.module())
498 .field("name", &self.name())
499 .field("ty", &self.ty())
500 .finish()
501 }
502}
503
504// Export Types
505
506/// A descriptor for an exported WebAssembly value.
507///
508/// This type is primarily accessed from the
509/// [`Module::exports`](crate::Module::exports) accessor and describes what
510/// names are exported from a wasm module and the type of the item that is
511/// exported.
512#[derive(Clone)]
513pub struct ExportType<'module> {
514 /// The name of the export.
515 name: &'module str,
516
517 /// The type of the export.
518 ty: EntityType,
519 types: &'module ModuleTypes,
520}
521
522impl<'module> ExportType<'module> {
523 /// Creates a new export which is exported with the given `name` and has the
524 /// given `ty`.
525 pub(crate) fn new(
526 name: &'module str,
527 ty: EntityType,
528 types: &'module ModuleTypes,
529 ) -> ExportType<'module> {
530 ExportType { name, ty, types }
531 }
532
533 /// Returns the name by which this export is known.
534 pub fn name(&self) -> &'module str {
535 self.name
536 }
537
538 /// Returns the type of this export.
539 pub fn ty(&self) -> ExternType {
540 ExternType::from_wasmtime(self.types, &self.ty)
541 }
542}
543
544impl<'module> fmt::Debug for ExportType<'module> {
545 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
546 f.debug_struct("ExportType")
547 .field("name", &self.name().to_owned())
548 .field("ty", &self.ty())
549 .finish()
550 }
551}