Bug 1774829 - wasm: Vendor latest wast crate. r=yury,glandium,supply-chain-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D151738
This commit is contained in:
Ryan Hunt 2022-07-28 15:25:42 +00:00
parent c7b9bb7b6c
commit 214a1d40fc
150 changed files with 27465 additions and 15329 deletions

28
Cargo.lock generated
View File

@ -1598,6 +1598,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "flagset"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda653ca797810c02f7ca4b804b40b8b95ae046eb989d356bce17919a8c25499"
[[package]]
name = "flate2"
version = "1.0.24"
@ -5780,40 +5786,46 @@ version = "0.2.100"
[[package]]
name = "wasm-encoder"
version = "0.7.0"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49cfbd7c23474849807ecde008c82eb38d303b07ec61d48f45b65f3c8cdd2770"
checksum = "f76068e87fe9b837a6bc2ccded66784173eadb828c4168643e9fddf6f9ed2e61"
dependencies = [
"leb128",
]
[[package]]
name = "wasm-smith"
version = "0.8.0"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "440458e050ee2731e85af3368ee58e23d4728d597809a88f841a24778876f2b6"
checksum = "b73250e61e41d0e467b78559c7d761841005d724384bb0b78d52ff974acf5520"
dependencies = [
"arbitrary",
"flagset",
"indexmap",
"leb128",
"wasm-encoder",
"wasmparser",
]
[[package]]
name = "wasmparser"
version = "0.78.2"
version = "0.87.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52144d4c78e5cf8b055ceab8e5fa22814ce4315d6002ad32cfd914f37c12fd65"
checksum = "5c04e207cd2e8ecb6f9bd28a2cf3119b4c6bfeee6fe3a25cc1daf8041d00a875"
dependencies = [
"indexmap",
]
[[package]]
name = "wast"
version = "41.0.0"
version = "44.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f882898b8b817cc4edc16aa3692fdc087b356edc8cc0c2164f5b5181e31c3870"
checksum = "5f474d1b1cb7d92e5360b293f28e8bc9b2d115197a5bbf76bdbfba9161cf9cdc"
dependencies = [
"leb128",
"memchr",
"unicode-width",
"wasm-encoder",
]
[[package]]

View File

@ -5,6 +5,6 @@ authors = ["Christian Holler"]
license = "MPL 2.0"
[dependencies]
wasm-smith = "0.8.0"
wasm-smith = "0.11.2"
arbitrary = { version = "1.0.0", features = ["derive"] }
libc = "0.2"

View File

@ -18,5 +18,5 @@ gluesmith = ['jsrust_shared/gluesmith']
jsrust_shared = { path = "./shared" }
# Workaround for https://github.com/rust-lang/rust/issues/58393
mozglue-static = { path = "../../../mozglue/static/rust" }
wast = { version = "41.0.0" }
wasmparser = { version = "0.78.2" }
wast = { version = "44.0.0" }
wasmparser = { version = "0.87.0" }

View File

@ -93,6 +93,12 @@ criteria = "safe-to-deploy"
delta = "0.4.0 -> 0.5.0"
notes = "The repository for this crate belongs in the Mozilla org."
[[audits.flagset]]
who = "Ryan Hunt <rhunt@eqrion.net>"
criteria = "safe-to-deploy"
version = "0.4.3"
notes = "Uses no ambient capabilities, vetted the one instance of unsafe."
[[audits.getrandom]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
@ -268,6 +274,36 @@ criteria = "safe-to-deploy"
version = "1.0.2"
notes = "Very small crate, just hosts the Void type for easier cross-crate interfacing."
[[audits.wasm-encoder]]
who = "Ryan Hunt <rhunt@eqrion.net>"
criteria = "safe-to-deploy"
version = "0.7.0"
notes = "Maintained by the Bytecode Alliance, with contributions from Mozilla. This has no unsafe code and uses no ambient capabilities."
[[audits.wasm-encoder]]
who = "Ryan Hunt <rhunt@eqrion.net>"
criteria = "safe-to-deploy"
delta = "0.7.0 -> 0.14.0"
notes = "wasm-encoder has no unsafe code and uses no ambient capabilities."
[[audits.wasm-smith]]
who = "Ryan Hunt <rhunt@eqrion.net>"
criteria = "safe-to-deploy"
version = "0.11.2"
notes = "Maintained by the Bytecode Alliance, with contributions from Mozilla. I've vetted the one instance of unsafe code."
[[audits.wasmparser]]
who = "Ryan Hunt <rhunt@eqrion.net>"
criteria = "safe-to-deploy"
version = "0.87.0"
notes = "Maintained by the Bytecode Alliance, with contributions from Mozilla. I've vetted the one instance of unsafe code."
[[audits.wast]]
who = "Ryan Hunt <rhunt@eqrion.net>"
criteria = "safe-to-deploy"
version = "44.0.0"
notes = "Maintained by the Bytecode Alliance, with contributions from Mozilla. wast has no unsafe code and the only ambient capability it uses is to read the full contents of a file that is given to it."
[[audits.webdriver]]
who = "Henrik Skupin <mail@hskupin.info>"
criteria = "safe-to-deploy"

View File

@ -1693,22 +1693,10 @@ criteria = "safe-to-run"
version = "0.11.0+wasi-snapshot-preview1"
criteria = "safe-to-deploy"
[[exemptions.wasm-encoder]]
version = "0.7.0"
criteria = "safe-to-run"
[[exemptions.wasm-smith]]
version = "0.8.0"
criteria = "safe-to-run"
[[exemptions.wasmparser]]
version = "0.78.2"
criteria = "safe-to-deploy"
[[exemptions.wast]]
version = "41.0.0"
criteria = "safe-to-deploy"
[[exemptions.webrtc-sdp]]
version = "0.3.9"
criteria = "safe-to-deploy"

View File

@ -0,0 +1 @@
{"files":{"Cargo.toml":"5a87209bc98397121d9b710b6eb05559c5f2ddb7884e82fbfc706026a24fac13","LICENSE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","README.md":"391c693969a7cd5e1810d3fc4271f1b69f79ee1a26def1fc9b3f7c5df50920dd","src/lib.rs":"77804ee547d8723e603975d586deaf4fa8a58bf13a8c80d9416eed0298b39462"},"package":"cda653ca797810c02f7ca4b804b40b8b95ae046eb989d356bce17919a8c25499"}

34
third_party/rust/flagset/Cargo.toml vendored Normal file
View File

@ -0,0 +1,34 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
name = "flagset"
version = "0.4.3"
authors = ["Nathaniel McCallum <nathaniel@profian.com>"]
description = "Data types and a macro for generating enumeration-based bit flags"
homepage = "https://github.com/enarx/flagset"
documentation = "https://docs.rs/flagset"
readme = "README.md"
keywords = ["flags", "bitflags", "enum", "enumflags"]
license = "Apache-2.0"
repository = "https://github.com/enarx/flagset"
[package.metadata.docs.rs]
all-features = true
[dependencies.serde]
version = "1.0"
features = ["serde_derive"]
optional = true
[dev-dependencies.serde_json]
version = "1.0"
[dev-dependencies.serde_repr]
version = "0.1"

202
third_party/rust/flagset/LICENSE vendored Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

227
third_party/rust/flagset/README.md vendored Normal file
View File

@ -0,0 +1,227 @@
[![Build Status](https://github.com/enarx/flagset/workflows/test/badge.svg)](https://github.com/enarx/flagset/actions)
![Rust Version 1.36+](https://img.shields.io/badge/rustc-v1.36%2B-blue.svg)
[![Crate](https://img.shields.io/crates/v/flagset.svg)](https://crates.io/crates/flagset)
[![Docs](https://docs.rs/flagset/badge.svg)](https://docs.rs/flagset)
![License](https://img.shields.io/crates/l/flagset.svg?style=popout)
# Welcome to FlagSet!
FlagSet is a new, ergonomic approach to handling flags that combines the
best of existing crates like `bitflags` and `enumflags` without their
downsides.
## Existing Implementations
The `bitflags` crate has long been part of the Rust ecosystem.
Unfortunately, it doesn't feel like natural Rust. The `bitflags` crate
uses a wierd struct format to define flags. Flags themselves are just
integers constants, so there is little type-safety involved. But it doesn't
have any dependencies. It also allows you to define implied flags (otherwise
known as overlapping flags).
The `enumflags` crate tried to improve on `bitflags` by using enumerations
to define flags. This was a big improvement to the natural feel of the code.
Unfortunately, there are some design flaws. To generate the flags,
procedural macros were used. This implied two separate crates plus
additional dependencies. Further, `enumflags` specifies the size of the
flags using a `repr($size)` attribute. Unfortunately, this attribute
cannot resolve type aliases, such as `c_int`. This makes `enumflags` a
poor fit for FFI, which is the most important place for a flags library.
The `enumflags` crate also disallows overlapping flags and is not
maintained.
FlagSet improves on both of these by adopting the `enumflags` natural feel
and the `bitflags` mode of flag generation; as well as additional API usage
niceties. FlagSet has no dependencies and is extensively documented and
tested. It also tries very hard to prevent you from making mistakes by
avoiding external usage of the integer types. FlagSet is also a zero-cost
abstraction: all functions are inlineable and should reduce to the core
integer operations. FlagSet also does not depend on stdlib, so it can be
used in `no_std` libraries and applications.
## Defining Flags
Flags are defined using the `flags!` macro:
```rust
use flagset::{FlagSet, flags};
use std::os::raw::c_int;
flags! {
enum FlagsA: u8 {
Foo,
Bar,
Baz,
}
enum FlagsB: c_int {
Foo,
Bar,
Baz,
}
}
```
Notice that a flag definition looks just like a regular enumeration, with
the addition of the field-size type. The field-size type is required and
can be either a type or a type alias. Both examples are given above.
Also note that the field-size type specifies the size of the corresponding
`FlagSet` type, not size of the enumeration itself. To specify the size of
the enumeration, use the `repr($size)` attribute as specified below.
## Flag Values
Flags often need values assigned to them. This can be done implicitly,
where the value depends on the order of the flags:
```rust
use flagset::{FlagSet, flags};
flags! {
enum Flags: u16 {
Foo, // Implicit Value: 0b0001
Bar, // Implicit Value: 0b0010
Baz, // Implicit Value: 0b0100
}
}
```
Alternatively, flag values can be defined explicitly, by specifying any
`const` expression:
```rust
use flagset::{FlagSet, flags};
flags! {
enum Flags: u16 {
Foo = 0x01, // Explicit Value: 0b0001
Bar = 2, // Explicit Value: 0b0010
Baz = 0b0100, // Explicit Value: 0b0100
}
}
```
Flags can also overlap or "imply" other flags:
```rust
use flagset::{FlagSet, flags};
flags! {
enum Flags: u16 {
Foo = 0b0001,
Bar = 0b0010,
Baz = 0b0110, // Implies Bar
All = (Flags::Foo | Flags::Bar | Flags::Baz).bits(),
}
}
```
## Specifying Attributes
Attributes can be used on the enumeration itself or any of the values:
```rust
use flagset::{FlagSet, flags};
flags! {
#[derive(PartialOrd, Ord)]
enum Flags: u8 {
Foo,
#[deprecated]
Bar,
Baz,
}
}
```
## Collections of Flags
A collection of flags is a `FlagSet<T>`. If you are storing the flags in
memory, the raw `FlagSet<T>` type should be used. However, if you want to
receive flags as an input to a function, you should use
`impl Into<FlagSet<T>>`. This allows for very ergonomic APIs:
```rust
use flagset::{FlagSet, flags};
flags! {
enum Flags: u8 {
Foo,
Bar,
Baz,
}
}
struct Container(FlagSet<Flags>);
impl Container {
fn new(flags: impl Into<FlagSet<Flags>>) -> Container {
Container(flags.into())
}
}
assert_eq!(Container::new(Flags::Foo | Flags::Bar).0.bits(), 0b011);
assert_eq!(Container::new(Flags::Foo).0.bits(), 0b001);
assert_eq!(Container::new(None).0.bits(), 0b000);
```
## Operations
Operations can be performed on a `FlagSet<F>` or on individual flags:
| Operator | Assignment Operator | Meaning |
|----------|---------------------|------------------------|
| \| | \|= | Union |
| & | &= | Intersection |
| ^ | ^= | Toggle specified flags |
| - | -= | Difference |
| % | %= | Symmetric difference |
| ! | | Toggle all flags |
## Optional Serde support
[Serde] support can be enabled with the 'serde' feature flag. You can then serialize and
deserialize `FlagSet<T>` to and from any of the [supported formats]:
```rust
use flagset::{FlagSet, flags};
flags! {
enum Flags: u8 {
Foo,
Bar,
}
}
let flagset = Flags::Foo | Flags::Bar;
let json = serde_json::to_string(&flagset).unwrap();
let flagset: FlagSet<Flags> = serde_json::from_str(&json).unwrap();
assert_eq!(flagset.bits(), 0b011);
```
For serialization and deserialization of flags enum itself, you can use the [`serde_repr`] crate
(or implement `serde::ser::Serialize` and `serde:de::Deserialize` manually), combined with the
appropriate `repr` attribute:
```rust
use flagset::{FlagSet, flags};
use serde_repr::{Serialize_repr, Deserialize_repr};
flags! {
#[repr(u8)]
#[derive(Deserialize_repr, Serialize_repr)]
enum Flags: u8 {
Foo,
Bar,
}
}
let json = serde_json::to_string(&Flags::Foo).unwrap();
let flag: Flags = serde_json::from_str(&json).unwrap();
assert_eq!(flag, Flags::Foo);
```
[Serde]: https://serde.rs/
[supported formats]: https://serde.rs/#data-formats
[`serde_repr`]: https://crates.io/crates/serde_repr

1286
third_party/rust/flagset/src/lib.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"019d126cc0ed433d59618be3141d40e936debbdcbbb4f806905b421937e0fee9","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"8d8b48c8ed202bd18494ed37678a0712688909bc350e5423fc18d70447e31f56","src/aliases.rs":"13dfd1947ad7285c1bab5b2bd14703e0e0a9392519e4a3a709a6d160751dfd80","src/code.rs":"c9cda29e7f11e404e8e11632c5e67ca0a1136f893c58376921396b2d81208c96","src/custom.rs":"0926d7c9b8418c316b2478abced1ddc0cf88f25c68c4c320e90fff237a033dd1","src/data.rs":"e89f9297f0e5cf2b784c59f445d6f2e7901eaaf7897731f4ef6282672fe7ae70","src/elements.rs":"8c68d1e0b176c643ba4d49705043d68ae063dfe7b790bbc2d0d8edf931981c16","src/encoders.rs":"c721ac7ad3080da42ff3e7397007e44471d1e47a8de117fbde7ab799b75d10a6","src/exports.rs":"6a9c9d1a8571e599424045296250296d11bc394e0f237403b2b8d5500aa18207","src/functions.rs":"e433d9199bad8c75609202a4282797e594002e3610d803e5732989f7b5edc2a6","src/globals.rs":"bb033493914c1c321f19fd3c974f174c13f877659ae7aae31a664790d839276a","src/imports.rs":"07442618a93c4ae3c381d71631256c6db14ed5dbb850905b83e75fb018ec6fbc","src/instances.rs":"d790933204e530e1264a289ef2090193d19006d082fbeba37a204b2f811d10df","src/lib.rs":"4c59c4c0de4138db6b55e9e97922c8b667d8c256015c5a7f1614d86d54e709f4","src/linking.rs":"830516e338fbe79dad86eab3476944bb810af57b3d1a3f215d3770327d379d9e","src/memories.rs":"950285bcf52e4dd6647b1efda05280a3c93c966ff0da33695e2da187dbff4a12","src/modules.rs":"9d92969c27f0fd59efa14c7bf9ac7b96c951c379de3f85907b387184dd571f3a","src/start.rs":"a2466aba18cd194dbd17ac9103f63639f8538cba765891f07b410107b752bafd","src/tables.rs":"6102a61c69046f826ca8cd4738120c7988f3b639d667ad453b9e1af9052c513e","src/tags.rs":"a7f1248b8c2e336c5991a95e846ceeb29de98dd4d691a86d8bbfe96773583630","src/types.rs":"9d268a4437922f607f23703b94b0ada05f6266b6c08a362fd4674649b3e68976","tests/linking.rs":"43025bd4a1270a6a925f421ba728e0ad180ac8e5ea6cb80f2fc443153a5c4ec4"},"package":"49cfbd7c23474849807ecde008c82eb38d303b07ec61d48f45b65f3c8cdd2770"}
{"files":{"Cargo.toml":"fd2036fa2be078a2a13373cf7644d5deb14c640d1fac4414fab7bc753cc632c6","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"8d8b48c8ed202bd18494ed37678a0712688909bc350e5423fc18d70447e31f56","src/component.rs":"d94ed30e52ba557e45139fd268ef6739bffdc5e1e80192917c29cedc6c337af8","src/component/aliases.rs":"c8a5d2f18d3b0586b8a7736b874ba2e685227e4c4a5c8eb2d06137b8e1fd7686","src/component/canonicals.rs":"8b270caef4e0f1e2b62af5b27560ac370399d11ce411aae6b811dddeaedb7750","src/component/components.rs":"07b8cae3a400e1955cc39d142569910b4fef2136021053d0ddbd6404d810aa52","src/component/exports.rs":"3f297f57a1278940c06219581f2129b7608f965371101af3d6c5e1aaa1c22b4f","src/component/imports.rs":"21b88e462ea1bc21fb72099912cb750eece1cf59b74a56a508176ebb4f1e9a74","src/component/instances.rs":"c86f24e466aeb6889413f32d95e039a90a1e20d2e5a0505339aa81fc086a8c24","src/component/modules.rs":"9e80907e72360fae4d8057b6b0e7a6b58edd7ba6aba6e63ba17346518e169617","src/component/start.rs":"6f69ce2ba65fb9551f98300a0f147268cf41323f219496396e911420b427ee1d","src/component/types.rs":"c8e8dd33ffb3379175ac672151fbae8c49c70c461492f0dc350953b15db04bd8","src/core.rs":"d52f366d84a931a1b994c1cf32da860ad0d7a456f82dfcdef32c6260fdc6999c","src/core/code.rs":"765c72621ab253e4f24ecdad5018bfd4327f6782eb2a78dd4687b7ff2702e333","src/core/custom.rs":"df2d6a8c5a64603822301522e9df4344022226301df846941d95930f1f4d99c4","src/core/data.rs":"8ff5166456dc14e46d08571bbc73cabf6da0b035858c63964358225ee0ec64c2","src/core/elements.rs":"102eef18da5b3b07aaf3cd5122d77d43eef96af0e69abfa5ad0efed16d133a46","src/core/exports.rs":"81a40d30b1ae6d8ae32a2ae20e398ccab9cf6b8ae66c985e6ab7f46e06bf2ed4","src/core/functions.rs":"c18b9872ac0c21048a3ce32e5e44e8e702f97a57fa1b3a07bdd98c7f6c820f09","src/core/globals.rs":"f6cd2849026c0d87e9fca4b4273128565b8d75b949c12654d7ad105f7a912ae7","src/core/imports.rs":"782bbc2e70b379831f85716c0f50c0221d1487c8cba26e8845028b2ae1962c0c","src/core/linking.rs":"5c7d5bce822fad92dc096ceafde878c6d25869004ca26dde1378e78ae37071c9","src/core/memories.rs":"840d15fcd9bd4a668298491c6a91455b145c5c7ff1adf8c769aaf49d6c664d3a","src/core/names.rs":"b12bcb3e0462d52849057467f6b80565cda6021f09c3c0f52c1f83341a5f482d","src/core/start.rs":"a01d4a91bcd93048977ccafc6af160357297450395bf598351f5a3e6d322e0de","src/core/tables.rs":"f87a9761002e93c8e04e646cdf19fb5d012b190a4dbba542e8bfe1cfc606b545","src/core/tags.rs":"26d58904871d92f395eed67d4c25f0914b337d213bab2288011abe3ad31fa12b","src/core/types.rs":"42125c08577c418237982980fd13eb9a21e63b52674c0820c2df2e61b5f454fc","src/lib.rs":"54c0f785fa56eed9dc251ce250d54e9fff452bba0a40519fe58e9f137215101c","src/raw.rs":"a6a72cfe8f88ea6476eccee4acf362030ba2d2e5710215bc4f13cde7de6d71ae"},"package":"f76068e87fe9b837a6bc2ccded66784173eadb828c4168643e9fddf6f9ed2e61"}

View File

@ -10,18 +10,23 @@
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
edition = "2021"
name = "wasm-encoder"
version = "0.7.0"
version = "0.14.0"
authors = ["Nick Fitzgerald <fitzgen@gmail.com>"]
description = "A low-level WebAssembly encoder.\n"
description = """
A low-level WebAssembly encoder.
"""
homepage = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-encoder"
documentation = "https://docs.rs/wasm-encoder"
readme = "README.md"
license = "Apache-2.0 WITH LLVM-exception"
repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-encoder"
resolver = "2"
[dependencies.leb128]
version = "0.2.4"
[dev-dependencies.anyhow]
version = "1.0.38"

View File

@ -1,97 +0,0 @@
use super::*;
/// An encoder for the alias section.
///
/// Note that this is part of the [module linking proposal][proposal] and is not
/// currently part of stable WebAssembly.
///
/// [proposal]: https://github.com/webassembly/module-linking
///
/// # Example
///
/// ```
/// use wasm_encoder::{Module, AliasSection, ItemKind};
///
/// let mut aliases = AliasSection::new();
/// aliases.outer_type(0, 2);
/// aliases.instance_export(0, ItemKind::Function, "foo");
///
/// let mut module = Module::new();
/// module.section(&aliases);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Debug)]
pub struct AliasSection {
bytes: Vec<u8>,
num_added: u32,
}
impl AliasSection {
/// Construct a new alias section encoder.
pub fn new() -> AliasSection {
AliasSection {
bytes: vec![],
num_added: 0,
}
}
/// How many aliases have been defined inside this section so far?
pub fn len(&self) -> u32 {
self.num_added
}
/// Define an alias that references the export of a defined instance.
pub fn instance_export(
&mut self,
instance: u32,
kind: crate::ItemKind,
name: &str,
) -> &mut Self {
self.bytes.push(0x00);
self.bytes.extend(encoders::u32(instance));
self.bytes.push(kind as u8);
self.bytes.extend(encoders::str(name));
self.num_added += 1;
self
}
/// Define an alias that references an outer module's type.
pub fn outer_type(&mut self, depth: u32, ty: u32) -> &mut Self {
self.bytes.push(0x01);
self.bytes.extend(encoders::u32(depth));
self.bytes.push(0x07);
self.bytes.extend(encoders::u32(ty));
self.num_added += 1;
self
}
/// Define an alias that references an outer module's module.
pub fn outer_module(&mut self, depth: u32, module: u32) -> &mut Self {
self.bytes.push(0x01);
self.bytes.extend(encoders::u32(depth));
self.bytes.push(ItemKind::Module as u8);
self.bytes.extend(encoders::u32(module));
self.num_added += 1;
self
}
}
impl Section for AliasSection {
fn id(&self) -> u8 {
SectionId::Alias.into()
}
fn encode<S>(&self, sink: &mut S)
where
S: Extend<u8>,
{
let num_added = encoders::u32(self.num_added);
let n = num_added.len();
sink.extend(
encoders::u32(u32::try_from(n + self.bytes.len()).unwrap())
.chain(num_added)
.chain(self.bytes.iter().copied()),
);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,137 @@
mod aliases;
mod canonicals;
mod components;
mod exports;
mod imports;
mod instances;
mod modules;
mod start;
mod types;
pub use self::aliases::*;
pub use self::canonicals::*;
pub use self::components::*;
pub use self::exports::*;
pub use self::imports::*;
pub use self::instances::*;
pub use self::modules::*;
pub use self::start::*;
pub use self::types::*;
use crate::{CustomSection, Encode};
// Core sorts extended by the component model
const CORE_TYPE_SORT: u8 = 0x10;
const CORE_MODULE_SORT: u8 = 0x11;
const CORE_INSTANCE_SORT: u8 = 0x12;
const CORE_SORT: u8 = 0x00;
const FUNCTION_SORT: u8 = 0x01;
const VALUE_SORT: u8 = 0x02;
const TYPE_SORT: u8 = 0x03;
const COMPONENT_SORT: u8 = 0x04;
const INSTANCE_SORT: u8 = 0x05;
/// A WebAssembly component section.
///
/// Various builders defined in this crate already implement this trait, but you
/// can also implement it yourself for your own custom section builders, or use
/// `RawSection` to use a bunch of raw bytes as a section.
pub trait ComponentSection: Encode {
/// Gets the section identifier for this section.
fn id(&self) -> u8;
}
/// Known section identifiers of WebAssembly components.
///
/// These sections are supported by the component model proposal.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
#[repr(u8)]
pub enum ComponentSectionId {
/// The section is a core custom section.
CoreCustom = 0,
/// The section is a core module section.
CoreModule = 1,
/// The section is a core instance section.
CoreInstance = 2,
/// The section is a core alias section.
CoreAlias = 3,
/// The section is a core type section.
CoreType = 4,
/// The section is a component section.
Component = 5,
/// The section is an instance section.
Instance = 6,
/// The section is an alias section.
Alias = 7,
/// The section is a type section.
Type = 8,
/// The section is a canonical function section.
CanonicalFunction = 9,
/// The section is a start section.
Start = 10,
/// The section is an import section.
Import = 11,
/// The section is an export section.
Export = 12,
}
impl From<ComponentSectionId> for u8 {
#[inline]
fn from(id: ComponentSectionId) -> u8 {
id as u8
}
}
impl Encode for ComponentSectionId {
fn encode(&self, sink: &mut Vec<u8>) {
sink.push(*self as u8);
}
}
/// Represents a WebAssembly component that is being encoded.
///
/// Unlike core WebAssembly modules, the sections of a component
/// may appear in any order and may be repeated.
///
/// Components may also added as a section to other components.
#[derive(Clone, Debug)]
pub struct Component {
bytes: Vec<u8>,
}
impl Component {
/// Begin writing a new `Component`.
pub fn new() -> Self {
Self {
bytes: vec![
0x00, 0x61, 0x73, 0x6D, // magic (`\0asm`)
0x0a, 0x00, 0x01, 0x00, // version
],
}
}
/// Finish writing this component and extract ownership of the encoded bytes.
pub fn finish(self) -> Vec<u8> {
self.bytes
}
/// Write a section to this component.
pub fn section(&mut self, section: &impl ComponentSection) -> &mut Self {
self.bytes.push(section.id());
section.encode(&mut self.bytes);
self
}
}
impl Default for Component {
fn default() -> Self {
Self::new()
}
}
impl ComponentSection for CustomSection<'_> {
fn id(&self) -> u8 {
ComponentSectionId::CoreCustom.into()
}
}

View File

@ -0,0 +1,208 @@
use super::{COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, CORE_TYPE_SORT, TYPE_SORT};
use crate::{
encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind,
};
/// Represents the kinds of outer core aliasable items in a component.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CoreOuterAliasKind {
/// The alias is to a core type.
Type,
}
impl Encode for CoreOuterAliasKind {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
Self::Type => {
sink.push(CORE_TYPE_SORT);
}
}
}
}
/// An encoder for the core alias section of WebAssembly components.
///
/// # Example
///
/// ```rust
/// use wasm_encoder::{Component, AliasSection, ExportKind};
///
/// let mut aliases = AliasSection::new();
/// aliases.instance_export(0, ExportKind::Func, "f");
///
/// let mut component = Component::new();
/// component.section(&aliases);
///
/// let bytes = component.finish();
/// ```
#[derive(Clone, Debug, Default)]
pub struct AliasSection {
bytes: Vec<u8>,
num_added: u32,
}
impl AliasSection {
/// Create a new core alias section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of aliases in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define an alias to an instance's export.
pub fn instance_export(
&mut self,
instance_index: u32,
kind: ExportKind,
name: &str,
) -> &mut Self {
kind.encode(&mut self.bytes);
self.bytes.push(0x00);
instance_index.encode(&mut self.bytes);
name.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Define an alias to an outer core item.
///
/// The count starts at 0 to indicate the current component, 1 indicates the direct
/// parent, 2 the grandparent, etc.
pub fn outer(&mut self, count: u32, kind: CoreOuterAliasKind, index: u32) -> &mut Self {
kind.encode(&mut self.bytes);
self.bytes.push(0x01);
count.encode(&mut self.bytes);
index.encode(&mut self.bytes);
self.num_added += 1;
self
}
}
impl Encode for AliasSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl ComponentSection for AliasSection {
fn id(&self) -> u8 {
ComponentSectionId::CoreAlias.into()
}
}
/// Represents the kinds of outer aliasable items in a component.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ComponentOuterAliasKind {
/// The alias is to a core module.
CoreModule,
/// The alias is to a core type.
CoreType,
/// The alias is to a type.
Type,
/// The alias is to a component.
Component,
}
impl Encode for ComponentOuterAliasKind {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
Self::CoreModule => {
sink.push(CORE_SORT);
sink.push(CORE_MODULE_SORT);
}
Self::CoreType => {
sink.push(CORE_SORT);
sink.push(CORE_TYPE_SORT);
}
Self::Type => sink.push(TYPE_SORT),
Self::Component => sink.push(COMPONENT_SORT),
}
}
}
/// An encoder for the alias section of WebAssembly component.
///
/// # Example
///
/// ```rust
/// use wasm_encoder::{Component, ComponentAliasSection, ComponentExportKind, ComponentOuterAliasKind};
///
/// let mut aliases = ComponentAliasSection::new();
/// aliases.instance_export(0, ComponentExportKind::Func, "f");
/// aliases.outer(0, ComponentOuterAliasKind::Type, 1);
///
/// let mut component = Component::new();
/// component.section(&aliases);
///
/// let bytes = component.finish();
/// ```
#[derive(Clone, Debug, Default)]
pub struct ComponentAliasSection {
bytes: Vec<u8>,
num_added: u32,
}
impl ComponentAliasSection {
/// Create a new alias section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of aliases in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define an alias to an instance's export.
pub fn instance_export(
&mut self,
instance_index: u32,
kind: ComponentExportKind,
name: &str,
) -> &mut Self {
kind.encode(&mut self.bytes);
self.bytes.push(0x00);
instance_index.encode(&mut self.bytes);
name.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Define an alias to an outer component item.
///
/// The count starts at 0 to indicate the current component, 1 indicates the direct
/// parent, 2 the grandparent, etc.
pub fn outer(&mut self, count: u32, kind: ComponentOuterAliasKind, index: u32) -> &mut Self {
kind.encode(&mut self.bytes);
self.bytes.push(0x01);
count.encode(&mut self.bytes);
index.encode(&mut self.bytes);
self.num_added += 1;
self
}
}
impl Encode for ComponentAliasSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl ComponentSection for ComponentAliasSection {
fn id(&self) -> u8 {
ComponentSectionId::Alias.into()
}
}

View File

@ -0,0 +1,133 @@
use crate::{encode_section, ComponentSection, ComponentSectionId, Encode};
/// Represents options for canonical function definitions.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CanonicalOption {
/// The string types in the function signature are UTF-8 encoded.
UTF8,
/// The string types in the function signature are UTF-16 encoded.
UTF16,
/// The string types in the function signature are compact UTF-16 encoded.
CompactUTF16,
/// The memory to use if the lifting or lowering of a function requires memory access.
///
/// The value is an index to a core memory.
Memory(u32),
/// The realloc function to use if the lifting or lowering of a function requires memory
/// allocation.
///
/// The value is an index to a core function of type `(func (param i32 i32 i32 i32) (result i32))`.
Realloc(u32),
/// The post-return function to use if the lifting of a function requires
/// cleanup after the function returns.
PostReturn(u32),
}
impl Encode for CanonicalOption {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
Self::UTF8 => sink.push(0x00),
Self::UTF16 => sink.push(0x01),
Self::CompactUTF16 => sink.push(0x02),
Self::Memory(idx) => {
sink.push(0x03);
idx.encode(sink);
}
Self::Realloc(idx) => {
sink.push(0x04);
idx.encode(sink);
}
Self::PostReturn(idx) => {
sink.push(0x05);
idx.encode(sink);
}
}
}
}
/// An encoder for the canonical function section of WebAssembly components.
///
/// # Example
///
/// ```
/// use wasm_encoder::{Component, CanonicalFunctionSection, CanonicalOption};
///
/// let mut functions = CanonicalFunctionSection::new();
/// functions.lift(0, 0, [CanonicalOption::UTF8]);
///
/// let mut component = Component::new();
/// component.section(&functions);
///
/// let bytes = component.finish();
/// ```
#[derive(Clone, Debug, Default)]
pub struct CanonicalFunctionSection {
bytes: Vec<u8>,
num_added: u32,
}
impl CanonicalFunctionSection {
/// Construct a new component function section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of functions in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define a function that will lift a core WebAssembly function to the canonical ABI.
pub fn lift<O>(&mut self, core_func_index: u32, type_index: u32, options: O) -> &mut Self
where
O: IntoIterator<Item = CanonicalOption>,
O::IntoIter: ExactSizeIterator,
{
let options = options.into_iter();
self.bytes.push(0x00);
self.bytes.push(0x00);
core_func_index.encode(&mut self.bytes);
options.len().encode(&mut self.bytes);
for option in options {
option.encode(&mut self.bytes);
}
type_index.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Define a function that will lower a canonical ABI function to a core WebAssembly function.
pub fn lower<O>(&mut self, func_index: u32, options: O) -> &mut Self
where
O: IntoIterator<Item = CanonicalOption>,
O::IntoIter: ExactSizeIterator,
{
let options = options.into_iter();
self.bytes.push(0x01);
self.bytes.push(0x00);
func_index.encode(&mut self.bytes);
options.len().encode(&mut self.bytes);
for option in options {
option.encode(&mut self.bytes);
}
self.num_added += 1;
self
}
}
impl Encode for CanonicalFunctionSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl ComponentSection for CanonicalFunctionSection {
fn id(&self) -> u8 {
ComponentSectionId::CanonicalFunction.into()
}
}

View File

@ -0,0 +1,29 @@
use crate::{Component, ComponentSection, ComponentSectionId, Encode};
/// An encoder for the component section of WebAssembly components.
///
/// # Example
///
/// ```rust
/// use wasm_encoder::{Component, NestedComponentSection};
///
/// let mut nested = Component::new();
/// let mut component = Component::new();
/// component.section(&NestedComponentSection(&nested));
///
/// let bytes = component.finish();
/// ```
#[derive(Clone, Debug)]
pub struct NestedComponentSection<'a>(pub &'a Component);
impl Encode for NestedComponentSection<'_> {
fn encode(&self, sink: &mut Vec<u8>) {
self.0.bytes.encode(sink);
}
}
impl ComponentSection for NestedComponentSection<'_> {
fn id(&self) -> u8 {
ComponentSectionId::Component.into()
}
}

View File

@ -0,0 +1,108 @@
use super::{
COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, FUNCTION_SORT, INSTANCE_SORT, TYPE_SORT,
VALUE_SORT,
};
use crate::{encode_section, ComponentSection, ComponentSectionId, Encode};
/// Represents the kind of an export from a WebAssembly component.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ComponentExportKind {
/// The export is a core module.
Module,
/// The export is a function.
Func,
/// The export is a value.
Value,
/// The export is a type.
Type,
/// The export is an instance.
Instance,
/// The export is a component.
Component,
}
impl Encode for ComponentExportKind {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
Self::Module => {
sink.push(CORE_SORT);
sink.push(CORE_MODULE_SORT);
}
Self::Func => {
sink.push(FUNCTION_SORT);
}
Self::Value => {
sink.push(VALUE_SORT);
}
Self::Type => {
sink.push(TYPE_SORT);
}
Self::Instance => {
sink.push(INSTANCE_SORT);
}
Self::Component => {
sink.push(COMPONENT_SORT);
}
}
}
}
/// An encoder for the export section of WebAssembly component.
///
/// # Example
///
/// ```rust
/// use wasm_encoder::{Component, ComponentExportSection, ComponentExportKind};
///
/// // This exports a function named "foo"
/// let mut exports = ComponentExportSection::new();
/// exports.export("foo", ComponentExportKind::Func, 0);
///
/// let mut component = Component::new();
/// component.section(&exports);
///
/// let bytes = component.finish();
/// ```
#[derive(Clone, Debug, Default)]
pub struct ComponentExportSection {
bytes: Vec<u8>,
num_added: u32,
}
impl ComponentExportSection {
/// Create a new component export section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of exports in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define an export in the export section.
pub fn export(&mut self, name: &str, kind: ComponentExportKind, index: u32) -> &mut Self {
name.encode(&mut self.bytes);
kind.encode(&mut self.bytes);
index.encode(&mut self.bytes);
self.num_added += 1;
self
}
}
impl Encode for ComponentExportSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl ComponentSection for ComponentExportSection {
fn id(&self) -> u8 {
ComponentSectionId::Export.into()
}
}

View File

@ -0,0 +1,148 @@
use crate::{
encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, ComponentValType,
Encode,
};
/// Represents the possible type bounds for type references.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum TypeBounds {
/// The type is bounded by equality.
Eq,
}
impl Encode for TypeBounds {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
Self::Eq => sink.push(0x00),
}
}
}
/// Represents a reference to a type.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum ComponentTypeRef {
/// The reference is to a core module type.
///
/// The index is expected to be core type index to a core module type.
Module(u32),
/// The reference is to a function type.
///
/// The index is expected to be a type index to a function type.
Func(u32),
/// The reference is to a value type.
Value(ComponentValType),
/// The reference is to a bounded type.
///
/// The index is expected to be a type index.
Type(TypeBounds, u32),
/// The reference is to an instance type.
///
/// The index is expected to be a type index to an instance type.
Instance(u32),
/// The reference is to a component type.
///
/// The index is expected to be a type index to a component type.
Component(u32),
}
impl ComponentTypeRef {
/// Gets the export kind of the reference.
pub fn kind(&self) -> ComponentExportKind {
match self {
Self::Module(_) => ComponentExportKind::Module,
Self::Func(_) => ComponentExportKind::Func,
Self::Value(_) => ComponentExportKind::Value,
Self::Type(..) => ComponentExportKind::Type,
Self::Instance(_) => ComponentExportKind::Instance,
Self::Component(_) => ComponentExportKind::Component,
}
}
}
impl Encode for ComponentTypeRef {
fn encode(&self, sink: &mut Vec<u8>) {
self.kind().encode(sink);
match self {
Self::Module(idx) | Self::Func(idx) | Self::Instance(idx) | Self::Component(idx) => {
idx.encode(sink);
}
Self::Value(ty) => ty.encode(sink),
Self::Type(bounds, idx) => {
bounds.encode(sink);
idx.encode(sink);
}
}
}
}
/// An encoder for the import section of WebAssembly components.
///
/// # Example
///
/// ```rust
/// use wasm_encoder::{Component, ComponentTypeSection, PrimitiveValType, ComponentImportSection, ComponentTypeRef};
///
/// let mut types = ComponentTypeSection::new();
///
/// // Define a function type of `[string, string] -> string`.
/// types.function(
/// [
/// (Some("a"), PrimitiveValType::String),
/// (Some("b"), PrimitiveValType::String)
/// ],
/// PrimitiveValType::String
/// );
///
/// // This imports a function named `f` with the type defined above
/// let mut imports = ComponentImportSection::new();
/// imports.import("f", ComponentTypeRef::Func(0));
///
/// let mut component = Component::new();
/// component.section(&types);
/// component.section(&imports);
///
/// let bytes = component.finish();
/// ```
#[derive(Clone, Debug, Default)]
pub struct ComponentImportSection {
bytes: Vec<u8>,
num_added: u32,
}
impl ComponentImportSection {
/// Create a new component import section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of imports in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define an import in the component import section.
pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self {
name.encode(&mut self.bytes);
ty.encode(&mut self.bytes);
self.num_added += 1;
self
}
}
impl Encode for ComponentImportSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl ComponentSection for ComponentImportSection {
fn id(&self) -> u8 {
ComponentSectionId::Import.into()
}
}

View File

@ -0,0 +1,196 @@
use super::CORE_INSTANCE_SORT;
use crate::{
encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind,
};
/// Represents an argument to a module instantiation.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ModuleArg {
/// The argument is an instance.
Instance(u32),
}
impl Encode for ModuleArg {
fn encode(&self, sink: &mut Vec<u8>) {
let (sort, idx) = match self {
Self::Instance(idx) => (CORE_INSTANCE_SORT, *idx),
};
sink.push(sort);
idx.encode(sink);
}
}
/// An encoder for the core instance section of WebAssembly components.
///
/// # Example
///
/// ```rust
/// use wasm_encoder::{Component, InstanceSection, ExportKind, ModuleArg};
///
/// let mut instances = InstanceSection::new();
/// instances.export_items([("foo", ExportKind::Func, 0)]);
/// instances.instantiate(1, [("foo", ModuleArg::Instance(0))]);
///
/// let mut component = Component::new();
/// component.section(&instances);
///
/// let bytes = component.finish();
/// ```
#[derive(Clone, Debug, Default)]
pub struct InstanceSection {
bytes: Vec<u8>,
num_added: u32,
}
impl InstanceSection {
/// Create a new core instance section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of instances in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define an instance by instantiating a core module.
pub fn instantiate<'a, A>(&mut self, module_index: u32, args: A) -> &mut Self
where
A: IntoIterator<Item = (&'a str, ModuleArg)>,
A::IntoIter: ExactSizeIterator,
{
let args = args.into_iter();
self.bytes.push(0x00);
module_index.encode(&mut self.bytes);
args.len().encode(&mut self.bytes);
for (name, arg) in args {
name.encode(&mut self.bytes);
arg.encode(&mut self.bytes);
}
self.num_added += 1;
self
}
/// Define an instance by exporting core WebAssembly items.
pub fn export_items<'a, E>(&mut self, exports: E) -> &mut Self
where
E: IntoIterator<Item = (&'a str, ExportKind, u32)>,
E::IntoIter: ExactSizeIterator,
{
let exports = exports.into_iter();
self.bytes.push(0x01);
exports.len().encode(&mut self.bytes);
for (name, kind, index) in exports {
name.encode(&mut self.bytes);
kind.encode(&mut self.bytes);
index.encode(&mut self.bytes);
}
self.num_added += 1;
self
}
}
impl Encode for InstanceSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl ComponentSection for InstanceSection {
fn id(&self) -> u8 {
ComponentSectionId::CoreInstance.into()
}
}
/// An encoder for the instance section of WebAssembly components.
///
/// # Example
///
/// ```rust
/// use wasm_encoder::{Component, ComponentInstanceSection, ComponentExportKind};
///
/// let mut instances = ComponentInstanceSection::new();
/// instances.export_items([("foo", ComponentExportKind::Func, 0)]);
/// instances.instantiate(1, [("foo", ComponentExportKind::Instance, 0)]);
///
/// let mut component = Component::new();
/// component.section(&instances);
///
/// let bytes = component.finish();
/// ```
#[derive(Clone, Debug, Default)]
pub struct ComponentInstanceSection {
bytes: Vec<u8>,
num_added: u32,
}
impl ComponentInstanceSection {
/// Create a new instance section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of instances in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define an instance by instantiating a component.
pub fn instantiate<'a, A>(&mut self, component_index: u32, args: A) -> &mut Self
where
A: IntoIterator<Item = (&'a str, ComponentExportKind, u32)>,
A::IntoIter: ExactSizeIterator,
{
let args = args.into_iter();
self.bytes.push(0x00);
component_index.encode(&mut self.bytes);
args.len().encode(&mut self.bytes);
for (name, kind, index) in args {
name.encode(&mut self.bytes);
kind.encode(&mut self.bytes);
index.encode(&mut self.bytes);
}
self.num_added += 1;
self
}
/// Define an instance by exporting items.
pub fn export_items<'a, E>(&mut self, exports: E) -> &mut Self
where
E: IntoIterator<Item = (&'a str, ComponentExportKind, u32)>,
E::IntoIter: ExactSizeIterator,
{
let exports = exports.into_iter();
self.bytes.push(0x01);
exports.len().encode(&mut self.bytes);
for (name, kind, index) in exports {
name.encode(&mut self.bytes);
kind.encode(&mut self.bytes);
index.encode(&mut self.bytes);
}
self.num_added += 1;
self
}
}
impl Encode for ComponentInstanceSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl ComponentSection for ComponentInstanceSection {
fn id(&self) -> u8 {
ComponentSectionId::Instance.into()
}
}

View File

@ -0,0 +1,29 @@
use crate::{ComponentSection, ComponentSectionId, Encode, Module};
/// An encoder for the module section of WebAssembly components.
///
/// # Example
///
/// ```rust
/// use wasm_encoder::{Module, Component, ModuleSection};
///
/// let mut module = Module::new();
/// let mut component = Component::new();
/// component.section(&ModuleSection(&module));
///
/// let bytes = component.finish();
/// ```
#[derive(Clone, Debug)]
pub struct ModuleSection<'a>(pub &'a Module);
impl Encode for ModuleSection<'_> {
fn encode(&self, sink: &mut Vec<u8>) {
self.0.bytes.encode(sink);
}
}
impl ComponentSection for ModuleSection<'_> {
fn id(&self) -> u8 {
ComponentSectionId::CoreModule.into()
}
}

View File

@ -0,0 +1,46 @@
use crate::{ComponentSection, ComponentSectionId, Encode};
/// An encoder for the start section of WebAssembly components.
///
/// # Example
///
/// ```
/// use wasm_encoder::{Component, ComponentStartSection};
///
/// let start = ComponentStartSection { function_index: 0, args: [] };
///
/// let mut component = Component::new();
/// component.section(&start);
///
/// let bytes = component.finish();
/// ```
#[derive(Clone, Debug)]
pub struct ComponentStartSection<A> {
/// The index to the start function.
pub function_index: u32,
/// The arguments to pass to the start function.
///
/// An argument is an index to a value.
pub args: A,
}
impl<A> Encode for ComponentStartSection<A>
where
A: AsRef<[u32]>,
{
fn encode(&self, sink: &mut Vec<u8>) {
let mut bytes = Vec::new();
self.function_index.encode(&mut bytes);
self.args.as_ref().encode(&mut bytes);
bytes.encode(sink);
}
}
impl<A> ComponentSection for ComponentStartSection<A>
where
A: AsRef<[u32]>,
{
fn id(&self) -> u8 {
ComponentSectionId::Start.into()
}
}

View File

@ -0,0 +1,727 @@
use crate::{
encode_section, ComponentOuterAliasKind, ComponentSection, ComponentSectionId,
ComponentTypeRef, CoreOuterAliasKind, Encode, EntityType, ValType,
};
/// Represents the type of a core module.
#[derive(Debug, Clone, Default)]
pub struct ModuleType {
bytes: Vec<u8>,
num_added: u32,
types_added: u32,
}
impl ModuleType {
/// Creates a new core module type.
pub fn new() -> Self {
Self::default()
}
/// Defines an outer core type alias in this module type.
pub fn alias_outer_core_type(&mut self, count: u32, index: u32) -> &mut Self {
self.bytes.push(0x02);
CoreOuterAliasKind::Type.encode(&mut self.bytes);
self.bytes.push(0x01);
count.encode(&mut self.bytes);
index.encode(&mut self.bytes);
self.num_added += 1;
self.types_added += 1;
self
}
/// Defines an import in this module type.
pub fn import(&mut self, module: &str, name: &str, ty: EntityType) -> &mut Self {
self.bytes.push(0x00);
module.encode(&mut self.bytes);
name.encode(&mut self.bytes);
ty.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Define a type in this module type.
///
/// The returned encoder must be used before adding another definition.
#[must_use = "the encoder must be used to encode the type"]
pub fn ty(&mut self) -> CoreTypeEncoder {
self.bytes.push(0x01);
self.num_added += 1;
self.types_added += 1;
CoreTypeEncoder(&mut self.bytes)
}
/// Defines an export in this module type.
pub fn export(&mut self, name: &str, ty: EntityType) -> &mut Self {
self.bytes.push(0x03);
name.encode(&mut self.bytes);
ty.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Gets the number of types that have been added to this module type.
pub fn type_count(&self) -> u32 {
self.types_added
}
}
impl Encode for ModuleType {
fn encode(&self, sink: &mut Vec<u8>) {
sink.push(0x50);
self.num_added.encode(sink);
sink.extend(&self.bytes);
}
}
/// Used to encode core types.
#[derive(Debug)]
pub struct CoreTypeEncoder<'a>(pub(crate) &'a mut Vec<u8>);
impl<'a> CoreTypeEncoder<'a> {
/// Define a function type.
pub fn function<P, R>(self, params: P, results: R)
where
P: IntoIterator<Item = ValType>,
P::IntoIter: ExactSizeIterator,
R: IntoIterator<Item = ValType>,
R::IntoIter: ExactSizeIterator,
{
let params = params.into_iter();
let results = results.into_iter();
self.0.push(0x60);
params.len().encode(self.0);
self.0.extend(params.map(u8::from));
results.len().encode(self.0);
self.0.extend(results.map(u8::from));
}
/// Define a module type.
pub fn module(self, ty: &ModuleType) {
ty.encode(self.0);
}
}
/// An encoder for the core type section of WebAssembly components.
///
/// # Example
///
/// ```rust
/// use wasm_encoder::{Component, CoreTypeSection, ModuleType};
///
/// let mut types = CoreTypeSection::new();
///
/// types.module(&ModuleType::new());
///
/// let mut component = Component::new();
/// component.section(&types);
///
/// let bytes = component.finish();
/// ```
#[derive(Clone, Debug, Default)]
pub struct CoreTypeSection {
bytes: Vec<u8>,
num_added: u32,
}
impl CoreTypeSection {
/// Create a new core type section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of types in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Encode a type into this section.
///
/// The returned encoder must be finished before adding another type.
#[must_use = "the encoder must be used to encode the type"]
pub fn ty(&mut self) -> CoreTypeEncoder<'_> {
self.num_added += 1;
CoreTypeEncoder(&mut self.bytes)
}
/// Define a function type in this type section.
pub fn function<P, R>(&mut self, params: P, results: R) -> &mut Self
where
P: IntoIterator<Item = ValType>,
P::IntoIter: ExactSizeIterator,
R: IntoIterator<Item = ValType>,
R::IntoIter: ExactSizeIterator,
{
self.ty().function(params, results);
self
}
/// Define a module type in this type section.
///
/// Currently this is only used for core type sections in components.
pub fn module(&mut self, ty: &ModuleType) -> &mut Self {
self.ty().module(ty);
self
}
}
impl Encode for CoreTypeSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl ComponentSection for CoreTypeSection {
fn id(&self) -> u8 {
ComponentSectionId::CoreType.into()
}
}
/// Represents a component type.
#[derive(Debug, Clone, Default)]
pub struct ComponentType {
bytes: Vec<u8>,
num_added: u32,
core_types_added: u32,
types_added: u32,
}
impl ComponentType {
/// Creates a new component type.
pub fn new() -> Self {
Self::default()
}
/// Define a core type in this component type.
///
/// The returned encoder must be used before adding another definition.
#[must_use = "the encoder must be used to encode the type"]
pub fn core_type(&mut self) -> CoreTypeEncoder {
self.bytes.push(0x00);
self.num_added += 1;
self.core_types_added += 1;
CoreTypeEncoder(&mut self.bytes)
}
/// Define a type in this component type.
///
/// The returned encoder must be used before adding another definition.
#[must_use = "the encoder must be used to encode the type"]
pub fn ty(&mut self) -> ComponentTypeEncoder {
self.bytes.push(0x01);
self.num_added += 1;
self.types_added += 1;
ComponentTypeEncoder(&mut self.bytes)
}
/// Defines an outer core type alias in this component type.
pub fn alias_outer_core_type(&mut self, count: u32, index: u32) -> &mut Self {
self.bytes.push(0x02);
ComponentOuterAliasKind::CoreType.encode(&mut self.bytes);
self.bytes.push(0x01);
count.encode(&mut self.bytes);
index.encode(&mut self.bytes);
self.num_added += 1;
self.types_added += 1;
self
}
/// Defines an outer type alias in this component type.
pub fn alias_outer_type(&mut self, count: u32, index: u32) -> &mut Self {
self.bytes.push(0x02);
ComponentOuterAliasKind::Type.encode(&mut self.bytes);
self.bytes.push(0x01);
count.encode(&mut self.bytes);
index.encode(&mut self.bytes);
self.num_added += 1;
self.types_added += 1;
self
}
/// Defines an import in this component type.
pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self {
self.bytes.push(0x03);
name.encode(&mut self.bytes);
ty.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Defines an export in this component type.
pub fn export(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self {
self.bytes.push(0x04);
name.encode(&mut self.bytes);
ty.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Gets the number of core types that have been added to this component type.
pub fn core_type_count(&self) -> u32 {
self.core_types_added
}
/// Gets the number of types that have been added or aliased in this component type.
pub fn type_count(&self) -> u32 {
self.types_added
}
}
impl Encode for ComponentType {
fn encode(&self, sink: &mut Vec<u8>) {
sink.push(0x41);
self.num_added.encode(sink);
sink.extend(&self.bytes);
}
}
/// Represents an instance type.
#[derive(Debug, Clone, Default)]
pub struct InstanceType {
bytes: Vec<u8>,
num_added: u32,
core_types_added: u32,
types_added: u32,
}
impl InstanceType {
/// Creates a new instance type.
pub fn new() -> Self {
Self::default()
}
/// Define a core type in this instance type.
///
/// The returned encoder must be used before adding another definition.
#[must_use = "the encoder must be used to encode the type"]
pub fn core_type(&mut self) -> CoreTypeEncoder {
self.bytes.push(0x00);
self.num_added += 1;
self.core_types_added += 1;
CoreTypeEncoder(&mut self.bytes)
}
/// Define a type in this instance type.
///
/// The returned encoder must be used before adding another definition.
#[must_use = "the encoder must be used to encode the type"]
pub fn ty(&mut self) -> ComponentTypeEncoder {
self.bytes.push(0x01);
self.num_added += 1;
self.types_added += 1;
ComponentTypeEncoder(&mut self.bytes)
}
/// Defines an outer core type alias in this component type.
pub fn alias_outer_core_type(&mut self, count: u32, index: u32) -> &mut Self {
self.bytes.push(0x02);
ComponentOuterAliasKind::CoreType.encode(&mut self.bytes);
self.bytes.push(0x01);
count.encode(&mut self.bytes);
index.encode(&mut self.bytes);
self.num_added += 1;
self.types_added += 1;
self
}
/// Defines an alias in this instance type.
pub fn alias_outer_type(&mut self, count: u32, index: u32) -> &mut Self {
self.bytes.push(0x02);
ComponentOuterAliasKind::Type.encode(&mut self.bytes);
self.bytes.push(0x01);
count.encode(&mut self.bytes);
index.encode(&mut self.bytes);
self.num_added += 1;
self.types_added += 1;
self
}
/// Defines an export in this instance type.
pub fn export(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self {
self.bytes.push(0x04);
name.encode(&mut self.bytes);
ty.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Gets the number of core types that have been added to this instance type.
pub fn core_type_count(&self) -> u32 {
self.core_types_added
}
/// Gets the number of types that have been added or aliased in this instance type.
pub fn type_count(&self) -> u32 {
self.types_added
}
}
impl Encode for InstanceType {
fn encode(&self, sink: &mut Vec<u8>) {
sink.push(0x42);
self.num_added.encode(sink);
sink.extend(&self.bytes);
}
}
/// Used to encode component and instance types.
#[derive(Debug)]
pub struct ComponentTypeEncoder<'a>(&'a mut Vec<u8>);
impl<'a> ComponentTypeEncoder<'a> {
/// Define a component type.
pub fn component(self, ty: &ComponentType) {
ty.encode(self.0);
}
/// Define an instance type.
pub fn instance(self, ty: &InstanceType) {
ty.encode(self.0);
}
/// Define a function type.
pub fn function<'b, P, T>(self, params: P, result: impl Into<ComponentValType>)
where
P: IntoIterator<Item = (Option<&'b str>, T)>,
P::IntoIter: ExactSizeIterator,
T: Into<ComponentValType>,
{
let params = params.into_iter();
self.0.push(0x40);
params.len().encode(self.0);
for (name, ty) in params {
match name {
Some(name) => {
self.0.push(0x01);
name.encode(self.0);
}
None => self.0.push(0x00),
}
ty.into().encode(self.0);
}
result.into().encode(self.0);
}
/// Define a defined component type.
///
/// The returned encoder must be used before adding another type.
#[must_use = "the encoder must be used to encode the type"]
pub fn defined_type(self) -> ComponentDefinedTypeEncoder<'a> {
ComponentDefinedTypeEncoder(self.0)
}
}
/// Represents a primitive component value type.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PrimitiveValType {
/// The type is the unit type.
Unit,
/// The type is a boolean.
Bool,
/// The type is a signed 8-bit integer.
S8,
/// The type is an unsigned 8-bit integer.
U8,
/// The type is a signed 16-bit integer.
S16,
/// The type is an unsigned 16-bit integer.
U16,
/// The type is a signed 32-bit integer.
S32,
/// The type is an unsigned 32-bit integer.
U32,
/// The type is a signed 64-bit integer.
S64,
/// The type is an unsigned 64-bit integer.
U64,
/// The type is a 32-bit floating point number.
Float32,
/// The type is a 64-bit floating point number.
Float64,
/// The type is a Unicode character.
Char,
/// The type is a string.
String,
}
impl Encode for PrimitiveValType {
fn encode(&self, sink: &mut Vec<u8>) {
sink.push(match self {
Self::Unit => 0x7f,
Self::Bool => 0x7e,
Self::S8 => 0x7d,
Self::U8 => 0x7c,
Self::S16 => 0x7b,
Self::U16 => 0x7a,
Self::S32 => 0x79,
Self::U32 => 0x78,
Self::S64 => 0x77,
Self::U64 => 0x76,
Self::Float32 => 0x75,
Self::Float64 => 0x74,
Self::Char => 0x73,
Self::String => 0x72,
});
}
}
/// Represents a component value type.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ComponentValType {
/// The value is a primitive type.
Primitive(PrimitiveValType),
/// The value is to a defined value type.
///
/// The type index must be to a value type.
Type(u32),
}
impl Encode for ComponentValType {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
Self::Primitive(ty) => ty.encode(sink),
Self::Type(index) => (*index as i64).encode(sink),
}
}
}
impl From<PrimitiveValType> for ComponentValType {
fn from(ty: PrimitiveValType) -> Self {
Self::Primitive(ty)
}
}
/// Used for encoding component defined types.
#[derive(Debug)]
pub struct ComponentDefinedTypeEncoder<'a>(&'a mut Vec<u8>);
impl ComponentDefinedTypeEncoder<'_> {
/// Define a primitive value type.
pub fn primitive(self, ty: PrimitiveValType) {
ty.encode(self.0);
}
/// Define a record type.
pub fn record<'a, F, T>(self, fields: F)
where
F: IntoIterator<Item = (&'a str, T)>,
F::IntoIter: ExactSizeIterator,
T: Into<ComponentValType>,
{
let fields = fields.into_iter();
self.0.push(0x71);
fields.len().encode(self.0);
for (name, ty) in fields {
name.encode(self.0);
ty.into().encode(self.0);
}
}
/// Define a variant type.
pub fn variant<'a, C, T>(self, cases: C)
where
C: IntoIterator<Item = (&'a str, T, Option<u32>)>,
C::IntoIter: ExactSizeIterator,
T: Into<ComponentValType>,
{
let cases = cases.into_iter();
self.0.push(0x70);
cases.len().encode(self.0);
for (name, ty, refines) in cases {
name.encode(self.0);
ty.into().encode(self.0);
if let Some(default) = refines {
self.0.push(0x01);
default.encode(self.0);
} else {
self.0.push(0x00);
}
}
}
/// Define a list type.
pub fn list(self, ty: impl Into<ComponentValType>) {
self.0.push(0x6f);
ty.into().encode(self.0);
}
/// Define a tuple type.
pub fn tuple<I, T>(self, types: I)
where
I: IntoIterator<Item = T>,
I::IntoIter: ExactSizeIterator,
T: Into<ComponentValType>,
{
let types = types.into_iter();
self.0.push(0x6E);
types.len().encode(self.0);
for ty in types {
ty.into().encode(self.0);
}
}
/// Define a flags type.
pub fn flags<'a, I>(self, names: I)
where
I: IntoIterator<Item = &'a str>,
I::IntoIter: ExactSizeIterator,
{
let names = names.into_iter();
self.0.push(0x6D);
names.len().encode(self.0);
for name in names {
name.encode(self.0);
}
}
/// Define an enum type.
pub fn enum_type<'a, I>(self, tags: I)
where
I: IntoIterator<Item = &'a str>,
I::IntoIter: ExactSizeIterator,
{
let tags = tags.into_iter();
self.0.push(0x6C);
tags.len().encode(self.0);
for tag in tags {
tag.encode(self.0);
}
}
/// Define a union type.
pub fn union<I, T>(self, types: I)
where
I: IntoIterator<Item = T>,
I::IntoIter: ExactSizeIterator,
T: Into<ComponentValType>,
{
let types = types.into_iter();
self.0.push(0x6B);
types.len().encode(self.0);
for ty in types {
ty.into().encode(self.0);
}
}
/// Define an option type.
pub fn option(self, ty: impl Into<ComponentValType>) {
self.0.push(0x6A);
ty.into().encode(self.0);
}
/// Define an expected type.
pub fn expected(self, ok: impl Into<ComponentValType>, error: impl Into<ComponentValType>) {
self.0.push(0x69);
ok.into().encode(self.0);
error.into().encode(self.0);
}
}
/// An encoder for the type section of WebAssembly components.
///
/// # Example
///
/// ```rust
/// use wasm_encoder::{Component, ComponentTypeSection, PrimitiveValType};
///
/// let mut types = ComponentTypeSection::new();
///
/// // Define a function type of `[string, string] -> string`.
/// types.function(
/// [
/// (Some("a"), PrimitiveValType::String),
/// (Some("b"), PrimitiveValType::String)
/// ],
/// PrimitiveValType::String
/// );
///
/// let mut component = Component::new();
/// component.section(&types);
///
/// let bytes = component.finish();
/// ```
#[derive(Clone, Debug, Default)]
pub struct ComponentTypeSection {
bytes: Vec<u8>,
num_added: u32,
}
impl ComponentTypeSection {
/// Create a new component type section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of types in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Encode a type into this section.
///
/// The returned encoder must be finished before adding another type.
#[must_use = "the encoder must be used to encode the type"]
pub fn ty(&mut self) -> ComponentTypeEncoder<'_> {
self.num_added += 1;
ComponentTypeEncoder(&mut self.bytes)
}
/// Define a component type in this type section.
pub fn component(&mut self, ty: &ComponentType) -> &mut Self {
self.ty().component(ty);
self
}
/// Define an instance type in this type section.
pub fn instance(&mut self, ty: &InstanceType) -> &mut Self {
self.ty().instance(ty);
self
}
/// Define a function type in this type section.
pub fn function<'a, P, T>(
&mut self,
params: P,
result: impl Into<ComponentValType>,
) -> &mut Self
where
P: IntoIterator<Item = (Option<&'a str>, T)>,
P::IntoIter: ExactSizeIterator,
T: Into<ComponentValType>,
{
self.ty().function(params, result);
self
}
/// Add a component defined type to this type section.
///
/// The returned encoder must be used before adding another type.
#[must_use = "the encoder must be used to encode the type"]
pub fn defined_type(&mut self) -> ComponentDefinedTypeEncoder<'_> {
self.ty().defined_type()
}
}
impl Encode for ComponentTypeSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl ComponentSection for ComponentTypeSection {
fn id(&self) -> u8 {
ComponentSectionId::Type.into()
}
}

View File

@ -0,0 +1,154 @@
mod code;
mod custom;
mod data;
mod elements;
mod exports;
mod functions;
mod globals;
mod imports;
mod linking;
mod memories;
mod names;
mod start;
mod tables;
mod tags;
mod types;
pub use code::*;
pub use custom::*;
pub use data::*;
pub use elements::*;
pub use exports::*;
pub use functions::*;
pub use globals::*;
pub use imports::*;
pub use linking::*;
pub use memories::*;
pub use names::*;
pub use start::*;
pub use tables::*;
pub use tags::*;
pub use types::*;
use crate::Encode;
pub(crate) const CORE_FUNCTION_SORT: u8 = 0x00;
pub(crate) const CORE_TABLE_SORT: u8 = 0x01;
pub(crate) const CORE_MEMORY_SORT: u8 = 0x02;
pub(crate) const CORE_GLOBAL_SORT: u8 = 0x03;
pub(crate) const CORE_TAG_SORT: u8 = 0x04;
/// A WebAssembly module section.
///
/// Various builders defined in this crate already implement this trait, but you
/// can also implement it yourself for your own custom section builders, or use
/// `RawSection` to use a bunch of raw bytes as a section.
pub trait Section: Encode {
/// Gets the section identifier for this section.
fn id(&self) -> u8;
}
/// Known section identifiers of WebAssembly modules.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
#[repr(u8)]
pub enum SectionId {
/// The custom section.
Custom = 0,
/// The type section.
Type = 1,
/// The import section.
Import = 2,
/// The function section.
Function = 3,
/// The table section.
Table = 4,
/// The memory section.
Memory = 5,
/// The global section.
Global = 6,
/// The export section.
Export = 7,
/// The start section.
Start = 8,
/// The element section.
Element = 9,
/// The code section.
Code = 10,
/// The data section.
Data = 11,
/// The data count section.
DataCount = 12,
/// The tag section.
///
/// This section is supported by the exception handling proposal.
Tag = 13,
}
impl From<SectionId> for u8 {
#[inline]
fn from(id: SectionId) -> u8 {
id as u8
}
}
impl Encode for SectionId {
fn encode(&self, sink: &mut Vec<u8>) {
sink.push(*self as u8);
}
}
/// Represents a WebAssembly component that is being encoded.
///
/// Sections within a WebAssembly module are encoded in a specific order.
///
/// Modules may also added as a section to a WebAssembly component.
#[derive(Clone, Debug)]
pub struct Module {
pub(crate) bytes: Vec<u8>,
}
impl Module {
/// Begin writing a new `Module`.
#[rustfmt::skip]
pub fn new() -> Self {
Module {
bytes: vec![
// Magic
0x00, 0x61, 0x73, 0x6D,
// Version
0x01, 0x00, 0x00, 0x00,
],
}
}
/// Write a section into this module.
///
/// It is your responsibility to define the sections in the [proper
/// order](https://webassembly.github.io/spec/core/binary/modules.html#binary-module),
/// and to ensure that each kind of section (other than custom sections) is
/// only defined once. While this is a potential footgun, it also allows you
/// to use this crate to easily construct test cases for bad Wasm module
/// encodings.
pub fn section(&mut self, section: &impl Section) -> &mut Self {
self.bytes.push(section.id());
section.encode(&mut self.bytes);
self
}
/// Get the encoded Wasm module as a slice.
pub fn as_slice(&self) -> &[u8] {
&self.bytes
}
/// Finish writing this Wasm module and extract ownership of the encoded
/// bytes.
pub fn finish(self) -> Vec<u8> {
self.bytes
}
}
impl Default for Module {
fn default() -> Self {
Self::new()
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
use super::*;
use crate::{encoding_size, Encode, Section, SectionId};
/// A custom section holding arbitrary data.
#[derive(Clone, Debug)]
@ -9,25 +9,19 @@ pub struct CustomSection<'a> {
pub data: &'a [u8],
}
impl Encode for CustomSection<'_> {
fn encode(&self, sink: &mut Vec<u8>) {
let encoded_name_len = encoding_size(u32::try_from(self.name.len()).unwrap());
(encoded_name_len + self.name.len() + self.data.len()).encode(sink);
self.name.encode(sink);
sink.extend(self.data);
}
}
impl Section for CustomSection<'_> {
fn id(&self) -> u8 {
SectionId::Custom.into()
}
fn encode<S>(&self, sink: &mut S)
where
S: Extend<u8>,
{
let name_len = encoders::u32(u32::try_from(self.name.len()).unwrap());
let n = name_len.len();
sink.extend(
encoders::u32(u32::try_from(n + self.name.len() + self.data.len()).unwrap())
.chain(name_len)
.chain(self.name.as_bytes().iter().copied())
.chain(self.data.iter().copied()),
);
}
}
#[cfg(test)]

View File

@ -1,7 +1,9 @@
use super::*;
use crate::{encode_section, encoding_size, Encode, Instruction, Section, SectionId};
/// An encoder for the data section.
///
/// Data sections are only supported for modules.
///
/// # Example
///
/// ```
@ -15,13 +17,14 @@ use super::*;
/// minimum: 1,
/// maximum: None,
/// memory64: false,
/// shared: false,
/// });
///
/// let mut data = DataSection::new();
/// let memory_index = 0;
/// let offset = Instruction::I32Const(42);
/// let segment_data = b"hello";
/// data.active(memory_index, offset, segment_data.iter().copied());
/// data.active(memory_index, &offset, segment_data.iter().copied());
///
/// let mut module = Module::new();
/// module
@ -30,14 +33,14 @@ use super::*;
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Debug)]
#[derive(Clone, Default, Debug)]
pub struct DataSection {
bytes: Vec<u8>,
num_added: u32,
}
/// A segment in the data section.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Debug)]
pub struct DataSegment<'a, D> {
/// This data segment's mode.
pub mode: DataSegmentMode<'a>,
@ -46,14 +49,14 @@ pub struct DataSegment<'a, D> {
}
/// A data segment's mode.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Debug)]
pub enum DataSegmentMode<'a> {
/// An active data segment.
Active {
/// The memory this segment applies to.
memory_index: u32,
/// The offset where this segment's data is initialized at.
offset: Instruction<'a>,
offset: &'a Instruction<'a>,
},
/// A passive data segment.
///
@ -63,19 +66,21 @@ pub enum DataSegmentMode<'a> {
impl DataSection {
/// Create a new data section encoder.
pub fn new() -> DataSection {
DataSection {
bytes: vec![],
num_added: 0,
}
pub fn new() -> Self {
Self::default()
}
/// How many segments have been defined inside this section so far?
/// The number of data segments in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Define an active data segment.
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define a data segment.
pub fn segment<D>(&mut self, segment: DataSegment<D>) -> &mut Self
where
D: IntoIterator<Item = u8>,
@ -98,15 +103,14 @@ impl DataSection {
offset,
} => {
self.bytes.push(0x02);
self.bytes.extend(encoders::u32(memory_index));
memory_index.encode(&mut self.bytes);
offset.encode(&mut self.bytes);
Instruction::End.encode(&mut self.bytes);
}
}
let data = segment.data.into_iter();
self.bytes
.extend(encoders::u32(u32::try_from(data.len()).unwrap()));
data.len().encode(&mut self.bytes);
self.bytes.extend(data);
self.num_added += 1;
@ -114,12 +118,7 @@ impl DataSection {
}
/// Define an active data segment.
pub fn active<'a, D>(
&mut self,
memory_index: u32,
offset: Instruction<'a>,
data: D,
) -> &mut Self
pub fn active<D>(&mut self, memory_index: u32, offset: &Instruction, data: D) -> &mut Self
where
D: IntoIterator<Item = u8>,
D::IntoIter: ExactSizeIterator,
@ -136,7 +135,7 @@ impl DataSection {
/// Define a passive data segment.
///
/// Passive data segments are part of the bulk memory proposal.
pub fn passive<'a, D>(&mut self, data: D) -> &mut Self
pub fn passive<D>(&mut self, data: D) -> &mut Self
where
D: IntoIterator<Item = u8>,
D::IntoIter: ExactSizeIterator,
@ -146,25 +145,25 @@ impl DataSection {
data,
})
}
/// Copy an already-encoded data segment into this data section.
pub fn raw(&mut self, already_encoded_data_segment: &[u8]) -> &mut Self {
self.bytes.extend_from_slice(already_encoded_data_segment);
self.num_added += 1;
self
}
}
impl Encode for DataSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl Section for DataSection {
fn id(&self) -> u8 {
SectionId::Data.into()
}
fn encode<S>(&self, sink: &mut S)
where
S: Extend<u8>,
{
let num_added = encoders::u32(self.num_added);
let n = num_added.len();
sink.extend(
encoders::u32(u32::try_from(n + self.bytes.len()).unwrap())
.chain(num_added)
.chain(self.bytes.iter().copied()),
);
}
}
/// An encoder for the data count section.
@ -174,17 +173,15 @@ pub struct DataCountSection {
pub count: u32,
}
impl Encode for DataCountSection {
fn encode(&self, sink: &mut Vec<u8>) {
encoding_size(self.count).encode(sink);
self.count.encode(sink);
}
}
impl Section for DataCountSection {
fn id(&self) -> u8 {
SectionId::DataCount.into()
}
fn encode<S>(&self, sink: &mut S)
where
S: Extend<u8>,
{
let count = encoders::u32(self.count);
let n = count.len();
sink.extend(encoders::u32(u32::try_from(n).unwrap()).chain(count));
}
}

View File

@ -1,7 +1,9 @@
use super::*;
use crate::{encode_section, Encode, Instruction, Section, SectionId, ValType};
/// An encoder for the element section.
///
/// Element sections are only supported for modules.
///
/// # Example
///
/// ```
@ -24,7 +26,7 @@ use super::*;
/// let functions = Elements::Functions(&[
/// // Function indices...
/// ]);
/// elements.active(Some(table_index), offset, element_type, functions);
/// elements.active(Some(table_index), &offset, element_type, functions);
///
/// let mut module = Module::new();
/// module
@ -33,7 +35,7 @@ use super::*;
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Debug)]
#[derive(Clone, Default, Debug)]
pub struct ElementSection {
bytes: Vec<u8>,
num_added: u32,
@ -58,7 +60,7 @@ pub enum Element {
}
/// An element segment's mode.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Debug)]
pub enum ElementMode<'a> {
/// A passive element segment.
///
@ -72,16 +74,17 @@ pub enum ElementMode<'a> {
Active {
/// The table index.
///
/// `None` is implicitly table `0`. Non-`None` tables are part of the
/// reference types proposal.
/// `Active` element specifying a `None` table forces the MVP encoding and refers to the
/// 0th table holding `funcref`s. Non-`None` tables use the encoding introduced with the
/// bulk memory proposal and can refer to tables with any valid reference type.
table: Option<u32>,
/// The offset within the table to place this segment.
offset: Instruction<'a>,
offset: &'a Instruction<'a>,
},
}
/// An element segment in the element section.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Debug)]
pub struct ElementSegment<'a> {
/// The element segment's mode.
pub mode: ElementMode<'a>,
@ -93,75 +96,73 @@ pub struct ElementSegment<'a> {
impl ElementSection {
/// Create a new element section encoder.
pub fn new() -> ElementSection {
ElementSection {
bytes: vec![],
num_added: 0,
}
pub fn new() -> Self {
Self::default()
}
/// How many segments have been defined inside this section so far?
/// The number of element segments in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define an element segment.
pub fn segment<'a>(&mut self, segment: ElementSegment<'a>) -> &mut Self {
let expr_bit = match segment.elements {
Elements::Expressions(_) => 0b100,
Elements::Functions(_) => 0b000,
Elements::Expressions(_) => 0b100u32,
Elements::Functions(_) => 0b000u32,
};
match &segment.mode {
ElementMode::Active {
table: None,
offset,
} => {
self.bytes.extend(encoders::u32(0x00 | expr_bit));
(/* 0x00 | */expr_bit).encode(&mut self.bytes);
offset.encode(&mut self.bytes);
Instruction::End.encode(&mut self.bytes);
}
ElementMode::Passive => {
self.bytes.extend(encoders::u32(0x01 | expr_bit));
(0x01 | expr_bit).encode(&mut self.bytes);
if expr_bit == 0 {
self.bytes.push(0x00); // elemkind == funcref
} else {
self.bytes.push(segment.element_type.into());
segment.element_type.encode(&mut self.bytes);
}
}
ElementMode::Active {
table: Some(i),
offset,
} => {
self.bytes.extend(encoders::u32(0x02 | expr_bit));
self.bytes.extend(encoders::u32(*i));
(0x02 | expr_bit).encode(&mut self.bytes);
i.encode(&mut self.bytes);
offset.encode(&mut self.bytes);
Instruction::End.encode(&mut self.bytes);
if expr_bit == 0 {
self.bytes.push(0x00); // elemkind == funcref
} else {
self.bytes.push(segment.element_type.into());
segment.element_type.encode(&mut self.bytes);
}
}
ElementMode::Declared => {
self.bytes.extend(encoders::u32(0x03 | expr_bit));
(0x03 | expr_bit).encode(&mut self.bytes);
if expr_bit == 0 {
self.bytes.push(0x00); // elemkind == funcref
} else {
self.bytes.push(segment.element_type.into());
segment.element_type.encode(&mut self.bytes);
}
}
}
match segment.elements {
Elements::Functions(fs) => {
self.bytes
.extend(encoders::u32(u32::try_from(fs.len()).unwrap()));
for f in fs {
self.bytes.extend(encoders::u32(*f));
}
fs.encode(&mut self.bytes);
}
Elements::Expressions(e) => {
self.bytes.extend(encoders::u32(e.len() as u32));
e.len().encode(&mut self.bytes);
for expr in e {
match expr {
Element::Func(i) => Instruction::RefFunc(*i).encode(&mut self.bytes),
@ -179,12 +180,16 @@ impl ElementSection {
}
/// Define an active element segment.
pub fn active<'a>(
///
/// `Active` element specifying a `None` table forces the MVP encoding and refers to the 0th
/// table holding `funcref`s. Non-`None` tables use the encoding introduced with the bulk
/// memory proposal and can refer to tables with any valid reference type.
pub fn active(
&mut self,
table_index: Option<u32>,
offset: Instruction,
offset: &Instruction<'_>,
element_type: ValType,
elements: Elements<'a>,
elements: Elements<'_>,
) -> &mut Self {
self.segment(ElementSegment {
mode: ElementMode::Active {
@ -217,23 +222,23 @@ impl ElementSection {
elements,
})
}
/// Copy a raw, already-encoded element segment into this elements section.
pub fn raw(&mut self, raw_bytes: &[u8]) -> &mut Self {
self.bytes.extend_from_slice(raw_bytes);
self.num_added += 1;
self
}
}
impl Encode for ElementSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl Section for ElementSection {
fn id(&self) -> u8 {
SectionId::Element.into()
}
fn encode<S>(&self, sink: &mut S)
where
S: Extend<u8>,
{
let num_added = encoders::u32(self.num_added);
let n = num_added.len();
sink.extend(
encoders::u32(u32::try_from(n + self.bytes.len()).unwrap())
.chain(num_added)
.chain(self.bytes.iter().copied()),
);
}
}

View File

@ -0,0 +1,90 @@
use super::{
CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_MEMORY_SORT, CORE_TABLE_SORT, CORE_TAG_SORT,
};
use crate::{encode_section, Encode, Section, SectionId};
/// Represents the kind of an export from a WebAssembly module.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ExportKind {
/// The export is a function.
Func,
/// The export is a table.
Table,
/// The export is a memory.
Memory,
/// The export is a global.
Global,
/// The export is a tag.
Tag,
}
impl Encode for ExportKind {
fn encode(&self, sink: &mut Vec<u8>) {
sink.push(match self {
Self::Func => CORE_FUNCTION_SORT,
Self::Table => CORE_TABLE_SORT,
Self::Memory => CORE_MEMORY_SORT,
Self::Global => CORE_GLOBAL_SORT,
Self::Tag => CORE_TAG_SORT,
});
}
}
/// An encoder for the export section of WebAssembly module.
///
/// # Example
///
/// ```rust
/// use wasm_encoder::{Module, ExportSection, ExportKind};
///
/// let mut exports = ExportSection::new();
/// exports.export("foo", ExportKind::Func, 0);
///
/// let mut module = Module::new();
/// module.section(&exports);
///
/// let bytes = module.finish();
/// ```
#[derive(Clone, Debug, Default)]
pub struct ExportSection {
bytes: Vec<u8>,
num_added: u32,
}
impl ExportSection {
/// Create a new export section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of exports in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define an export in the export section.
pub fn export(&mut self, name: &str, kind: ExportKind, index: u32) -> &mut Self {
name.encode(&mut self.bytes);
kind.encode(&mut self.bytes);
index.encode(&mut self.bytes);
self.num_added += 1;
self
}
}
impl Encode for ExportSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl Section for ExportSection {
fn id(&self) -> u8 {
SectionId::Export.into()
}
}

View File

@ -1,6 +1,6 @@
use super::*;
use crate::{encode_section, Encode, Section, SectionId};
/// An encoder for the function section.
/// An encoder for the function section of WebAssembly modules.
///
/// # Example
///
@ -18,51 +18,46 @@ use super::*;
/// // code section containing the function body. See the documentation for
/// // `CodeSection` for details.
///
/// let wasm_bytes = module.finish();
/// let bytes = module.finish();
/// ```
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Default)]
pub struct FunctionSection {
bytes: Vec<u8>,
num_added: u32,
}
impl FunctionSection {
/// Construct a new function section encoder.
pub fn new() -> FunctionSection {
FunctionSection {
bytes: vec![],
num_added: 0,
}
/// Construct a new module function section encoder.
pub fn new() -> Self {
Self::default()
}
/// How many functions have been defined inside this section so far?
/// The number of functions in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Define a function that uses the given type.
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define a function in a module's function section.
pub fn function(&mut self, type_index: u32) -> &mut Self {
self.bytes.extend(encoders::u32(type_index));
type_index.encode(&mut self.bytes);
self.num_added += 1;
self
}
}
impl Encode for FunctionSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl Section for FunctionSection {
fn id(&self) -> u8 {
SectionId::Function.into()
}
fn encode<S>(&self, sink: &mut S)
where
S: Extend<u8>,
{
let num_added = encoders::u32(self.num_added);
let n = num_added.len();
sink.extend(
encoders::u32(u32::try_from(n + self.bytes.len()).unwrap())
.chain(num_added)
.chain(self.bytes.iter().copied()),
);
}
}

View File

@ -1,7 +1,9 @@
use super::*;
use crate::{encode_section, Encode, Instruction, Section, SectionId, ValType};
/// An encoder for the global section.
///
/// Global sections are only supported for modules.
///
/// # Example
///
/// ```
@ -13,7 +15,7 @@ use super::*;
/// val_type: ValType::I32,
/// mutable: false,
/// },
/// Instruction::I32Const(42),
/// &Instruction::I32Const(42),
/// );
///
/// let mut module = Module::new();
@ -21,7 +23,7 @@ use super::*;
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Debug)]
#[derive(Clone, Default, Debug)]
pub struct GlobalSection {
bytes: Vec<u8>,
num_added: u32,
@ -29,49 +31,51 @@ pub struct GlobalSection {
impl GlobalSection {
/// Create a new global section encoder.
pub fn new() -> GlobalSection {
GlobalSection {
bytes: vec![],
num_added: 0,
}
pub fn new() -> Self {
Self::default()
}
/// How many globals have been defined inside this section so far?
/// The number of globals in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define a global.
pub fn global(&mut self, global_type: GlobalType, init_expr: Instruction) -> &mut Self {
pub fn global(&mut self, global_type: GlobalType, init_expr: &Instruction<'_>) -> &mut Self {
global_type.encode(&mut self.bytes);
init_expr.encode(&mut self.bytes);
Instruction::End.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Add a raw byte slice into this code section as a global.
pub fn raw(&mut self, data: &[u8]) -> &mut Self {
self.bytes.extend(data);
self.num_added += 1;
self
}
}
impl Encode for GlobalSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl Section for GlobalSection {
fn id(&self) -> u8 {
SectionId::Global.into()
}
fn encode<S>(&self, sink: &mut S)
where
S: Extend<u8>,
{
let num_added = encoders::u32(self.num_added);
let n = num_added.len();
sink.extend(
encoders::u32(u32::try_from(n + self.bytes.len()).unwrap())
.chain(num_added)
.chain(self.bytes.iter().copied()),
);
}
}
/// A global's type.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct GlobalType {
/// This global's value type.
pub val_type: ValType,
@ -79,9 +83,9 @@ pub struct GlobalType {
pub mutable: bool,
}
impl GlobalType {
pub(crate) fn encode(&self, bytes: &mut Vec<u8>) {
bytes.push(self.val_type.into());
bytes.push(self.mutable as u8);
impl Encode for GlobalType {
fn encode(&self, sink: &mut Vec<u8>) {
self.val_type.encode(sink);
sink.push(self.mutable as u8);
}
}

View File

@ -0,0 +1,142 @@
use crate::{
encode_section, Encode, GlobalType, MemoryType, Section, SectionId, TableType, TagType,
CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_MEMORY_SORT, CORE_TABLE_SORT, CORE_TAG_SORT,
};
/// The type of an entity.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EntityType {
/// A function type.
///
/// The value is an index into the types section.
Function(u32),
/// A table type.
Table(TableType),
/// A memory type.
Memory(MemoryType),
/// A global type.
Global(GlobalType),
/// A tag type.
///
/// This variant is used with the exception handling proposal.
Tag(TagType),
}
impl Encode for EntityType {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
Self::Function(i) => {
sink.push(CORE_FUNCTION_SORT);
i.encode(sink);
}
Self::Table(t) => {
sink.push(CORE_TABLE_SORT);
t.encode(sink);
}
Self::Memory(t) => {
sink.push(CORE_MEMORY_SORT);
t.encode(sink);
}
Self::Global(t) => {
sink.push(CORE_GLOBAL_SORT);
t.encode(sink);
}
Self::Tag(t) => {
sink.push(CORE_TAG_SORT);
t.encode(sink);
}
}
}
}
impl From<TableType> for EntityType {
fn from(t: TableType) -> Self {
Self::Table(t)
}
}
impl From<MemoryType> for EntityType {
fn from(t: MemoryType) -> Self {
Self::Memory(t)
}
}
impl From<GlobalType> for EntityType {
fn from(t: GlobalType) -> Self {
Self::Global(t)
}
}
impl From<TagType> for EntityType {
fn from(t: TagType) -> Self {
Self::Tag(t)
}
}
/// An encoder for the import section of WebAssembly modules.
///
/// # Example
///
/// ```rust
/// use wasm_encoder::{MemoryType, Module, ImportSection};
///
/// let mut imports = ImportSection::new();
/// imports.import(
/// "env",
/// "memory",
/// MemoryType {
/// minimum: 1,
/// maximum: None,
/// memory64: false,
/// shared: false,
/// }
/// );
///
/// let mut module = Module::new();
/// module.section(&imports);
///
/// let bytes = module.finish();
/// ```
#[derive(Clone, Debug, Default)]
pub struct ImportSection {
bytes: Vec<u8>,
num_added: u32,
}
impl ImportSection {
/// Create a new import section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of imports in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define an import in the import section.
pub fn import(&mut self, module: &str, field: &str, ty: impl Into<EntityType>) -> &mut Self {
module.encode(&mut self.bytes);
field.encode(&mut self.bytes);
ty.into().encode(&mut self.bytes);
self.num_added += 1;
self
}
}
impl Encode for ImportSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl Section for ImportSection {
fn id(&self) -> u8 {
SectionId::Import.into()
}
}

View File

@ -1,5 +1,6 @@
use super::*;
use std::convert::TryInto;
use crate::{encode_section, CustomSection, Encode, Section, SectionId};
const VERSION: u32 = 2;
/// An encoder for the [linking custom
/// section](https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md#linking-metadata-section).
@ -44,7 +45,7 @@ pub struct LinkingSection {
impl LinkingSection {
/// Construct a new encoder for the linking custom section.
pub fn new() -> Self {
LinkingSection { bytes: vec![] }
Self::default()
}
// TODO: `fn segment_info` for the `WASM_SEGMENT_INFO` linking subsection.
@ -60,30 +61,28 @@ impl LinkingSection {
}
}
impl Default for LinkingSection {
fn default() -> Self {
let mut bytes = Vec::new();
VERSION.encode(&mut bytes);
Self { bytes }
}
}
impl Encode for LinkingSection {
fn encode(&self, sink: &mut Vec<u8>) {
CustomSection {
name: "linking",
data: &self.bytes,
}
.encode(sink);
}
}
impl Section for LinkingSection {
fn id(&self) -> u8 {
SectionId::Custom.into()
}
fn encode<S>(&self, sink: &mut S)
where
S: Extend<u8>,
{
let name_len = encoders::u32(u32::try_from("linking".len()).unwrap());
let name_len_len = name_len.len();
let version = 2;
sink.extend(
encoders::u32(
u32::try_from(name_len_len + "linking".len() + 1 + self.bytes.len()).unwrap(),
)
.chain(name_len)
.chain(b"linking".iter().copied())
.chain(encoders::u32(version))
.chain(self.bytes.iter().copied()),
);
}
}
#[allow(unused)]
@ -97,7 +96,7 @@ const WASM_SYMBOL_TABLE: u8 = 8;
/// A subsection of the [linking custom section][crate::LinkingSection] that
/// provides extra information about the symbols present in this Wasm object
/// file.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Default)]
pub struct SymbolTable {
bytes: Vec<u8>,
num_added: u32,
@ -126,16 +125,11 @@ impl SymbolTable {
/// The `name` must be omitted if `index` references an imported table and
/// the `WASM_SYM_EXPLICIT_NAME` flag is not set.
pub fn function(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self {
self.bytes.extend(
encoders::u32(SYMTAB_FUNCTION)
.chain(encoders::u32(flags))
.chain(encoders::u32(index)),
);
SYMTAB_FUNCTION.encode(&mut self.bytes);
flags.encode(&mut self.bytes);
index.encode(&mut self.bytes);
if let Some(name) = name {
self.bytes.extend(
encoders::u32(name.len().try_into().unwrap())
.chain(name.as_bytes().iter().copied()),
);
name.encode(&mut self.bytes);
}
self.num_added += 1;
self
@ -146,16 +140,11 @@ impl SymbolTable {
/// The `name` must be omitted if `index` references an imported table and
/// the `WASM_SYM_EXPLICIT_NAME` flag is not set.
pub fn global(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self {
self.bytes.extend(
encoders::u32(SYMTAB_GLOBAL)
.chain(encoders::u32(flags))
.chain(encoders::u32(index)),
);
SYMTAB_GLOBAL.encode(&mut self.bytes);
flags.encode(&mut self.bytes);
index.encode(&mut self.bytes);
if let Some(name) = name {
self.bytes.extend(
encoders::u32(name.len().try_into().unwrap())
.chain(name.as_bytes().iter().copied()),
);
name.encode(&mut self.bytes);
}
self.num_added += 1;
self
@ -168,16 +157,11 @@ impl SymbolTable {
/// The `name` must be omitted if `index` references an imported table and
/// the `WASM_SYM_EXPLICIT_NAME` flag is not set.
pub fn table(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self {
self.bytes.extend(
encoders::u32(SYMTAB_TABLE)
.chain(encoders::u32(flags))
.chain(encoders::u32(index)),
);
SYMTAB_TABLE.encode(&mut self.bytes);
flags.encode(&mut self.bytes);
index.encode(&mut self.bytes);
if let Some(name) = name {
self.bytes.extend(
encoders::u32(name.len().try_into().unwrap())
.chain(name.as_bytes().iter().copied()),
);
name.encode(&mut self.bytes);
}
self.num_added += 1;
self
@ -190,18 +174,13 @@ impl SymbolTable {
name: &str,
definition: Option<DataSymbolDefinition>,
) -> &mut Self {
self.bytes.extend(
encoders::u32(SYMTAB_DATA)
.chain(encoders::u32(flags))
.chain(encoders::u32(name.len().try_into().unwrap()))
.chain(name.as_bytes().iter().copied()),
);
SYMTAB_DATA.encode(&mut self.bytes);
flags.encode(&mut self.bytes);
name.encode(&mut self.bytes);
if let Some(def) = definition {
self.bytes.extend(
encoders::u32(def.index)
.chain(encoders::u32(def.offset))
.chain(encoders::u32(def.size)),
);
def.index.encode(&mut self.bytes);
def.offset.encode(&mut self.bytes);
def.size.encode(&mut self.bytes);
}
self.num_added += 1;
self
@ -209,21 +188,6 @@ impl SymbolTable {
// TODO: sections
fn encode(&self, bytes: &mut Vec<u8>) {
let num_added = encoders::u32(self.num_added);
let num_added_len = num_added.len();
let payload_len = num_added_len + self.bytes.len();
bytes.extend(
std::iter::once(WASM_SYMBOL_TABLE)
.chain(encoders::u32(payload_len.try_into().unwrap()))
.chain(num_added)
.chain(self.bytes.iter().copied()),
);
}
}
/// # Symbol definition flags.
impl SymbolTable {
/// This is a weak symbol.
///
/// This flag is mutually exclusive with `WASM_SYM_BINDING_LOCAL`.
@ -275,6 +239,13 @@ impl SymbolTable {
pub const WASM_SYM_NO_STRIP: u32 = 0x80;
}
impl Encode for SymbolTable {
fn encode(&self, sink: &mut Vec<u8>) {
sink.push(WASM_SYMBOL_TABLE);
encode_section(sink, self.num_added, &self.bytes);
}
}
/// The definition of a data symbol within a symbol table.
#[derive(Clone, Debug)]
pub struct DataSymbolDefinition {

View File

@ -1,7 +1,9 @@
use super::*;
use crate::{encode_section, Encode, Section, SectionId};
/// An encoder for the memory section.
///
/// Memory sections are only supported for modules.
///
/// # Example
///
/// ```
@ -12,6 +14,7 @@ use super::*;
/// minimum: 1,
/// maximum: None,
/// memory64: false,
/// shared: false,
/// });
///
/// let mut module = Module::new();
@ -19,7 +22,7 @@ use super::*;
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Debug)]
#[derive(Clone, Default, Debug)]
pub struct MemorySection {
bytes: Vec<u8>,
num_added: u32,
@ -27,18 +30,20 @@ pub struct MemorySection {
impl MemorySection {
/// Create a new memory section encoder.
pub fn new() -> MemorySection {
MemorySection {
bytes: vec![],
num_added: 0,
}
pub fn new() -> Self {
Self::default()
}
/// How many memories have been defined inside this section so far?
/// The number of memories in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define a memory.
pub fn memory(&mut self, memory_type: MemoryType) -> &mut Self {
memory_type.encode(&mut self.bytes);
@ -47,27 +52,20 @@ impl MemorySection {
}
}
impl Encode for MemorySection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl Section for MemorySection {
fn id(&self) -> u8 {
SectionId::Memory.into()
}
fn encode<S>(&self, sink: &mut S)
where
S: Extend<u8>,
{
let num_added = encoders::u32(self.num_added);
let n = num_added.len();
sink.extend(
encoders::u32(u32::try_from(n + self.bytes.len()).unwrap())
.chain(num_added)
.chain(self.bytes.iter().copied()),
);
}
}
/// A memory's type.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct MemoryType {
/// Minimum size, in pages, of this memory
pub minimum: u64,
@ -75,21 +73,27 @@ pub struct MemoryType {
pub maximum: Option<u64>,
/// Whether or not this is a 64-bit memory.
pub memory64: bool,
/// Whether or not this memory is shared.
pub shared: bool,
}
impl MemoryType {
pub(crate) fn encode(&self, bytes: &mut Vec<u8>) {
impl Encode for MemoryType {
fn encode(&self, sink: &mut Vec<u8>) {
let mut flags = 0;
if self.maximum.is_some() {
flags |= 0b001;
}
if self.shared {
flags |= 0b010;
}
if self.memory64 {
flags |= 0b100;
}
bytes.push(flags);
bytes.extend(encoders::u64(self.minimum));
sink.push(flags);
self.minimum.encode(sink);
if let Some(max) = self.maximum {
bytes.extend(encoders::u64(max));
max.encode(sink);
}
}
}

View File

@ -0,0 +1,254 @@
use crate::{encoding_size, CustomSection, Encode, Section, SectionId};
/// An encoder for the custom `name` section.
///
/// # Example
///
/// ```
/// use wasm_encoder::{Module, NameSection, NameMap};
///
/// let mut names = NameSection::new();
/// names.module("the module name");
///
/// let mut function_names = NameMap::new();
/// function_names.append(0, "name of function 0");
/// function_names.append(1, "a better function");
/// function_names.append(3, "the best function");
/// names.functions(&function_names);
///
/// let mut module = Module::new();
/// module.section(&names);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Debug, Default)]
pub struct NameSection {
bytes: Vec<u8>,
}
enum Subsection {
// Currently specified in the wasm spec's appendix
Module = 0,
Function = 1,
Local = 2,
// specified as part of the extended name section proposal
//
// https://github.com/WebAssembly/extended-name-section/blob/main/proposals/extended-name-section/Overview.md
Label = 3,
Type = 4,
Table = 5,
Memory = 6,
Global = 7,
Element = 8,
Data = 9,
}
impl NameSection {
/// Creates a new blank `name` custom section.
pub fn new() -> Self {
Self::default()
}
/// Appends a module name subsection to this section.
///
/// This will indicate that the name of the entire module should be the
/// `name` specified. Note that this should be encoded first before other
/// subsections.
pub fn module(&mut self, name: &str) {
let len = encoding_size(u32::try_from(name.len()).unwrap());
self.subsection_header(Subsection::Module, len + name.len());
name.encode(&mut self.bytes);
}
/// Appends a subsection for the names of all functions in this wasm module.
///
/// Function names are declared in the `names` map provided where the index
/// in the map corresponds to the wasm index of the function. This section
/// should come after the module name subsection (if present) and before the
/// locals subsection (if present).
pub fn functions(&mut self, names: &NameMap) {
self.subsection_header(Subsection::Function, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of locals within functions in the
/// wasm module.
///
/// This section should come after the function name subsection (if present)
/// and before the labels subsection (if present).
pub fn locals(&mut self, names: &IndirectNameMap) {
self.subsection_header(Subsection::Local, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of labels within functions in the
/// wasm module.
///
/// This section should come after the local name subsection (if present)
/// and before the type subsection (if present).
pub fn labels(&mut self, names: &IndirectNameMap) {
self.subsection_header(Subsection::Label, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of all types in this wasm module.
///
/// This section should come after the label name subsection (if present)
/// and before the table subsection (if present).
pub fn types(&mut self, names: &NameMap) {
self.subsection_header(Subsection::Type, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of all tables in this wasm module.
///
/// This section should come after the type name subsection (if present)
/// and before the memory subsection (if present).
pub fn tables(&mut self, names: &NameMap) {
self.subsection_header(Subsection::Table, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of all memories in this wasm module.
///
/// This section should come after the table name subsection (if present)
/// and before the global subsection (if present).
pub fn memories(&mut self, names: &NameMap) {
self.subsection_header(Subsection::Memory, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of all globals in this wasm module.
///
/// This section should come after the memory name subsection (if present)
/// and before the element subsection (if present).
pub fn globals(&mut self, names: &NameMap) {
self.subsection_header(Subsection::Global, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of all elements in this wasm module.
///
/// This section should come after the global name subsection (if present)
/// and before the data subsection (if present).
pub fn elements(&mut self, names: &NameMap) {
self.subsection_header(Subsection::Element, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of all data in this wasm module.
///
/// This section should come after the element name subsection (if present).
pub fn data(&mut self, names: &NameMap) {
self.subsection_header(Subsection::Data, names.size());
names.encode(&mut self.bytes);
}
fn subsection_header(&mut self, id: Subsection, len: usize) {
self.bytes.push(id as u8);
len.encode(&mut self.bytes);
}
}
impl Encode for NameSection {
fn encode(&self, sink: &mut Vec<u8>) {
CustomSection {
name: "name",
data: &self.bytes,
}
.encode(sink);
}
}
impl Section for NameSection {
fn id(&self) -> u8 {
SectionId::Custom.into()
}
}
/// A map used to name items in a wasm module, organized by naming each
/// individual index.
///
/// This is used in conjunction with [`NameSection::functions`] and simlar
/// methods.
#[derive(Clone, Debug, Default)]
pub struct NameMap {
bytes: Vec<u8>,
count: u32,
}
impl NameMap {
/// Creates a new empty `NameMap`.
pub fn new() -> NameMap {
NameMap {
bytes: vec![],
count: 0,
}
}
/// Adds a an entry where the item at `idx` has the `name` specified.
///
/// Note that indices should be appended in ascending order of the index
/// value. Each index may only be named once, but not all indices must be
/// named (e.g. `0 foo; 1 bar; 7 qux` is valid but `0 foo; 0 bar` is not).
/// Names do not have to be unique (e.g. `0 foo; 1 foo; 2 foo` is valid).
pub fn append(&mut self, idx: u32, name: &str) {
idx.encode(&mut self.bytes);
name.encode(&mut self.bytes);
self.count += 1;
}
fn size(&self) -> usize {
encoding_size(self.count) + self.bytes.len()
}
}
impl Encode for NameMap {
fn encode(&self, sink: &mut Vec<u8>) {
self.count.encode(sink);
sink.extend(&self.bytes);
}
}
/// A map used to describe names with two levels of indirection, as opposed to a
/// [`NameMap`] which has one level of indirection.
///
/// This naming map is used with [`NameSection::locals`], for example.
#[derive(Clone, Debug, Default)]
pub struct IndirectNameMap {
bytes: Vec<u8>,
count: u32,
}
impl IndirectNameMap {
/// Creates a new empty name map.
pub fn new() -> IndirectNameMap {
IndirectNameMap {
bytes: vec![],
count: 0,
}
}
/// Adds a new entry where the item at `idx` has sub-items named within
/// `names` as specified.
///
/// For example if this is describing local names then `idx` is a function
/// index where the indexes within `names` are local indices.
pub fn append(&mut self, idx: u32, names: &NameMap) {
idx.encode(&mut self.bytes);
names.encode(&mut self.bytes);
self.count += 1;
}
fn size(&self) -> usize {
encoding_size(self.count) + self.bytes.len()
}
}
impl Encode for IndirectNameMap {
fn encode(&self, sink: &mut Vec<u8>) {
self.count.encode(sink);
sink.extend(&self.bytes);
}
}

View File

@ -1,6 +1,6 @@
use super::*;
use crate::{encoding_size, Encode, Section, SectionId};
/// An encoder for the start section.
/// An encoder for the start section of WebAssembly modules.
///
/// # Example
///
@ -25,17 +25,15 @@ pub struct StartSection {
pub function_index: u32,
}
impl Encode for StartSection {
fn encode(&self, sink: &mut Vec<u8>) {
encoding_size(self.function_index).encode(sink);
self.function_index.encode(sink);
}
}
impl Section for StartSection {
fn id(&self) -> u8 {
SectionId::Start.into()
}
fn encode<S>(&self, sink: &mut S)
where
S: Extend<u8>,
{
let f = encoders::u32(self.function_index);
let n = f.len();
sink.extend(encoders::u32(n as u32).chain(f));
}
}

View File

@ -1,7 +1,9 @@
use super::*;
use crate::{encode_section, Encode, Section, SectionId, ValType};
/// An encoder for the table section.
///
/// Table sections are only supported for modules.
///
/// # Example
///
/// ```
@ -19,7 +21,7 @@ use super::*;
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Debug)]
#[derive(Clone, Default, Debug)]
pub struct TableSection {
bytes: Vec<u8>,
num_added: u32,
@ -27,18 +29,20 @@ pub struct TableSection {
impl TableSection {
/// Construct a new table section encoder.
pub fn new() -> TableSection {
TableSection {
bytes: vec![],
num_added: 0,
}
pub fn new() -> Self {
Self::default()
}
/// How many tables have been defined inside this section so far?
/// The number of tables in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define a table.
pub fn table(&mut self, table_type: TableType) -> &mut Self {
table_type.encode(&mut self.bytes);
@ -47,27 +51,20 @@ impl TableSection {
}
}
impl Encode for TableSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl Section for TableSection {
fn id(&self) -> u8 {
SectionId::Table.into()
}
fn encode<S>(&self, sink: &mut S)
where
S: Extend<u8>,
{
let num_added = encoders::u32(self.num_added);
let n = num_added.len();
sink.extend(
encoders::u32(u32::try_from(n + self.bytes.len()).unwrap())
.chain(num_added)
.chain(self.bytes.iter().copied()),
);
}
}
/// A table's type.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct TableType {
/// The table's element type.
pub element_type: ValType,
@ -77,17 +74,19 @@ pub struct TableType {
pub maximum: Option<u32>,
}
impl TableType {
pub(crate) fn encode(&self, bytes: &mut Vec<u8>) {
bytes.push(self.element_type.into());
impl Encode for TableType {
fn encode(&self, sink: &mut Vec<u8>) {
let mut flags = 0;
if self.maximum.is_some() {
flags |= 0b001;
}
bytes.push(flags);
bytes.extend(encoders::u32(self.minimum));
self.element_type.encode(sink);
sink.push(flags);
self.minimum.encode(sink);
if let Some(max) = self.maximum {
bytes.extend(encoders::u32(max));
max.encode(sink);
}
}
}

View File

@ -1,5 +1,4 @@
use super::*;
use std::convert::TryFrom;
use crate::{encode_section, Encode, Section, SectionId};
/// An encoder for the tag section.
///
@ -19,7 +18,7 @@ use std::convert::TryFrom;
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Debug)]
#[derive(Clone, Default, Debug)]
pub struct TagSection {
bytes: Vec<u8>,
num_added: u32,
@ -27,18 +26,20 @@ pub struct TagSection {
impl TagSection {
/// Create a new tag section encoder.
pub fn new() -> TagSection {
TagSection {
bytes: vec![],
num_added: 0,
}
pub fn new() -> Self {
Self::default()
}
/// How many tags have been defined inside this section so far?
/// The number of tags in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define a tag.
pub fn tag(&mut self, tag_type: TagType) -> &mut Self {
tag_type.encode(&mut self.bytes);
@ -47,34 +48,28 @@ impl TagSection {
}
}
impl Encode for TagSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl Section for TagSection {
fn id(&self) -> u8 {
SectionId::Tag.into()
}
fn encode<S>(&self, sink: &mut S)
where
S: Extend<u8>,
{
let num_added = encoders::u32(self.num_added);
let n = num_added.len();
sink.extend(
encoders::u32(u32::try_from(n + self.bytes.len()).unwrap())
.chain(num_added)
.chain(self.bytes.iter().copied()),
);
}
}
#[allow(missing_docs)]
/// Represents a tag kind.
#[repr(u8)]
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TagKind {
/// The tag is an exception type.
Exception = 0x0,
}
/// A tag's type.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct TagType {
/// The kind of tag
pub kind: TagKind,
@ -82,9 +77,9 @@ pub struct TagType {
pub func_type_idx: u32,
}
impl TagType {
pub(crate) fn encode(&self, bytes: &mut Vec<u8>) {
bytes.push(self.kind as u8);
bytes.extend(encoders::u32(self.func_type_idx));
impl Encode for TagType {
fn encode(&self, sink: &mut Vec<u8>) {
sink.push(self.kind as u8);
self.func_type_idx.encode(sink);
}
}

View File

@ -0,0 +1,112 @@
use crate::{encode_section, Encode, Section, SectionId};
/// The type of a core WebAssembly value.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
#[repr(u8)]
pub enum ValType {
/// The `i32` type.
I32 = 0x7F,
/// The `i64` type.
I64 = 0x7E,
/// The `f32` type.
F32 = 0x7D,
/// The `f64` type.
F64 = 0x7C,
/// The `v128` type.
///
/// Part of the SIMD proposal.
V128 = 0x7B,
/// The `funcref` type.
///
/// Part of the reference types proposal when used anywhere other than a
/// table's element type.
FuncRef = 0x70,
/// The `externref` type.
///
/// Part of the reference types proposal.
ExternRef = 0x6F,
}
impl From<ValType> for u8 {
#[inline]
fn from(t: ValType) -> u8 {
t as u8
}
}
impl Encode for ValType {
fn encode(&self, sink: &mut Vec<u8>) {
sink.push(*self as u8);
}
}
/// An encoder for the type section of WebAssembly modules.
///
/// # Example
///
/// ```rust
/// use wasm_encoder::{Module, TypeSection, ValType};
///
/// let mut types = TypeSection::new();
///
/// types.function([ValType::I32, ValType::I32], [ValType::I64]);
///
/// let mut module = Module::new();
/// module.section(&types);
///
/// let bytes = module.finish();
/// ```
#[derive(Clone, Debug, Default)]
pub struct TypeSection {
bytes: Vec<u8>,
num_added: u32,
}
impl TypeSection {
/// Create a new module type section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of types in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define a function type in this type section.
pub fn function<P, R>(&mut self, params: P, results: R) -> &mut Self
where
P: IntoIterator<Item = ValType>,
P::IntoIter: ExactSizeIterator,
R: IntoIterator<Item = ValType>,
R::IntoIter: ExactSizeIterator,
{
let params = params.into_iter();
let results = results.into_iter();
self.bytes.push(0x60);
params.len().encode(&mut self.bytes);
self.bytes.extend(params.map(u8::from));
results.len().encode(&mut self.bytes);
self.bytes.extend(results.map(u8::from));
self.num_added += 1;
self
}
}
impl Encode for TypeSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl Section for TypeSection {
fn id(&self) -> u8 {
SectionId::Type.into()
}
}

View File

@ -1,70 +0,0 @@
//! Low-level encoders.
//!
//! This module provides low-level encoders that can be used (for example) to
//! define your own custom section encodings.
use std::convert::TryFrom;
/// Encode a `u32` as a ULEB128.
pub fn u32(n: u32) -> impl ExactSizeIterator<Item = u8> {
let mut buf = [0; 5];
let n = leb128::write::unsigned(&mut &mut buf[..], n.into()).unwrap();
<_>::into_iter(buf).take(n)
}
/// Encode a `u64` as a ULEB128.
pub fn u64(n: u64) -> impl ExactSizeIterator<Item = u8> {
let mut buf = [0; 10];
let n = leb128::write::unsigned(&mut &mut buf[..], n.into()).unwrap();
<_>::into_iter(buf).take(n)
}
/// Encode an `i32` as a SLEB128.
pub fn s32(x: i32) -> impl ExactSizeIterator<Item = u8> {
let mut buf = [0; 5];
let n = leb128::write::signed(&mut &mut buf[..], x.into()).unwrap();
<_>::into_iter(buf).take(n)
}
/// Encode an `i64` that uses at most 33 bits as a SLEB128.
///
/// # Panics
///
/// Panics if more than 33 bits are used.
///
/// ```
/// wasm_encoder::encoders::s33(1 << 32);
/// ```
///
/// ```should_panic
/// wasm_encoder::encoders::s33(1 << 33);
/// ```
///
/// ```
/// wasm_encoder::encoders::s33(-1 << 32);
/// ```
///
/// ```should_panic
/// wasm_encoder::encoders::s33(-1 << 33);
/// ```
pub fn s33(x: i64) -> impl ExactSizeIterator<Item = u8> {
assert!({
let mask = 1 << 33 << 30 >> 30;
x != mask && (x & mask == 0) == (x >= 0)
});
let mut buf = [0; 5];
let n = leb128::write::signed(&mut &mut buf[..], x).unwrap();
<_>::into_iter(buf).take(n)
}
/// Encode an `i64` as a SLEB128.
pub fn s64(x: i64) -> impl ExactSizeIterator<Item = u8> {
let mut buf = [0; 10];
let n = leb128::write::signed(&mut &mut buf[..], x).unwrap();
<_>::into_iter(buf).take(n)
}
/// Encode a length-prefixed UTF-8 string.
pub fn str<'a>(s: &'a str) -> impl Iterator<Item = u8> + 'a {
u32(u32::try_from(s.len()).unwrap()).chain(s.as_bytes().iter().copied())
}

View File

@ -1,154 +0,0 @@
use super::*;
/// An encoder for the export section.
///
/// # Example
///
/// ```
/// use wasm_encoder::{
/// Export, ExportSection, TableSection, TableType, Module, ValType,
/// };
///
/// let mut tables = TableSection::new();
/// tables.table(TableType {
/// element_type: ValType::FuncRef,
/// minimum: 128,
/// maximum: None,
/// });
///
/// let mut exports = ExportSection::new();
/// exports.export("my-table", Export::Table(0));
///
/// let mut module = Module::new();
/// module
/// .section(&tables)
/// .section(&exports);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Debug)]
pub struct ExportSection {
bytes: Vec<u8>,
num_added: u32,
}
impl ExportSection {
/// Create a new export section encoder.
pub fn new() -> ExportSection {
ExportSection {
bytes: vec![],
num_added: 0,
}
}
/// How many exports have been defined inside this section so far?
pub fn len(&self) -> u32 {
self.num_added
}
/// Define an export.
pub fn export(&mut self, name: &str, export: Export) -> &mut Self {
self.bytes.extend(encoders::str(name));
export.encode(&mut self.bytes);
self.num_added += 1;
self
}
}
impl Section for ExportSection {
fn id(&self) -> u8 {
SectionId::Export.into()
}
fn encode<S>(&self, sink: &mut S)
where
S: Extend<u8>,
{
let num_added = encoders::u32(self.num_added);
let n = num_added.len();
sink.extend(
encoders::u32(u32::try_from(n + self.bytes.len()).unwrap())
.chain(num_added)
.chain(self.bytes.iter().copied()),
);
}
}
/// A WebAssembly export.
#[derive(Clone, Copy, Debug)]
pub enum Export {
/// An export of the `n`th function.
Function(u32),
/// An export of the `n`th table.
Table(u32),
/// An export of the `n`th memory.
Memory(u32),
/// An export of the `n`th global.
Global(u32),
/// An export of the `n`th tag.
Tag(u32),
/// An export of the `n`th instance.
///
/// Note that this is part of the [module linking proposal][proposal] and is
/// not currently part of stable WebAssembly.
///
/// [proposal]: https://github.com/webassembly/module-linking
Instance(u32),
/// An export of the `n`th module.
///
/// Note that this is part of the [module linking proposal][proposal] and is
/// not currently part of stable WebAssembly.
///
/// [proposal]: https://github.com/webassembly/module-linking
Module(u32),
}
impl Export {
pub(crate) fn encode(&self, bytes: &mut Vec<u8>) {
let idx = match *self {
Export::Function(x) => {
bytes.push(ItemKind::Function as u8);
x
}
Export::Table(x) => {
bytes.push(ItemKind::Table as u8);
x
}
Export::Memory(x) => {
bytes.push(ItemKind::Memory as u8);
x
}
Export::Global(x) => {
bytes.push(ItemKind::Global as u8);
x
}
Export::Tag(x) => {
bytes.push(ItemKind::Tag as u8);
x
}
Export::Instance(x) => {
bytes.push(ItemKind::Instance as u8);
x
}
Export::Module(x) => {
bytes.push(ItemKind::Module as u8);
x
}
};
bytes.extend(encoders::u32(idx));
}
}
/// Kinds of WebAssembly items
#[allow(missing_docs)]
#[repr(u8)]
#[derive(Clone, Copy, Debug)]
pub enum ItemKind {
Function = 0x00,
Table = 0x01,
Memory = 0x02,
Global = 0x03,
Tag = 0x04,
Module = 0x05,
Instance = 0x06,
}

View File

@ -1,167 +0,0 @@
use super::*;
use std::convert::TryFrom;
/// An encoder for the import section.
///
/// # Example
///
/// ```
/// use wasm_encoder::{Module, ImportSection, MemoryType};
///
/// let mut imports = ImportSection::new();
/// imports.import(
/// "env",
/// Some("memory"),
/// MemoryType {
/// minimum: 1,
/// maximum: None,
/// memory64: false,
/// }
/// );
///
/// let mut module = Module::new();
/// module.section(&imports);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Debug)]
pub struct ImportSection {
bytes: Vec<u8>,
num_added: u32,
}
impl ImportSection {
/// Construct a new import section encoder.
pub fn new() -> ImportSection {
ImportSection {
bytes: vec![],
num_added: 0,
}
}
/// How many imports have been defined inside this section so far?
pub fn len(&self) -> u32 {
self.num_added
}
/// Define an import.
pub fn import(
&mut self,
module: &str,
name: Option<&str>,
ty: impl Into<EntityType>,
) -> &mut Self {
self.bytes.extend(encoders::str(module));
match name {
Some(name) => self.bytes.extend(encoders::str(name)),
None => {
self.bytes.push(0x00);
self.bytes.push(0xff);
}
}
ty.into().encode(&mut self.bytes);
self.num_added += 1;
self
}
}
impl Section for ImportSection {
fn id(&self) -> u8 {
SectionId::Import.into()
}
fn encode<S>(&self, sink: &mut S)
where
S: Extend<u8>,
{
let num_added = encoders::u32(self.num_added);
let n = num_added.len();
sink.extend(
encoders::u32(u32::try_from(n + self.bytes.len()).unwrap())
.chain(num_added)
.chain(self.bytes.iter().copied()),
);
}
}
/// The type of an entity.
#[derive(Clone, Copy, Debug)]
pub enum EntityType {
/// The `n`th type, which is a function.
Function(u32),
/// A table type.
Table(TableType),
/// A memory type.
Memory(MemoryType),
/// A global type.
Global(GlobalType),
/// A tag type.
Tag(TagType),
/// The `n`th type, which is an instance.
Instance(u32),
/// The `n`th type, which is a module.
Module(u32),
}
// NB: no `impl From<u32> for ImportType` because instances and modules also use
// `u32` indices in module linking, so we would have to remove that impl when
// adding support for module linking anyways.
impl From<TableType> for EntityType {
fn from(t: TableType) -> Self {
EntityType::Table(t)
}
}
impl From<MemoryType> for EntityType {
fn from(m: MemoryType) -> Self {
EntityType::Memory(m)
}
}
impl From<GlobalType> for EntityType {
fn from(g: GlobalType) -> Self {
EntityType::Global(g)
}
}
impl From<TagType> for EntityType {
fn from(t: TagType) -> Self {
EntityType::Tag(t)
}
}
impl EntityType {
pub(crate) fn encode(&self, dst: &mut Vec<u8>) {
match self {
EntityType::Function(x) => {
dst.push(0x00);
dst.extend(encoders::u32(*x));
}
EntityType::Table(ty) => {
dst.push(0x01);
ty.encode(dst);
}
EntityType::Memory(ty) => {
dst.push(0x02);
ty.encode(dst);
}
EntityType::Global(ty) => {
dst.push(0x03);
ty.encode(dst);
}
EntityType::Tag(ty) => {
dst.push(0x04);
ty.encode(dst);
}
EntityType::Module(ty) => {
dst.push(0x05);
dst.extend(encoders::u32(*ty));
}
EntityType::Instance(ty) => {
dst.push(0x06);
dst.extend(encoders::u32(*ty));
}
}
}
}

View File

@ -1,86 +0,0 @@
use super::*;
/// An encoder for the instance section.
///
/// Note that this is part of the [module linking proposal][proposal] and is not
/// currently part of stable WebAssembly.
///
/// [proposal]: https://github.com/webassembly/module-linking
///
/// # Example
///
/// ```
/// use wasm_encoder::{Module, InstanceSection, Export};
///
/// let mut instances = InstanceSection::new();
/// instances.instantiate(0, vec![
/// ("x", Export::Function(0)),
/// ("", Export::Module(2)),
/// ("foo", Export::Global(0)),
/// ]);
///
/// let mut module = Module::new();
/// module.section(&instances);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Debug)]
pub struct InstanceSection {
bytes: Vec<u8>,
num_added: u32,
}
impl InstanceSection {
/// Construct a new instance section encoder.
pub fn new() -> InstanceSection {
InstanceSection {
bytes: vec![],
num_added: 0,
}
}
/// How many instances have been defined inside this section so far?
pub fn len(&self) -> u32 {
self.num_added
}
/// Define an instantiation of the given module with the given items as
/// arguments to the instantiation.
pub fn instantiate<'a, I>(&mut self, module: u32, args: I) -> &mut Self
where
I: IntoIterator<Item = (&'a str, Export)>,
I::IntoIter: ExactSizeIterator,
{
let args = args.into_iter();
self.bytes.push(0x00);
self.bytes.extend(encoders::u32(module));
self.bytes
.extend(encoders::u32(u32::try_from(args.len()).unwrap()));
for (name, export) in args {
self.bytes.extend(encoders::str(name));
export.encode(&mut self.bytes);
}
self.num_added += 1;
self
}
}
impl Section for InstanceSection {
fn id(&self) -> u8 {
SectionId::Instance.into()
}
fn encode<S>(&self, sink: &mut S)
where
S: Extend<u8>,
{
let num_added = encoders::u32(self.num_added);
let n = num_added.len();
sink.extend(
encoders::u32(u32::try_from(n + self.bytes.len()).unwrap())
.chain(num_added)
.chain(self.bytes.iter().copied()),
);
}
}

View File

@ -26,7 +26,7 @@
//!
//! ```
//! use wasm_encoder::{
//! CodeSection, Export, ExportSection, Function, FunctionSection, Instruction,
//! CodeSection, ExportKind, ExportSection, Function, FunctionSection, Instruction,
//! Module, TypeSection, ValType,
//! };
//!
@ -47,17 +47,17 @@
//!
//! // Encode the export section.
//! let mut exports = ExportSection::new();
//! exports.export("f", Export::Function(0));
//! exports.export("f", ExportKind::Func, 0);
//! module.section(&exports);
//!
//! // Encode the code section.
//! let mut codes = CodeSection::new();
//! let locals = vec![];
//! let mut f = Function::new(locals);
//! f.instruction(Instruction::LocalGet(0));
//! f.instruction(Instruction::LocalGet(1));
//! f.instruction(Instruction::I32Add);
//! f.instruction(Instruction::End);
//! f.instruction(&Instruction::LocalGet(0));
//! f.instruction(&Instruction::LocalGet(1));
//! f.instruction(&Instruction::I32Add);
//! f.instruction(&Instruction::End);
//! codes.function(&f);
//! module.section(&codes);
//!
@ -70,199 +70,104 @@
#![deny(missing_docs, missing_debug_implementations)]
mod aliases;
mod code;
mod custom;
mod data;
mod elements;
mod exports;
mod functions;
mod globals;
mod imports;
mod instances;
mod linking;
mod memories;
mod modules;
mod start;
mod tables;
mod tags;
mod types;
mod component;
mod core;
mod raw;
pub use aliases::*;
pub use code::*;
pub use custom::*;
pub use data::*;
pub use elements::*;
pub use exports::*;
pub use functions::*;
pub use globals::*;
pub use imports::*;
pub use instances::*;
pub use linking::*;
pub use memories::*;
pub use modules::*;
pub use start::*;
pub use tables::*;
pub use tags::*;
pub use types::*;
pub use self::component::*;
pub use self::core::*;
pub use self::raw::*;
pub mod encoders;
use std::convert::TryFrom;
/// A Wasm module that is being encoded.
#[derive(Clone, Debug)]
pub struct Module {
bytes: Vec<u8>,
/// Implemented by types that can be encoded into a byte sink.
pub trait Encode {
/// Encode the type into the given byte sink.
fn encode(&self, sink: &mut Vec<u8>);
}
/// A WebAssembly section.
///
/// Various builders defined in this crate already implement this trait, but you
/// can also implement it yourself for your own custom section builders, or use
/// `RawSection` to use a bunch of raw bytes as a section.
pub trait Section {
/// This section's id.
///
/// See `SectionId` for known section ids.
fn id(&self) -> u8;
/// Write this section's data and data length prefix into the given sink.
fn encode<S>(&self, sink: &mut S)
where
S: Extend<u8>;
}
/// A section made up of uninterpreted, raw bytes.
///
/// Allows you to splat any data into a Wasm section.
#[derive(Clone, Copy, Debug)]
pub struct RawSection<'a> {
/// The id for this section.
pub id: u8,
/// The raw data for this section.
pub data: &'a [u8],
}
impl Section for RawSection<'_> {
fn id(&self) -> u8 {
self.id
}
fn encode<S>(&self, sink: &mut S)
where
S: Extend<u8>,
{
sink.extend(
encoders::u32(u32::try_from(self.data.len()).unwrap()).chain(self.data.iter().copied()),
);
impl<T: Encode + ?Sized> Encode for &'_ T {
fn encode(&self, sink: &mut Vec<u8>) {
T::encode(self, sink)
}
}
impl Module {
/// Begin writing a new `Module`.
#[rustfmt::skip]
pub fn new() -> Self {
Module {
bytes: vec![
// Magic
0x00, 0x61, 0x73, 0x6D,
// Version
0x01, 0x00, 0x00, 0x00,
],
impl<T: Encode> Encode for [T] {
fn encode(&self, sink: &mut Vec<u8>) {
self.len().encode(sink);
for item in self {
item.encode(sink);
}
}
}
/// Write a section into this module.
///
/// It is your responsibility to define the sections in the [proper
/// order](https://webassembly.github.io/spec/core/binary/modules.html#binary-module),
/// and to ensure that each kind of section (other than custom sections) is
/// only defined once. While this is a potential footgun, it also allows you
/// to use this crate to easily construct test cases for bad Wasm module
/// encodings.
pub fn section(&mut self, section: &impl Section) -> &mut Self {
self.bytes.push(section.id());
section.encode(&mut self.bytes);
self
}
/// Get the encoded Wasm module as a slice.
pub fn as_slice(&self) -> &[u8] {
&self.bytes
}
/// Finish writing this Wasm module and extract ownership of the encoded
/// bytes.
pub fn finish(self) -> Vec<u8> {
self.bytes
impl Encode for [u8] {
fn encode(&self, sink: &mut Vec<u8>) {
self.len().encode(sink);
sink.extend(self);
}
}
/// Known section IDs.
///
/// Useful for implementing the `Section` trait, or for setting
/// `RawSection::id`.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
#[repr(u8)]
#[allow(missing_docs)]
pub enum SectionId {
Custom = 0,
Type = 1,
Import = 2,
Function = 3,
Table = 4,
Memory = 5,
Global = 6,
Export = 7,
Start = 8,
Element = 9,
Code = 10,
Data = 11,
DataCount = 12,
Tag = 13,
Module = 14,
Instance = 15,
Alias = 16,
}
impl From<SectionId> for u8 {
#[inline]
fn from(id: SectionId) -> u8 {
id as u8
impl Encode for str {
fn encode(&self, sink: &mut Vec<u8>) {
self.len().encode(sink);
sink.extend_from_slice(self.as_bytes());
}
}
/// The type of a value.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum ValType {
/// The `i32` type.
I32 = 0x7F,
/// The `i64` type.
I64 = 0x7E,
/// The `f32` type.
F32 = 0x7D,
/// The `f64` type.
F64 = 0x7C,
/// The `v128` type.
///
/// Part of the SIMD proposal.
V128 = 0x7B,
/// The `funcref` type.
///
/// Part of the reference types proposal when used anywhere other than a
/// table's element type.
FuncRef = 0x70,
/// The `externref` type.
///
/// Part of the reference types proposal.
ExternRef = 0x6F,
impl Encode for usize {
fn encode(&self, sink: &mut Vec<u8>) {
assert!(*self <= u32::max_value() as usize);
(*self as u32).encode(sink)
}
}
impl From<ValType> for u8 {
#[inline]
fn from(t: ValType) -> u8 {
t as u8
impl Encode for u32 {
fn encode(&self, sink: &mut Vec<u8>) {
leb128::write::unsigned(sink, (*self).into()).unwrap();
}
}
impl Encode for i32 {
fn encode(&self, sink: &mut Vec<u8>) {
leb128::write::signed(sink, (*self).into()).unwrap();
}
}
impl Encode for u64 {
fn encode(&self, sink: &mut Vec<u8>) {
leb128::write::unsigned(sink, *self).unwrap();
}
}
impl Encode for i64 {
fn encode(&self, sink: &mut Vec<u8>) {
leb128::write::signed(sink, *self).unwrap();
}
}
fn encoding_size(n: u32) -> usize {
let mut buf = [0u8; 5];
leb128::write::unsigned(&mut &mut buf[..], n.into()).unwrap()
}
fn encode_section(sink: &mut Vec<u8>, count: u32, bytes: &[u8]) {
(encoding_size(count) + bytes.len()).encode(sink);
count.encode(sink);
sink.extend(bytes);
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn it_encodes_an_empty_module() {
let bytes = Module::new().finish();
assert_eq!(bytes, [0x00, b'a', b's', b'm', 0x01, 0x00, 0x00, 0x00]);
}
#[test]
fn it_encodes_an_empty_component() {
let bytes = Component::new().finish();
assert_eq!(bytes, [0x00, b'a', b's', b'm', 0x0a, 0x00, 0x01, 0x00]);
}
}

View File

@ -1,72 +0,0 @@
use super::*;
/// An encoder for the module section.
///
/// Note that this is part of the [module linking proposal][proposal] and is
/// not currently part of stable WebAssembly.
///
/// [proposal]: https://github.com/webassembly/module-linking
///
/// # Example
///
/// ```
/// use wasm_encoder::{ModuleSection, Module};
///
/// let mut modules = ModuleSection::new();
/// modules.module(&Module::new());
/// modules.module(&Module::new());
///
/// let mut module = Module::new();
/// module.section(&modules);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Debug)]
pub struct ModuleSection {
bytes: Vec<u8>,
num_added: u32,
}
impl ModuleSection {
/// Create a new code section encoder.
pub fn new() -> ModuleSection {
ModuleSection {
bytes: vec![],
num_added: 0,
}
}
/// How many modules have been defined inside this section so far?
pub fn len(&self) -> u32 {
self.num_added
}
/// Writes a module into this module code section.
pub fn module(&mut self, module: &Module) -> &mut Self {
self.bytes.extend(
encoders::u32(u32::try_from(module.bytes.len()).unwrap())
.chain(module.bytes.iter().copied()),
);
self.num_added += 1;
self
}
}
impl Section for ModuleSection {
fn id(&self) -> u8 {
SectionId::Module.into()
}
fn encode<S>(&self, sink: &mut S)
where
S: Extend<u8>,
{
let num_added = encoders::u32(self.num_added);
let n = num_added.len();
sink.extend(
encoders::u32(u32::try_from(n + self.bytes.len()).unwrap())
.chain(num_added)
.chain(self.bytes.iter().copied()),
);
}
}

View File

@ -0,0 +1,30 @@
use crate::{ComponentSection, Encode, Section};
/// A section made up of uninterpreted, raw bytes.
///
/// Allows you to splat any data into a module or component.
#[derive(Clone, Copy, Debug)]
pub struct RawSection<'a> {
/// The id for this section.
pub id: u8,
/// The raw data for this section.
pub data: &'a [u8],
}
impl Encode for RawSection<'_> {
fn encode(&self, sink: &mut Vec<u8>) {
self.data.encode(sink);
}
}
impl Section for RawSection<'_> {
fn id(&self) -> u8 {
self.id
}
}
impl ComponentSection for RawSection<'_> {
fn id(&self) -> u8 {
self.id
}
}

View File

@ -1,140 +0,0 @@
use super::*;
use std::convert::TryFrom;
/// An encoder for the type section.
///
/// # Example
///
/// ```
/// use wasm_encoder::{Module, TypeSection, ValType};
///
/// let mut types = TypeSection::new();
/// let params = vec![ValType::I32, ValType::I64];
/// let results = vec![ValType::I32];
/// types.function(params, results);
///
/// let mut module = Module::new();
/// module.section(&types);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Debug)]
pub struct TypeSection {
bytes: Vec<u8>,
num_added: u32,
}
impl TypeSection {
/// Create a new type section encoder.
pub fn new() -> TypeSection {
TypeSection {
bytes: vec![],
num_added: 0,
}
}
/// How many types have been defined inside this section so far?
pub fn len(&self) -> u32 {
self.num_added
}
/// Define a function type.
pub fn function<P, R>(&mut self, params: P, results: R) -> &mut Self
where
P: IntoIterator<Item = ValType>,
P::IntoIter: ExactSizeIterator,
R: IntoIterator<Item = ValType>,
R::IntoIter: ExactSizeIterator,
{
let params = params.into_iter();
let results = results.into_iter();
self.bytes.push(0x60);
self.bytes
.extend(encoders::u32(u32::try_from(params.len()).unwrap()));
self.bytes.extend(params.map(|ty| u8::from(ty)));
self.bytes
.extend(encoders::u32(u32::try_from(results.len()).unwrap()));
self.bytes.extend(results.map(|ty| u8::from(ty)));
self.num_added += 1;
self
}
/// Define a module type.
pub fn module<'a, I, E>(&mut self, imports: I, exports: E) -> &mut Self
where
I: IntoIterator<Item = (&'a str, Option<&'a str>, EntityType)>,
I::IntoIter: ExactSizeIterator,
E: IntoIterator<Item = (&'a str, EntityType)>,
E::IntoIter: ExactSizeIterator,
{
let exports = exports.into_iter();
let imports = imports.into_iter();
self.bytes.push(0x61);
self.bytes
.extend(encoders::u32(u32::try_from(imports.len()).unwrap()));
for (module, name, ty) in imports {
self.bytes.extend(encoders::str(module));
match name {
Some(name) => self.bytes.extend(encoders::str(name)),
None => self.bytes.extend(&[0x00, 0xff]),
}
ty.encode(&mut self.bytes);
}
self.bytes
.extend(encoders::u32(u32::try_from(exports.len()).unwrap()));
for (name, ty) in exports {
self.bytes.extend(encoders::str(name));
ty.encode(&mut self.bytes);
}
self.num_added += 1;
self
}
/// Define an instance type.
pub fn instance<'a, E>(&mut self, exports: E) -> &mut Self
where
E: IntoIterator<Item = (&'a str, EntityType)>,
E::IntoIter: ExactSizeIterator,
{
let exports = exports.into_iter();
self.bytes.push(0x62);
self.bytes
.extend(encoders::u32(u32::try_from(exports.len()).unwrap()));
for (name, ty) in exports {
self.bytes.extend(encoders::str(name));
ty.encode(&mut self.bytes);
}
self.num_added += 1;
self
}
}
impl Section for TypeSection {
fn id(&self) -> u8 {
SectionId::Type.into()
}
fn encode<S>(&self, sink: &mut S)
where
S: Extend<u8>,
{
let num_added = encoders::u32(self.num_added);
let n = num_added.len();
sink.extend(
encoders::u32(u32::try_from(n + self.bytes.len()).unwrap())
.chain(num_added)
.chain(self.bytes.iter().copied()),
);
}
}

View File

@ -1,198 +0,0 @@
use anyhow::{Context, Result};
use std::fs;
use std::io::{self, Write};
use std::process::{Command, Stdio};
use wasm_encoder::*;
/// Run `wasm-objdump -x -j linking` on the given Wasm bytes.
///
/// Returns `Ok(Some(stdout))` on success, `Ok(None)` if it looks like this
/// system doesn't have WABT installed on it (so that the caller can skip the
/// current test), and `Err(e)` on some other kind of failure.
fn wabt_linking_section(wasm: &[u8]) -> Result<Option<String>> {
let tmp = tempfile::NamedTempFile::new().context("failed to create a named temp file")?;
fs::write(tmp.path(), wasm).context("failed to write our wasm module to a temp file")?;
let child = match Command::new("wasm-objdump")
.arg(tmp.path())
.arg("-x")
.arg("-s")
.arg("-j")
.arg("linking")
.stdin(Stdio::null())
.stderr(Stdio::null())
.stdout(Stdio::piped())
.spawn()
{
Ok(c) => c,
Err(_) => {
let stderr = io::stderr();
let mut stderr = stderr.lock();
let _ = writeln!(
&mut stderr,
"Warning: failed to spawn `wasm-objdump` command. Assuming WABT tools are not \
installed on this system and ignoring this test.",
);
return Ok(None);
}
};
let output = child
.wait_with_output()
.context("failed to read wasm-objdump's stdout")?;
let mut stdout =
String::from_utf8(output.stdout).context("wasm-objdump did not emit UTF-8 to stdout")?;
eprintln!(
"====== full wasm-objdump output ======\n{}\n======================================",
stdout
);
// Trim the prefix output before the linking section dump (which includes
// the name of the tempfile, so we can't have it in here).
let i = stdout.find(" - name: \"linking\"\n").ok_or_else(|| {
anyhow::anyhow!("could not find linking section dump in wasm-objdump output")
})?;
let mut stdout = stdout.split_off(i);
// Trim the hexdump of the custom section. While this is useful to have in
// the `stderr` logging above when debugging tests, we don't want it
// repeated in our test assertions.
let i = stdout
.find("\n\nContents of section Custom:\n")
.ok_or_else(|| {
anyhow::anyhow!("could not find contents of custom section in wasm-objdump output")
})?;
let _ = stdout.split_off(i);
Ok(Some(stdout))
}
fn assert_wabt_linking(linking: &LinkingSection, expected_wabt_dump: &str) -> Result<()> {
let mut module = Module::new();
module.section(linking);
let wasm = module.finish();
if let Some(actual_wabt_dump) = wabt_linking_section(&wasm)? {
assert_eq!(expected_wabt_dump.trim(), actual_wabt_dump.trim());
}
Ok(())
}
#[test]
fn sym_tab_function() -> Result<()> {
let mut sym_tab = SymbolTable::new();
sym_tab.function(0, 42, Some("func"));
let mut linking = LinkingSection::new();
linking.symbol_table(&sym_tab);
assert_wabt_linking(
&linking,
"
- name: \"linking\"
- symbol table [count=1]
- 0: F <func> func=42 [ binding=global vis=default ]
",
)
}
#[test]
fn sym_tab_flags() -> Result<()> {
let mut sym_tab = SymbolTable::new();
sym_tab.function(
SymbolTable::WASM_SYM_BINDING_WEAK | SymbolTable::WASM_SYM_VISIBILITY_HIDDEN,
1337,
Some("func"),
);
let mut linking = LinkingSection::new();
linking.symbol_table(&sym_tab);
assert_wabt_linking(
&linking,
"
- name: \"linking\"
- symbol table [count=1]
- 0: F <func> func=1337 [ binding=weak vis=hidden ]
",
)
}
#[test]
fn sym_tab_global() -> Result<()> {
let mut sym_tab = SymbolTable::new();
sym_tab.global(0, 42, Some("my_global"));
let mut linking = LinkingSection::new();
linking.symbol_table(&sym_tab);
assert_wabt_linking(
&linking,
"
- name: \"linking\"
- symbol table [count=1]
- 0: G <my_global> global=42 [ binding=global vis=default ]",
)
}
#[test]
fn sym_tab_table() -> Result<()> {
let mut sym_tab = SymbolTable::new();
sym_tab.table(0, 42, Some("my_table"));
let mut linking = LinkingSection::new();
linking.symbol_table(&sym_tab);
assert_wabt_linking(
&linking,
"
- name: \"linking\"
- symbol table [count=1]
- 0: T <my_table> table=42 [ binding=global vis=default ]",
)
}
#[test]
fn sym_tab_data_defined() -> Result<()> {
let mut sym_tab = SymbolTable::new();
sym_tab.data(
0,
"my_data",
Some(DataSymbolDefinition {
index: 42,
offset: 1337,
size: 1234,
}),
);
let mut linking = LinkingSection::new();
linking.symbol_table(&sym_tab);
assert_wabt_linking(
&linking,
"
- name: \"linking\"
- symbol table [count=1]
- 0: D <my_data> segment=42 offset=1337 size=1234 [ binding=global vis=default ]
",
)
}
#[test]
fn sym_tab_data_undefined() -> Result<()> {
let mut sym_tab = SymbolTable::new();
sym_tab.data(SymbolTable::WASM_SYM_UNDEFINED, "my_data", None);
let mut linking = LinkingSection::new();
linking.symbol_table(&sym_tab);
assert_wabt_linking(
&linking,
"
- name: \"linking\"
- symbol table [count=1]
- 0: D <my_data> [ undefined binding=global vis=default ]
",
)
}

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"ef414c81e8535129ca20ac5d14a376ae9718ad49f5565e93aea462a32b395fa1","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"9948cd1d106d8632025da5d9fc5b9d43da8f5591b16074fc10b5638840d3cd18","benches/corpus.rs":"2df29556be0799f0cb1f32c8d0ae5ba0c4b9815cf4d59a8b71744d926c0693a0","src/code_builder.rs":"d3ff894119bf379fd2188ab897a8dbec86aa12e09e0ccf1045cf9d9b0fd71fcc","src/config.rs":"c0d9c6406e224bded23dc63ca6201a2d91ef9be2f4912f8b2fca91fc1d9363e0","src/encode.rs":"51cbb1432b9a32b5be9257045c7ee23852f36b3559d7bddb3eb7abbbd88e87e6","src/lib.rs":"c55373dd6f62d157d238032941c19ce14f94b9aba1423559d7d691ba7e187964","src/terminate.rs":"dd23771541c966770823e67e350e22390f777d4bc39c1fdbabf4ed13a3b1c6b4","tests/tests.rs":"6ea31f083d7c01d09310203abb1428d323c077dd024fe45049dff77b20625338"},"package":"440458e050ee2731e85af3368ee58e23d4728d597809a88f841a24778876f2b6"}
{"files":{"Cargo.toml":"41e7bfa4b5f89f5c3db096de0799cef34ccbc378bd8bca4e444199be6135b625","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"9948cd1d106d8632025da5d9fc5b9d43da8f5591b16074fc10b5638840d3cd18","benches/corpus.rs":"2df29556be0799f0cb1f32c8d0ae5ba0c4b9815cf4d59a8b71744d926c0693a0","src/component.rs":"18f354f335cf84f49f70e1c8c3ad6b272df9b6c6aa6051112ca30b5fd4f63346","src/component/encode.rs":"4905a5efc695ad6e0aae306907ed033d85804cc9e4dfee04d823df47e64acdd0","src/config.rs":"4f2bddb2c9c5c7c16959cd88590965987a177ed029be9267e9a57a9be49f9fde","src/core.rs":"b961e48e975effa1cb273b998062f31d8672a06bec4a76e5168703bf8c543f3c","src/core/code_builder.rs":"35dc4e5bfa4a204a7354b630f71c215b9ae849bc1826279b4e5d8d6e1d16397b","src/core/encode.rs":"560dae224942d768d325f15d732f0a8336171b52b76e5dc07356b1e5e7528ce5","src/core/terminate.rs":"f3fdc4fdc93300417762f05764c5b68e614737adc7749bf3dd49186a1a42b1e9","src/lib.rs":"5230cdd1bfd6f668ea97282702c07fe0d3232da8e8f5a4d89a9f7053d4836a12","tests/component.rs":"54c69ebdda583207f9f0467a600ee0ca87fbee6b365e97ec3deff7b46bd6af06","tests/core.rs":"c595640db5619db703e0f8f08e0aa7426f8b8a8cf70654cac226c80a876fc3e4"},"package":"b73250e61e41d0e467b78559c7d761841005d724384bb0b78d52ff974acf5520"}

View File

@ -10,33 +10,52 @@
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
edition = "2021"
name = "wasm-smith"
version = "0.8.0"
version = "0.11.2"
authors = ["Nick Fitzgerald <fitzgen@gmail.com>"]
exclude = ["/benches/corpus"]
description = "A WebAssembly test case generator"
documentation = "https://docs.rs/wasm-smith"
readme = "./README.md"
categories = ["command-line-utilities", "development-tools", "development-tools::testing", "wasm"]
categories = [
"command-line-utilities",
"development-tools",
"development-tools::testing",
"wasm",
]
license = "Apache-2.0 WITH LLVM-exception"
repository = "https://github.com/bytecodealliance/wasm-tools"
repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-smith"
resolver = "2"
[[bench]]
name = "corpus"
harness = false
[dependencies.arbitrary]
version = "1.0.0"
version = "1.1.0"
features = ["derive"]
[dependencies.flagset]
version = "0.4"
[dependencies.indexmap]
version = "1.6"
[dependencies.leb128]
version = "0.2.4"
[dependencies.serde]
version = "1"
features = ["derive"]
optional = true
[dependencies.wasm-encoder]
version = "0.7.0"
version = "0.14.0"
[dependencies.wasmparser]
version = "0.87.0"
[dev-dependencies.criterion]
version = "0.3.3"
@ -44,5 +63,11 @@ version = "0.3.3"
version = "0.4.0"
[dev-dependencies.rand]
version = "0.7.3"
version = "0.8.0"
features = ["small_rng"]
[features]
_internal_cli = [
"serde",
"flagset/serde",
]

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,301 @@
use super::*;
impl Component {
/// Encode this Wasm component into bytes.
pub fn to_bytes(&self) -> Vec<u8> {
self.encoded().finish()
}
fn encoded(&self) -> wasm_encoder::Component {
let mut component = wasm_encoder::Component::new();
for section in &self.sections {
section.encode(&mut component);
}
component
}
}
impl Section {
fn encode(&self, component: &mut wasm_encoder::Component) {
match self {
Self::Custom(sec) => sec.encode(component),
Self::CoreModule(module) => {
let bytes = module.to_bytes();
component.section(&wasm_encoder::RawSection {
id: wasm_encoder::ComponentSectionId::CoreModule as u8,
data: &bytes,
});
}
Self::CoreInstance(_) => todo!(),
Self::CoreAlias(_) => todo!(),
Self::CoreType(sec) => sec.encode(component),
Self::Component(comp) => {
let bytes = comp.to_bytes();
component.section(&wasm_encoder::RawSection {
id: wasm_encoder::ComponentSectionId::Component as u8,
data: &bytes,
});
}
Self::Instance(_) => todo!(),
Self::Alias(_) => todo!(),
Self::Type(sec) => sec.encode(component),
Self::Canonical(sec) => sec.encode(component),
Self::Start(_) => todo!(),
Self::Import(sec) => sec.encode(component),
Self::Export(_) => todo!(),
}
}
}
impl CustomSection {
fn encode(&self, component: &mut wasm_encoder::Component) {
component.section(&wasm_encoder::CustomSection {
name: &self.name,
data: &self.data,
});
}
}
impl TypeSection {
fn encode(&self, component: &mut wasm_encoder::Component) {
let mut sec = wasm_encoder::ComponentTypeSection::new();
for ty in &self.types {
ty.encode(sec.ty());
}
component.section(&sec);
}
}
impl ImportSection {
fn encode(&self, component: &mut wasm_encoder::Component) {
let mut sec = wasm_encoder::ComponentImportSection::new();
for imp in &self.imports {
sec.import(&imp.name, imp.ty);
}
component.section(&sec);
}
}
impl CanonicalSection {
fn encode(&self, component: &mut wasm_encoder::Component) {
let mut sec = wasm_encoder::CanonicalFunctionSection::new();
for func in &self.funcs {
match func {
Func::CanonLift {
func_ty,
options,
core_func_index,
} => {
let options = translate_canon_opt(options);
sec.lift(*core_func_index, *func_ty, options);
}
Func::CanonLower {
options,
func_index,
} => {
let options = translate_canon_opt(options);
sec.lower(*func_index, options);
}
}
}
component.section(&sec);
}
}
impl CoreTypeSection {
fn encode(&self, component: &mut wasm_encoder::Component) {
let mut sec = wasm_encoder::CoreTypeSection::new();
for ty in &self.types {
ty.encode(sec.ty());
}
component.section(&sec);
}
}
impl CoreType {
fn encode(&self, enc: wasm_encoder::CoreTypeEncoder<'_>) {
match self {
Self::Func(ty) => {
enc.function(ty.params.iter().copied(), ty.results.iter().copied());
}
Self::Module(mod_ty) => {
let mut enc_mod_ty = wasm_encoder::ModuleType::new();
for def in &mod_ty.defs {
match def {
ModuleTypeDef::TypeDef(crate::core::Type::Func(func_ty)) => {
enc_mod_ty.ty().function(
func_ty.params.iter().copied(),
func_ty.results.iter().copied(),
);
}
ModuleTypeDef::Alias(alias) => match alias {
CoreAlias::Outer {
count,
i,
kind: CoreOuterAliasKind::Type(_),
} => {
enc_mod_ty.alias_outer_core_type(*count, *i);
}
CoreAlias::InstanceExport { .. } => unreachable!(),
},
ModuleTypeDef::Import(imp) => {
enc_mod_ty.import(
&imp.module,
&imp.field,
crate::core::encode::translate_entity_type(&imp.entity_type),
);
}
ModuleTypeDef::Export(name, ty) => {
enc_mod_ty.export(name, crate::core::encode::translate_entity_type(ty));
}
}
}
enc.module(&enc_mod_ty);
}
}
}
}
impl Type {
fn encode(&self, enc: wasm_encoder::ComponentTypeEncoder<'_>) {
match self {
Self::Defined(ty) => {
ty.encode(enc.defined_type());
}
Self::Func(func_ty) => {
enc.function(
func_ty.params.iter().map(translate_optional_named_type),
func_ty.result,
);
}
Self::Component(comp_ty) => {
let mut enc_comp_ty = wasm_encoder::ComponentType::new();
for def in &comp_ty.defs {
match def {
ComponentTypeDef::Import(imp) => {
enc_comp_ty.import(&imp.name, imp.ty);
}
ComponentTypeDef::CoreType(ty) => {
ty.encode(enc_comp_ty.core_type());
}
ComponentTypeDef::Type(ty) => {
ty.encode(enc_comp_ty.ty());
}
ComponentTypeDef::Export { name, ty } => {
enc_comp_ty.export(name, *ty);
}
ComponentTypeDef::Alias(Alias::Outer {
count,
i,
kind: OuterAliasKind::Type(_),
}) => {
enc_comp_ty.alias_outer_type(*count, *i);
}
ComponentTypeDef::Alias(Alias::Outer {
count,
i,
kind: OuterAliasKind::CoreType(_),
}) => {
enc_comp_ty.alias_outer_core_type(*count, *i);
}
ComponentTypeDef::Alias(_) => unreachable!(),
}
}
enc.component(&enc_comp_ty);
}
Self::Instance(inst_ty) => {
let mut enc_inst_ty = wasm_encoder::InstanceType::new();
for def in &inst_ty.defs {
match def {
InstanceTypeDef::CoreType(ty) => {
ty.encode(enc_inst_ty.core_type());
}
InstanceTypeDef::Type(ty) => {
ty.encode(enc_inst_ty.ty());
}
InstanceTypeDef::Export { name, ty } => {
enc_inst_ty.export(name, *ty);
}
InstanceTypeDef::Alias(Alias::Outer {
count,
i,
kind: OuterAliasKind::Type(_),
}) => {
enc_inst_ty.alias_outer_type(*count, *i);
}
InstanceTypeDef::Alias(Alias::Outer {
count,
i,
kind: OuterAliasKind::CoreType(_),
}) => {
enc_inst_ty.alias_outer_core_type(*count, *i);
}
InstanceTypeDef::Alias(_) => unreachable!(),
}
}
enc.instance(&enc_inst_ty);
}
}
}
}
impl DefinedType {
fn encode(&self, enc: wasm_encoder::ComponentDefinedTypeEncoder<'_>) {
match self {
Self::Primitive(ty) => enc.primitive(*ty),
Self::Record(ty) => {
enc.record(ty.fields.iter().map(translate_named_type));
}
Self::Variant(ty) => {
enc.variant(
ty.cases
.iter()
.map(|(ty, refines)| (ty.name.as_str(), ty.ty, *refines)),
);
}
Self::List(ty) => {
enc.list(ty.elem_ty);
}
Self::Tuple(ty) => {
enc.tuple(ty.fields.iter().copied());
}
Self::Flags(ty) => {
enc.flags(ty.fields.iter().map(|f| f.as_str()));
}
Self::Enum(ty) => {
enc.enum_type(ty.variants.iter().map(|v| v.as_str()));
}
Self::Union(ty) => {
enc.union(ty.variants.iter().copied());
}
Self::Option(ty) => {
enc.option(ty.inner_ty);
}
Self::Expected(ty) => {
enc.expected(ty.ok_ty, ty.err_ty);
}
}
}
}
fn translate_named_type(ty: &NamedType) -> (&str, ComponentValType) {
(&ty.name, ty.ty)
}
fn translate_optional_named_type(ty: &OptionalNamedType) -> (Option<&str>, ComponentValType) {
(ty.name.as_deref(), ty.ty)
}
fn translate_canon_opt(options: &[CanonOpt]) -> Vec<wasm_encoder::CanonicalOption> {
options
.iter()
.map(|o| match o {
CanonOpt::StringUtf8 => wasm_encoder::CanonicalOption::UTF8,
CanonOpt::StringUtf16 => wasm_encoder::CanonicalOption::UTF16,
CanonOpt::StringLatin1Utf16 => wasm_encoder::CanonicalOption::CompactUTF16,
CanonOpt::Memory(idx) => wasm_encoder::CanonicalOption::Memory(*idx),
CanonOpt::Realloc(idx) => wasm_encoder::CanonicalOption::Realloc(*idx),
CanonOpt::PostReturn(idx) => wasm_encoder::CanonicalOption::PostReturn(*idx),
})
.collect()
}

View File

@ -1,6 +1,8 @@
//! Configuring the shape of generated Wasm modules.
use crate::InstructionKinds;
use arbitrary::{Arbitrary, Result, Unstructured};
use std::borrow::Cow;
/// Configuration for a generated module.
///
@ -58,6 +60,41 @@ pub trait Config: 'static + std::fmt::Debug {
100
}
/// The imports that may be used when generating the module.
///
/// Defaults to `None` which means that any arbitrary import can be generated.
///
/// To only allow specific imports, override this method to return a WebAssembly module which
/// describes the imports allowed.
///
/// Note that [`Self::min_imports`] is ignored when `available_imports` are enabled.
///
/// # Panics
///
/// The returned value must be a valid binary encoding of a WebAssembly module. `wasm-smith`
/// will panic if the module cannot be parsed.
///
/// # Example
///
/// An implementation of this method could use the `wat` crate to provide a human-readable and
/// maintainable description:
///
/// ```rust
/// Some(wat::parse_str(r#"
/// (module
/// (import "env" "ping" (func (param i32)))
/// (import "env" "pong" (func (result i32)))
/// (import "env" "memory" (memory 1))
/// (import "env" "table" (table 1))
/// (import "env" "tag" (tag (param i32)))
/// )
/// "#))
/// # ;
/// ```
fn available_imports(&self) -> Option<Cow<'_, [u8]>> {
None
}
/// The minimum number of functions to generate. Defaults to 0. This
/// includes imported functions.
fn min_funcs(&self) -> usize {
@ -92,6 +129,12 @@ pub trait Config: 'static + std::fmt::Debug {
100
}
/// Export all WebAssembly objects in the module. This overrides
/// [`Config::min_exports`] and [`Config::max_exports`]. Defaults to false.
fn export_everything(&self) -> bool {
false
}
/// The minimum number of element segments to generate. Defaults to 0.
fn min_element_segments(&self) -> usize {
0
@ -180,6 +223,19 @@ pub trait Config: 'static + std::fmt::Debug {
false
}
/// The maximum, elements, of any table's initial or maximum size.
///
/// Defaults to 1 million.
fn max_table_elements(&self) -> u32 {
1_000_000
}
/// Whether every Wasm table must have a maximum size specified. Defaults
/// to `false`.
fn table_max_size_required(&self) -> bool {
false
}
/// The maximum number of instances to use. Defaults to 10. This includes
/// imported instances.
///
@ -191,11 +247,27 @@ pub trait Config: 'static + std::fmt::Debug {
/// The maximum number of modules to use. Defaults to 10. This includes
/// imported modules.
///
/// Note that this is irrelevant unless module linking is enabled.
/// Note that this is irrelevant unless component model support is enabled.
fn max_modules(&self) -> usize {
10
}
/// The maximum number of components to use. Defaults to 10. This includes
/// imported components.
///
/// Note that this is irrelevant unless component model support is enabled.
fn max_components(&self) -> usize {
10
}
/// The maximum number of values to use. Defaults to 10. This includes
/// imported values.
///
/// Note that this is irrelevant unless value model support is enabled.
fn max_values(&self) -> usize {
10
}
/// Control the probability of generating memory offsets that are in bounds
/// vs. potentially out of bounds.
///
@ -236,34 +308,64 @@ pub trait Config: 'static + std::fmt::Debug {
}
/// Determines whether the bulk memory proposal is enabled for generating
/// insructions. Defaults to `false`.
/// instructions.
///
/// Defaults to `false`.
fn bulk_memory_enabled(&self) -> bool {
false
}
/// Determines whether the reference types proposal is enabled for
/// generating insructions. Defaults to `false`.
/// generating instructions.
///
/// Defaults to `false`.
fn reference_types_enabled(&self) -> bool {
false
}
/// Determines whether the SIMD proposal is enabled for
/// generating insructions. Defaults to `false`.
/// generating instructions.
///
/// Defaults to `false`.
fn simd_enabled(&self) -> bool {
false
}
/// Determines whether the Relaxed SIMD proposal is enabled for
/// generating instructions.
///
/// Defaults to `false`.
fn relaxed_simd_enabled(&self) -> bool {
false
}
/// Determines whether the exception-handling proposal is enabled for
/// generating insructions. Defaults to `false`.
/// generating instructions.
///
/// Defaults to `false`.
fn exceptions_enabled(&self) -> bool {
false
}
/// Determines whether the module linking proposal is enabled.
/// Determines whether the multi-value results are enabled.
///
/// Defaults to `false`.
fn module_linking_enabled(&self) -> bool {
false
/// Defaults to `true`.
fn multi_value_enabled(&self) -> bool {
true
}
/// Determines whether the nontrapping-float-to-int-conversions propsal is enabled.
///
/// Defaults to `true`.
fn saturating_float_to_int_enabled(&self) -> bool {
true
}
/// Determines whether the sign-extension-ops propsal is enabled.
///
/// Defaults to `true`.
fn sign_extension_ops_enabled(&self) -> bool {
true
}
/// Determines whether a `start` export may be included. Defaults to `true`.
@ -313,6 +415,40 @@ pub trait Config: 'static + std::fmt::Debug {
fn canonicalize_nans(&self) -> bool {
false
}
/// Returns the kinds of instructions allowed in the generated wasm
/// programs.
///
/// The categories of instructions match the categories used by the
/// [WebAssembly
/// specification](https://webassembly.github.io/spec/core/syntax/instructions.html);
/// e.g., numeric, vector, control, memory, etc. Note that modifying this
/// setting is separate from the proposal flags; that is, if `simd_enabled()
/// == true` but `allowed_instruction()` does not include vector
/// instructions, the generated programs will not include these instructions
/// but could contain vector types.
fn allowed_instructions(&self) -> InstructionKinds {
InstructionKinds::all()
}
/// Returns whether we should generate custom sections or not.
///
/// This is false by default.
fn generate_custom_sections(&self) -> bool {
false
}
/// Determines whether the threads proposal is enabled.
///
/// The [threads proposal] involves shared linear memory, new atomic
/// instructions, and new `wait` and `notify` instructions.
///
/// [threads proposal]: https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md
///
/// Defaults to `false`.
fn threads_enabled(&self) -> bool {
false
}
}
/// The default configuration.
@ -336,50 +472,57 @@ impl Config for DefaultConfig {}
#[derive(Clone, Debug)]
#[allow(missing_docs)]
pub struct SwarmConfig {
// These fields are configured via `Arbitrary`
pub max_types: usize,
pub max_imports: usize,
pub max_tags: usize,
pub max_funcs: usize,
pub max_globals: usize,
pub max_exports: usize,
pub allow_start_export: bool,
pub available_imports: Option<Vec<u8>>,
pub bulk_memory_enabled: bool,
pub canonicalize_nans: bool,
pub exceptions_enabled: bool,
pub export_everything: bool,
pub max_aliases: usize,
pub max_components: usize,
pub max_data_segments: usize,
pub max_element_segments: usize,
pub max_elements: usize,
pub max_data_segments: usize,
pub max_exports: usize,
pub max_funcs: usize,
pub max_globals: usize,
pub max_imports: usize,
pub max_instances: usize,
pub max_instructions: usize,
pub max_memories: usize,
pub min_uleb_size: u8,
pub max_tables: usize,
pub max_memory_pages: u64,
pub bulk_memory_enabled: bool,
pub reference_types_enabled: bool,
pub module_linking_enabled: bool,
pub max_aliases: usize,
pub max_modules: usize,
pub max_nesting_depth: usize,
// These fields are always set to their default value as specified in the
// default trait implementation.
pub max_tables: usize,
pub max_tags: usize,
pub max_type_size: u32,
pub max_types: usize,
pub max_values: usize,
pub memory64_enabled: bool,
pub min_types: usize,
pub min_imports: usize,
pub min_tags: usize,
pub min_funcs: usize,
pub min_globals: usize,
pub min_exports: usize,
pub memory_max_size_required: bool,
pub memory_offset_choices: (u32, u32, u32),
pub min_data_segments: usize,
pub min_element_segments: usize,
pub min_elements: usize,
pub min_exports: usize,
pub min_funcs: usize,
pub min_globals: usize,
pub min_imports: usize,
pub min_memories: u32,
pub min_tables: u32,
pub max_instances: usize,
pub max_modules: usize,
pub memory_offset_choices: (u32, u32, u32),
pub memory_max_size_required: bool,
pub min_tags: usize,
pub min_types: usize,
pub min_uleb_size: u8,
pub multi_value_enabled: bool,
pub reference_types_enabled: bool,
pub relaxed_simd_enabled: bool,
pub saturating_float_to_int_enabled: bool,
pub sign_extension_enabled: bool,
pub simd_enabled: bool,
pub exceptions_enabled: bool,
pub allow_start_export: bool,
pub max_type_size: u32,
pub canonicalize_nans: bool,
pub threads_enabled: bool,
pub allowed_instructions: InstructionKinds,
pub max_table_elements: u32,
pub table_max_size_required: bool,
}
impl<'a> Arbitrary<'a> for SwarmConfig {
@ -404,10 +547,26 @@ impl<'a> Arbitrary<'a> for SwarmConfig {
max_tables,
max_memory_pages: u.arbitrary()?,
min_uleb_size: u.int_in_range(0..=5)?,
bulk_memory_enabled: u.arbitrary()?,
bulk_memory_enabled: reference_types_enabled || u.arbitrary()?,
reference_types_enabled,
simd_enabled: u.arbitrary()?,
multi_value_enabled: u.arbitrary()?,
max_aliases: u.int_in_range(0..=MAX_MAXIMUM)?,
max_nesting_depth: u.int_in_range(0..=10)?,
saturating_float_to_int_enabled: u.arbitrary()?,
sign_extension_enabled: u.arbitrary()?,
allowed_instructions: {
use flagset::Flags;
let mut allowed = Vec::new();
for kind in crate::core::InstructionKind::LIST {
if u.arbitrary()? {
allowed.push(*kind);
}
}
InstructionKinds::new(&allowed)
},
table_max_size_required: u.arbitrary()?,
max_table_elements: u.int_in_range(0..=1_000_000)?,
// These fields, unlike the ones above, are less useful to set.
// They either make weird inputs or are for features not widely
@ -426,14 +585,18 @@ impl<'a> Arbitrary<'a> for SwarmConfig {
memory_max_size_required: false,
max_instances: 0,
max_modules: 0,
max_components: 0,
max_values: 0,
memory_offset_choices: (75, 24, 1),
allow_start_export: true,
simd_enabled: false,
relaxed_simd_enabled: false,
exceptions_enabled: false,
memory64_enabled: false,
max_type_size: 1000,
module_linking_enabled: false,
canonicalize_nans: false,
available_imports: None,
threads_enabled: false,
export_everything: false,
})
}
}
@ -455,6 +618,12 @@ impl Config for SwarmConfig {
self.max_imports
}
fn available_imports(&self) -> Option<Cow<'_, [u8]>> {
self.available_imports
.as_ref()
.map(|is| Cow::Borrowed(&is[..]))
}
fn min_funcs(&self) -> usize {
self.min_funcs
}
@ -479,6 +648,10 @@ impl Config for SwarmConfig {
self.max_exports
}
fn export_everything(&self) -> bool {
self.export_everything
}
fn min_element_segments(&self) -> usize {
self.min_element_segments
}
@ -559,18 +732,30 @@ impl Config for SwarmConfig {
self.reference_types_enabled
}
fn module_linking_enabled(&self) -> bool {
self.module_linking_enabled
}
fn simd_enabled(&self) -> bool {
self.simd_enabled
}
fn relaxed_simd_enabled(&self) -> bool {
self.relaxed_simd_enabled
}
fn exceptions_enabled(&self) -> bool {
self.exceptions_enabled
}
fn multi_value_enabled(&self) -> bool {
self.multi_value_enabled
}
fn saturating_float_to_int_enabled(&self) -> bool {
self.saturating_float_to_int_enabled
}
fn sign_extension_ops_enabled(&self) -> bool {
self.sign_extension_enabled
}
fn allow_start_export(&self) -> bool {
self.allow_start_export
}
@ -583,6 +768,10 @@ impl Config for SwarmConfig {
self.max_nesting_depth
}
fn max_type_size(&self) -> u32 {
self.max_type_size
}
fn memory64_enabled(&self) -> bool {
self.memory64_enabled
}
@ -590,4 +779,20 @@ impl Config for SwarmConfig {
fn canonicalize_nans(&self) -> bool {
self.canonicalize_nans
}
fn threads_enabled(&self) -> bool {
self.threads_enabled
}
fn allowed_instructions(&self) -> InstructionKinds {
self.allowed_instructions
}
fn max_table_elements(&self) -> u32 {
self.max_table_elements
}
fn table_max_size_required(&self) -> bool {
self.table_max_size_required
}
}

1651
third_party/rust/wasm-smith/src/core.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,243 @@
use super::*;
use std::convert::TryFrom;
impl Module {
/// Encode this Wasm module into bytes.
pub fn to_bytes(&self) -> Vec<u8> {
self.encoded().finish()
}
fn encoded(&self) -> wasm_encoder::Module {
let mut module = wasm_encoder::Module::new();
self.encode_types(&mut module);
self.encode_imports(&mut module);
self.encode_funcs(&mut module);
self.encode_tables(&mut module);
self.encode_memories(&mut module);
self.encode_tags(&mut module);
self.encode_globals(&mut module);
self.encode_exports(&mut module);
self.encode_start(&mut module);
self.encode_elems(&mut module);
self.encode_data_count(&mut module);
self.encode_code(&mut module);
self.encode_data(&mut module);
module
}
fn encode_types(&self, module: &mut wasm_encoder::Module) {
if !self.should_encode_types {
return;
}
let mut section = wasm_encoder::TypeSection::new();
for ty in &self.types {
match ty {
Type::Func(ty) => {
section.function(ty.params.iter().cloned(), ty.results.iter().cloned());
}
}
}
module.section(&section);
}
fn encode_imports(&self, module: &mut wasm_encoder::Module) {
if !self.should_encode_imports {
return;
}
let mut section = wasm_encoder::ImportSection::new();
for im in &self.imports {
section.import(
&im.module,
&im.field,
translate_entity_type(&im.entity_type),
);
}
module.section(&section);
}
fn encode_tags(&self, module: &mut wasm_encoder::Module) {
if self.num_defined_tags == 0 {
return;
}
let mut tags = wasm_encoder::TagSection::new();
for tag in self.tags[self.tags.len() - self.num_defined_tags..].iter() {
tags.tag(wasm_encoder::TagType {
kind: wasm_encoder::TagKind::Exception,
func_type_idx: tag.func_type_idx,
});
}
module.section(&tags);
}
fn encode_funcs(&self, module: &mut wasm_encoder::Module) {
if self.num_defined_funcs == 0 {
return;
}
let mut funcs = wasm_encoder::FunctionSection::new();
for (ty, _) in self.funcs[self.funcs.len() - self.num_defined_funcs..].iter() {
funcs.function(*ty);
}
module.section(&funcs);
}
fn encode_tables(&self, module: &mut wasm_encoder::Module) {
if self.num_defined_tables == 0 {
return;
}
let mut tables = wasm_encoder::TableSection::new();
for t in self.tables[self.tables.len() - self.num_defined_tables..].iter() {
tables.table(*t);
}
module.section(&tables);
}
fn encode_memories(&self, module: &mut wasm_encoder::Module) {
if self.num_defined_memories == 0 {
return;
}
let mut mems = wasm_encoder::MemorySection::new();
for m in self.memories[self.memories.len() - self.num_defined_memories..].iter() {
mems.memory(*m);
}
module.section(&mems);
}
fn encode_globals(&self, module: &mut wasm_encoder::Module) {
if self.globals.is_empty() {
return;
}
let mut globals = wasm_encoder::GlobalSection::new();
for (idx, expr) in &self.defined_globals {
let ty = &self.globals[*idx as usize];
globals.global(*ty, expr);
}
module.section(&globals);
}
fn encode_exports(&self, module: &mut wasm_encoder::Module) {
if self.exports.is_empty() {
return;
}
let mut exports = wasm_encoder::ExportSection::new();
for (name, kind, idx) in &self.exports {
exports.export(name, *kind, *idx);
}
module.section(&exports);
}
fn encode_start(&self, module: &mut wasm_encoder::Module) {
if let Some(f) = self.start {
module.section(&wasm_encoder::StartSection { function_index: f });
}
}
fn encode_elems(&self, module: &mut wasm_encoder::Module) {
if self.elems.is_empty() {
return;
}
let mut elems = wasm_encoder::ElementSection::new();
let mut exps = vec![];
for el in &self.elems {
let elements = match &el.items {
Elements::Expressions(es) => {
exps.clear();
exps.extend(es.iter().map(|e| match e {
Some(i) => wasm_encoder::Element::Func(*i),
None => wasm_encoder::Element::Null,
}));
wasm_encoder::Elements::Expressions(&exps)
}
Elements::Functions(fs) => wasm_encoder::Elements::Functions(fs),
};
match &el.kind {
ElementKind::Active { table, offset } => {
elems.active(*table, offset, el.ty, elements);
}
ElementKind::Passive => {
elems.passive(el.ty, elements);
}
ElementKind::Declared => {
elems.declared(el.ty, elements);
}
}
}
module.section(&elems);
}
fn encode_data_count(&self, module: &mut wasm_encoder::Module) {
// Without bulk memory there's no need for a data count section,
if !self.config.bulk_memory_enabled() {
return;
}
// ... and also if there's no data no need for a data count section.
if self.data.is_empty() {
return;
}
module.section(&wasm_encoder::DataCountSection {
count: u32::try_from(self.data.len()).unwrap(),
});
}
fn encode_code(&self, module: &mut wasm_encoder::Module) {
if self.code.is_empty() {
return;
}
let mut code = wasm_encoder::CodeSection::new();
for c in &self.code {
// Skip the run-length encoding because it is a little
// annoying to compute; use a length of one for every local.
let mut func = wasm_encoder::Function::new(c.locals.iter().map(|l| (1, *l)));
match &c.instructions {
Instructions::Generated(instrs) => {
for instr in instrs {
func.instruction(instr);
}
func.instruction(&wasm_encoder::Instruction::End);
}
Instructions::Arbitrary(body) => {
func.raw(body.iter().copied());
}
}
code.function(&func);
}
module.section(&code);
}
fn encode_data(&self, module: &mut wasm_encoder::Module) {
if self.data.is_empty() {
return;
}
let mut data = wasm_encoder::DataSection::new();
for seg in &self.data {
match &seg.kind {
DataSegmentKind::Active {
memory_index,
offset,
} => {
data.active(*memory_index, offset, seg.init.iter().copied());
}
DataSegmentKind::Passive => {
data.passive(seg.init.iter().copied());
}
}
}
module.section(&data);
}
}
pub(crate) fn translate_entity_type(ty: &EntityType) -> wasm_encoder::EntityType {
match ty {
EntityType::Tag(t) => wasm_encoder::EntityType::Tag(wasm_encoder::TagType {
kind: wasm_encoder::TagKind::Exception,
func_type_idx: t.func_type_idx,
}),
EntityType::Func(f, _) => wasm_encoder::EntityType::Function(*f),
EntityType::Table(ty) => (*ty).into(),
EntityType::Memory(m) => (*m).into(),
EntityType::Global(g) => (*g).into(),
}
}

View File

@ -1,5 +1,6 @@
use super::*;
use std::mem;
use wasm_encoder::BlockType;
impl Module {
/// Ensure that all of this Wasm module's functions will terminate when

View File

@ -1,907 +0,0 @@
use super::*;
use std::convert::TryFrom;
impl Module {
/// Encode this Wasm module into bytes.
pub fn to_bytes(&self) -> Vec<u8> {
self.encoded().finish()
}
fn encoded(&self) -> wasm_encoder::Module {
let mut module = wasm_encoder::Module::new();
self.encode_initializers(&mut module);
self.encode_funcs(&mut module);
self.encode_tables(&mut module);
self.encode_memories(&mut module);
self.encode_tags(&mut module);
self.encode_globals(&mut module);
self.encode_exports(&mut module);
self.encode_start(&mut module);
self.encode_elems(&mut module);
self.encode_data_count(&mut module);
self.encode_code(&mut module);
self.encode_data(&mut module);
module
}
fn encode_initializers(&self, module: &mut wasm_encoder::Module) {
for init in self.initial_sections.iter() {
match init {
InitialSection::Type(types) => self.encode_types(module, types),
InitialSection::Import(imports) => self.encode_imports(module, imports),
InitialSection::Alias(aliases) => self.encode_aliases(module, aliases),
InitialSection::Instance(list) => self.encode_instances(module, list),
InitialSection::Module(list) => self.encode_modules(module, list),
}
}
}
fn encode_types(&self, module: &mut wasm_encoder::Module, types: &[Type]) {
let mut section = wasm_encoder::TypeSection::new();
for ty in types {
match ty {
Type::Func(ty) => {
section.function(
ty.params.iter().map(|t| translate_val_type(*t)),
ty.results.iter().map(|t| translate_val_type(*t)),
);
}
Type::Module(ty) => {
section.module(
ty.imports.iter().map(|(module, name, ty)| {
(module.as_str(), name.as_deref(), translate_entity_type(ty))
}),
ty.exports
.exports
.iter()
.map(|(name, ty)| (name.as_str(), translate_entity_type(ty))),
);
}
Type::Instance(ty) => {
section.instance(
ty.exports
.iter()
.map(|(name, ty)| (name.as_str(), translate_entity_type(ty))),
);
}
}
}
module.section(&section);
}
fn encode_imports(
&self,
module: &mut wasm_encoder::Module,
imports: &[(String, Option<String>, EntityType)],
) {
let mut section = wasm_encoder::ImportSection::new();
for (module, name, ty) in imports {
section.import(module, name.as_deref(), translate_entity_type(ty));
}
module.section(&section);
}
fn encode_aliases(&self, module: &mut wasm_encoder::Module, imports: &[Alias]) {
let mut section = wasm_encoder::AliasSection::new();
for alias in imports {
match alias {
Alias::InstanceExport {
instance,
kind,
name,
} => {
section.instance_export(*instance, translate_item_kind(kind), name);
}
Alias::OuterType { depth, index } => {
section.outer_type(*depth, *index);
}
Alias::OuterModule { depth, index } => {
section.outer_module(*depth, *index);
}
}
}
module.section(&section);
}
fn encode_instances(&self, module: &mut wasm_encoder::Module, list: &[Instance]) {
let mut section = wasm_encoder::InstanceSection::new();
for instance in list {
section.instantiate(
instance.module,
instance
.args
.iter()
.map(|(name, export)| (name.as_str(), translate_export(export))),
);
}
module.section(&section);
}
fn encode_modules(&self, module: &mut wasm_encoder::Module, list: &[Self]) {
let mut section = wasm_encoder::ModuleSection::new();
for module in list {
let encoded = module.encoded();
section.module(&encoded);
}
module.section(&section);
}
fn encode_tags(&self, module: &mut wasm_encoder::Module) {
if self.num_defined_tags == 0 {
return;
}
let mut tags = wasm_encoder::TagSection::new();
for tag in self.tags[self.tags.len() - self.num_defined_tags..].iter() {
tags.tag(wasm_encoder::TagType {
kind: wasm_encoder::TagKind::Exception,
func_type_idx: tag.func_type_idx,
});
}
module.section(&tags);
}
fn encode_funcs(&self, module: &mut wasm_encoder::Module) {
if self.num_defined_funcs == 0 {
return;
}
let mut funcs = wasm_encoder::FunctionSection::new();
for (ty, _) in self.funcs[self.funcs.len() - self.num_defined_funcs..].iter() {
funcs.function(ty.unwrap());
}
module.section(&funcs);
}
fn encode_tables(&self, module: &mut wasm_encoder::Module) {
if self.num_defined_tables == 0 {
return;
}
let mut tables = wasm_encoder::TableSection::new();
for t in self.tables[self.tables.len() - self.num_defined_tables..].iter() {
tables.table(translate_table_type(t));
}
module.section(&tables);
}
fn encode_memories(&self, module: &mut wasm_encoder::Module) {
if self.num_defined_memories == 0 {
return;
}
let mut mems = wasm_encoder::MemorySection::new();
for m in self.memories[self.memories.len() - self.num_defined_memories..].iter() {
mems.memory(translate_memory_type(m));
}
module.section(&mems);
}
fn encode_globals(&self, module: &mut wasm_encoder::Module) {
if self.globals.is_empty() {
return;
}
let mut globals = wasm_encoder::GlobalSection::new();
for (idx, expr) in &self.defined_globals {
let ty = &self.globals[*idx as usize];
globals.global(translate_global_type(ty), translate_instruction(expr));
}
module.section(&globals);
}
fn encode_exports(&self, module: &mut wasm_encoder::Module) {
if self.exports.is_empty() {
return;
}
let mut exports = wasm_encoder::ExportSection::new();
for (name, export) in &self.exports {
exports.export(name, translate_export(export));
}
module.section(&exports);
}
fn encode_start(&self, module: &mut wasm_encoder::Module) {
if let Some(f) = self.start {
module.section(&wasm_encoder::StartSection { function_index: f });
}
}
fn encode_elems(&self, module: &mut wasm_encoder::Module) {
if self.elems.is_empty() {
return;
}
let mut elems = wasm_encoder::ElementSection::new();
let mut exps = vec![];
for el in &self.elems {
let elem_ty = translate_val_type(el.ty);
let elements = match &el.items {
Elements::Expressions(es) => {
exps.clear();
exps.extend(es.iter().map(|e| match e {
Some(i) => wasm_encoder::Element::Func(*i),
None => wasm_encoder::Element::Null,
}));
wasm_encoder::Elements::Expressions(&exps)
}
Elements::Functions(fs) => wasm_encoder::Elements::Functions(fs),
};
match &el.kind {
ElementKind::Active { table, offset } => {
elems.active(*table, translate_instruction(offset), elem_ty, elements);
}
ElementKind::Passive => {
elems.passive(elem_ty, elements);
}
ElementKind::Declared => {
elems.declared(elem_ty, elements);
}
}
}
module.section(&elems);
}
fn encode_data_count(&self, module: &mut wasm_encoder::Module) {
// Without bulk memory there's no need for a data count section,
if !self.config.bulk_memory_enabled() {
return;
}
// ... and also if there's no data no need for a data count section.
if self.data.is_empty() {
return;
}
module.section(&wasm_encoder::DataCountSection {
count: u32::try_from(self.data.len()).unwrap(),
});
}
fn encode_code(&self, module: &mut wasm_encoder::Module) {
if self.code.is_empty() {
return;
}
let mut code = wasm_encoder::CodeSection::new();
for c in &self.code {
// Skip the run-length encoding because it is a little
// annoying to compute; use a length of one for every local.
let mut func =
wasm_encoder::Function::new(c.locals.iter().map(|l| (1, translate_val_type(*l))));
match &c.instructions {
Instructions::Generated(instrs) => {
for instr in instrs {
func.instruction(translate_instruction(instr));
}
func.instruction(wasm_encoder::Instruction::End);
}
Instructions::Arbitrary(body) => {
func.raw(body.iter().copied());
}
}
code.function(&func);
}
module.section(&code);
}
fn encode_data(&self, module: &mut wasm_encoder::Module) {
if self.data.is_empty() {
return;
}
let mut data = wasm_encoder::DataSection::new();
for seg in &self.data {
match &seg.kind {
DataSegmentKind::Active {
memory_index,
offset,
} => {
data.active(
*memory_index,
translate_instruction(offset),
seg.init.iter().copied(),
);
}
DataSegmentKind::Passive => {
data.passive(seg.init.iter().copied());
}
}
}
module.section(&data);
}
}
fn translate_val_type(ty: ValType) -> wasm_encoder::ValType {
match ty {
ValType::I32 => wasm_encoder::ValType::I32,
ValType::I64 => wasm_encoder::ValType::I64,
ValType::F32 => wasm_encoder::ValType::F32,
ValType::F64 => wasm_encoder::ValType::F64,
ValType::V128 => wasm_encoder::ValType::V128,
ValType::FuncRef => wasm_encoder::ValType::FuncRef,
ValType::ExternRef => wasm_encoder::ValType::ExternRef,
}
}
fn translate_entity_type(ty: &EntityType) -> wasm_encoder::EntityType {
match ty {
EntityType::Tag(t) => wasm_encoder::EntityType::Tag(wasm_encoder::TagType {
kind: wasm_encoder::TagKind::Exception,
func_type_idx: t.func_type_idx,
}),
EntityType::Func(f, _) => wasm_encoder::EntityType::Function(*f),
EntityType::Instance(i, _) => wasm_encoder::EntityType::Instance(*i),
EntityType::Module(i, _) => wasm_encoder::EntityType::Module(*i),
EntityType::Table(ty) => translate_table_type(ty).into(),
EntityType::Memory(m) => translate_memory_type(m).into(),
EntityType::Global(g) => translate_global_type(g).into(),
}
}
fn translate_table_type(ty: &TableType) -> wasm_encoder::TableType {
wasm_encoder::TableType {
element_type: translate_val_type(ty.elem_ty),
minimum: ty.minimum,
maximum: ty.maximum,
}
}
fn translate_memory_type(ty: &MemoryType) -> wasm_encoder::MemoryType {
wasm_encoder::MemoryType {
minimum: ty.minimum,
maximum: ty.maximum,
memory64: ty.memory64,
}
}
fn translate_global_type(ty: &GlobalType) -> wasm_encoder::GlobalType {
wasm_encoder::GlobalType {
val_type: translate_val_type(ty.val_type),
mutable: ty.mutable,
}
}
fn translate_block_type(ty: BlockType) -> wasm_encoder::BlockType {
match ty {
BlockType::Empty => wasm_encoder::BlockType::Empty,
BlockType::Result(ty) => wasm_encoder::BlockType::Result(translate_val_type(ty)),
BlockType::FuncType(f) => wasm_encoder::BlockType::FunctionType(f),
}
}
fn translate_mem_arg(m: MemArg) -> wasm_encoder::MemArg {
wasm_encoder::MemArg {
offset: m.offset,
align: m.align,
memory_index: m.memory_index,
}
}
fn translate_item_kind(kind: &ItemKind) -> wasm_encoder::ItemKind {
match kind {
ItemKind::Tag => wasm_encoder::ItemKind::Tag,
ItemKind::Func => wasm_encoder::ItemKind::Function,
ItemKind::Table => wasm_encoder::ItemKind::Table,
ItemKind::Memory => wasm_encoder::ItemKind::Memory,
ItemKind::Global => wasm_encoder::ItemKind::Global,
ItemKind::Instance => wasm_encoder::ItemKind::Instance,
ItemKind::Module => wasm_encoder::ItemKind::Module,
}
}
fn translate_export(export: &Export) -> wasm_encoder::Export {
match export {
Export::Tag(idx) => wasm_encoder::Export::Tag(*idx),
Export::Func(idx) => wasm_encoder::Export::Function(*idx),
Export::Table(idx) => wasm_encoder::Export::Table(*idx),
Export::Memory(idx) => wasm_encoder::Export::Memory(*idx),
Export::Global(idx) => wasm_encoder::Export::Global(*idx),
Export::Instance(idx) => wasm_encoder::Export::Instance(*idx),
Export::Module(idx) => wasm_encoder::Export::Module(*idx),
}
}
fn translate_instruction(inst: &Instruction) -> wasm_encoder::Instruction {
use Instruction::*;
match *inst {
// Control instructions.
Unreachable => wasm_encoder::Instruction::Unreachable,
Nop => wasm_encoder::Instruction::Nop,
Block(bt) => wasm_encoder::Instruction::Block(translate_block_type(bt)),
Loop(bt) => wasm_encoder::Instruction::Loop(translate_block_type(bt)),
If(bt) => wasm_encoder::Instruction::If(translate_block_type(bt)),
Else => wasm_encoder::Instruction::Else,
Try(bt) => wasm_encoder::Instruction::Try(translate_block_type(bt)),
Delegate(l) => wasm_encoder::Instruction::Delegate(l),
Catch(t) => wasm_encoder::Instruction::Catch(t),
CatchAll => wasm_encoder::Instruction::CatchAll,
End => wasm_encoder::Instruction::End,
Br(x) => wasm_encoder::Instruction::Br(x),
BrIf(x) => wasm_encoder::Instruction::BrIf(x),
BrTable(ref ls, l) => wasm_encoder::Instruction::BrTable(ls, l),
Return => wasm_encoder::Instruction::Return,
Call(x) => wasm_encoder::Instruction::Call(x),
CallIndirect { ty, table } => wasm_encoder::Instruction::CallIndirect { ty, table },
Throw(t) => wasm_encoder::Instruction::Throw(t),
Rethrow(l) => wasm_encoder::Instruction::Rethrow(l),
// Parametric instructions.
Drop => wasm_encoder::Instruction::Drop,
Select => wasm_encoder::Instruction::Select,
// Variable instructions.
LocalGet(x) => wasm_encoder::Instruction::LocalGet(x),
LocalSet(x) => wasm_encoder::Instruction::LocalSet(x),
LocalTee(x) => wasm_encoder::Instruction::LocalTee(x),
GlobalGet(x) => wasm_encoder::Instruction::GlobalGet(x),
GlobalSet(x) => wasm_encoder::Instruction::GlobalSet(x),
// Memory instructions.
I32Load(m) => wasm_encoder::Instruction::I32Load(translate_mem_arg(m)),
I64Load(m) => wasm_encoder::Instruction::I64Load(translate_mem_arg(m)),
F32Load(m) => wasm_encoder::Instruction::F32Load(translate_mem_arg(m)),
F64Load(m) => wasm_encoder::Instruction::F64Load(translate_mem_arg(m)),
I32Load8_S(m) => wasm_encoder::Instruction::I32Load8_S(translate_mem_arg(m)),
I32Load8_U(m) => wasm_encoder::Instruction::I32Load8_U(translate_mem_arg(m)),
I32Load16_S(m) => wasm_encoder::Instruction::I32Load16_S(translate_mem_arg(m)),
I32Load16_U(m) => wasm_encoder::Instruction::I32Load16_U(translate_mem_arg(m)),
I64Load8_S(m) => wasm_encoder::Instruction::I64Load8_S(translate_mem_arg(m)),
I64Load8_U(m) => wasm_encoder::Instruction::I64Load8_U(translate_mem_arg(m)),
I64Load16_S(m) => wasm_encoder::Instruction::I64Load16_S(translate_mem_arg(m)),
I64Load16_U(m) => wasm_encoder::Instruction::I64Load16_U(translate_mem_arg(m)),
I64Load32_S(m) => wasm_encoder::Instruction::I64Load32_S(translate_mem_arg(m)),
I64Load32_U(m) => wasm_encoder::Instruction::I64Load32_U(translate_mem_arg(m)),
I32Store(m) => wasm_encoder::Instruction::I32Store(translate_mem_arg(m)),
I64Store(m) => wasm_encoder::Instruction::I64Store(translate_mem_arg(m)),
F32Store(m) => wasm_encoder::Instruction::F32Store(translate_mem_arg(m)),
F64Store(m) => wasm_encoder::Instruction::F64Store(translate_mem_arg(m)),
I32Store8(m) => wasm_encoder::Instruction::I32Store8(translate_mem_arg(m)),
I32Store16(m) => wasm_encoder::Instruction::I32Store16(translate_mem_arg(m)),
I64Store8(m) => wasm_encoder::Instruction::I64Store8(translate_mem_arg(m)),
I64Store16(m) => wasm_encoder::Instruction::I64Store16(translate_mem_arg(m)),
I64Store32(m) => wasm_encoder::Instruction::I64Store32(translate_mem_arg(m)),
MemorySize(x) => wasm_encoder::Instruction::MemorySize(x),
MemoryGrow(x) => wasm_encoder::Instruction::MemoryGrow(x),
MemoryInit { mem, data } => wasm_encoder::Instruction::MemoryInit { mem, data },
DataDrop(x) => wasm_encoder::Instruction::DataDrop(x),
MemoryCopy { src, dst } => wasm_encoder::Instruction::MemoryCopy { src, dst },
MemoryFill(x) => wasm_encoder::Instruction::MemoryFill(x),
// Numeric instructions.
I32Const(x) => wasm_encoder::Instruction::I32Const(x),
I64Const(x) => wasm_encoder::Instruction::I64Const(x),
F32Const(x) => wasm_encoder::Instruction::F32Const(x),
F64Const(x) => wasm_encoder::Instruction::F64Const(x),
I32Eqz => wasm_encoder::Instruction::I32Eqz,
I32Eq => wasm_encoder::Instruction::I32Eq,
I32Neq => wasm_encoder::Instruction::I32Neq,
I32LtS => wasm_encoder::Instruction::I32LtS,
I32LtU => wasm_encoder::Instruction::I32LtU,
I32GtS => wasm_encoder::Instruction::I32GtS,
I32GtU => wasm_encoder::Instruction::I32GtU,
I32LeS => wasm_encoder::Instruction::I32LeS,
I32LeU => wasm_encoder::Instruction::I32LeU,
I32GeS => wasm_encoder::Instruction::I32GeS,
I32GeU => wasm_encoder::Instruction::I32GeU,
I64Eqz => wasm_encoder::Instruction::I64Eqz,
I64Eq => wasm_encoder::Instruction::I64Eq,
I64Neq => wasm_encoder::Instruction::I64Neq,
I64LtS => wasm_encoder::Instruction::I64LtS,
I64LtU => wasm_encoder::Instruction::I64LtU,
I64GtS => wasm_encoder::Instruction::I64GtS,
I64GtU => wasm_encoder::Instruction::I64GtU,
I64LeS => wasm_encoder::Instruction::I64LeS,
I64LeU => wasm_encoder::Instruction::I64LeU,
I64GeS => wasm_encoder::Instruction::I64GeS,
I64GeU => wasm_encoder::Instruction::I64GeU,
F32Eq => wasm_encoder::Instruction::F32Eq,
F32Neq => wasm_encoder::Instruction::F32Neq,
F32Lt => wasm_encoder::Instruction::F32Lt,
F32Gt => wasm_encoder::Instruction::F32Gt,
F32Le => wasm_encoder::Instruction::F32Le,
F32Ge => wasm_encoder::Instruction::F32Ge,
F64Eq => wasm_encoder::Instruction::F64Eq,
F64Neq => wasm_encoder::Instruction::F64Neq,
F64Lt => wasm_encoder::Instruction::F64Lt,
F64Gt => wasm_encoder::Instruction::F64Gt,
F64Le => wasm_encoder::Instruction::F64Le,
F64Ge => wasm_encoder::Instruction::F64Ge,
I32Clz => wasm_encoder::Instruction::I32Clz,
I32Ctz => wasm_encoder::Instruction::I32Ctz,
I32Popcnt => wasm_encoder::Instruction::I32Popcnt,
I32Add => wasm_encoder::Instruction::I32Add,
I32Sub => wasm_encoder::Instruction::I32Sub,
I32Mul => wasm_encoder::Instruction::I32Mul,
I32DivS => wasm_encoder::Instruction::I32DivS,
I32DivU => wasm_encoder::Instruction::I32DivU,
I32RemS => wasm_encoder::Instruction::I32RemS,
I32RemU => wasm_encoder::Instruction::I32RemU,
I32And => wasm_encoder::Instruction::I32And,
I32Or => wasm_encoder::Instruction::I32Or,
I32Xor => wasm_encoder::Instruction::I32Xor,
I32Shl => wasm_encoder::Instruction::I32Shl,
I32ShrS => wasm_encoder::Instruction::I32ShrS,
I32ShrU => wasm_encoder::Instruction::I32ShrU,
I32Rotl => wasm_encoder::Instruction::I32Rotl,
I32Rotr => wasm_encoder::Instruction::I32Rotr,
I64Clz => wasm_encoder::Instruction::I64Clz,
I64Ctz => wasm_encoder::Instruction::I64Ctz,
I64Popcnt => wasm_encoder::Instruction::I64Popcnt,
I64Add => wasm_encoder::Instruction::I64Add,
I64Sub => wasm_encoder::Instruction::I64Sub,
I64Mul => wasm_encoder::Instruction::I64Mul,
I64DivS => wasm_encoder::Instruction::I64DivS,
I64DivU => wasm_encoder::Instruction::I64DivU,
I64RemS => wasm_encoder::Instruction::I64RemS,
I64RemU => wasm_encoder::Instruction::I64RemU,
I64And => wasm_encoder::Instruction::I64And,
I64Or => wasm_encoder::Instruction::I64Or,
I64Xor => wasm_encoder::Instruction::I64Xor,
I64Shl => wasm_encoder::Instruction::I64Shl,
I64ShrS => wasm_encoder::Instruction::I64ShrS,
I64ShrU => wasm_encoder::Instruction::I64ShrU,
I64Rotl => wasm_encoder::Instruction::I64Rotl,
I64Rotr => wasm_encoder::Instruction::I64Rotr,
F32Abs => wasm_encoder::Instruction::F32Abs,
F32Neg => wasm_encoder::Instruction::F32Neg,
F32Ceil => wasm_encoder::Instruction::F32Ceil,
F32Floor => wasm_encoder::Instruction::F32Floor,
F32Trunc => wasm_encoder::Instruction::F32Trunc,
F32Nearest => wasm_encoder::Instruction::F32Nearest,
F32Sqrt => wasm_encoder::Instruction::F32Sqrt,
F32Add => wasm_encoder::Instruction::F32Add,
F32Sub => wasm_encoder::Instruction::F32Sub,
F32Mul => wasm_encoder::Instruction::F32Mul,
F32Div => wasm_encoder::Instruction::F32Div,
F32Min => wasm_encoder::Instruction::F32Min,
F32Max => wasm_encoder::Instruction::F32Max,
F32Copysign => wasm_encoder::Instruction::F32Copysign,
F64Abs => wasm_encoder::Instruction::F64Abs,
F64Neg => wasm_encoder::Instruction::F64Neg,
F64Ceil => wasm_encoder::Instruction::F64Ceil,
F64Floor => wasm_encoder::Instruction::F64Floor,
F64Trunc => wasm_encoder::Instruction::F64Trunc,
F64Nearest => wasm_encoder::Instruction::F64Nearest,
F64Sqrt => wasm_encoder::Instruction::F64Sqrt,
F64Add => wasm_encoder::Instruction::F64Add,
F64Sub => wasm_encoder::Instruction::F64Sub,
F64Mul => wasm_encoder::Instruction::F64Mul,
F64Div => wasm_encoder::Instruction::F64Div,
F64Min => wasm_encoder::Instruction::F64Min,
F64Max => wasm_encoder::Instruction::F64Max,
F64Copysign => wasm_encoder::Instruction::F64Copysign,
I32WrapI64 => wasm_encoder::Instruction::I32WrapI64,
I32TruncF32S => wasm_encoder::Instruction::I32TruncF32S,
I32TruncF32U => wasm_encoder::Instruction::I32TruncF32U,
I32TruncF64S => wasm_encoder::Instruction::I32TruncF64S,
I32TruncF64U => wasm_encoder::Instruction::I32TruncF64U,
I64ExtendI32S => wasm_encoder::Instruction::I64ExtendI32S,
I64ExtendI32U => wasm_encoder::Instruction::I64ExtendI32U,
I64TruncF32S => wasm_encoder::Instruction::I64TruncF32S,
I64TruncF32U => wasm_encoder::Instruction::I64TruncF32U,
I64TruncF64S => wasm_encoder::Instruction::I64TruncF64S,
I64TruncF64U => wasm_encoder::Instruction::I64TruncF64U,
F32ConvertI32S => wasm_encoder::Instruction::F32ConvertI32S,
F32ConvertI32U => wasm_encoder::Instruction::F32ConvertI32U,
F32ConvertI64S => wasm_encoder::Instruction::F32ConvertI64S,
F32ConvertI64U => wasm_encoder::Instruction::F32ConvertI64U,
F32DemoteF64 => wasm_encoder::Instruction::F32DemoteF64,
F64ConvertI32S => wasm_encoder::Instruction::F64ConvertI32S,
F64ConvertI32U => wasm_encoder::Instruction::F64ConvertI32U,
F64ConvertI64S => wasm_encoder::Instruction::F64ConvertI64S,
F64ConvertI64U => wasm_encoder::Instruction::F64ConvertI64U,
F64PromoteF32 => wasm_encoder::Instruction::F64PromoteF32,
I32ReinterpretF32 => wasm_encoder::Instruction::I32ReinterpretF32,
I64ReinterpretF64 => wasm_encoder::Instruction::I64ReinterpretF64,
F32ReinterpretI32 => wasm_encoder::Instruction::F32ReinterpretI32,
F64ReinterpretI64 => wasm_encoder::Instruction::F64ReinterpretI64,
I32Extend8S => wasm_encoder::Instruction::I32Extend8S,
I32Extend16S => wasm_encoder::Instruction::I32Extend16S,
I64Extend8S => wasm_encoder::Instruction::I64Extend8S,
I64Extend16S => wasm_encoder::Instruction::I64Extend16S,
I64Extend32S => wasm_encoder::Instruction::I64Extend32S,
I32TruncSatF32S => wasm_encoder::Instruction::I32TruncSatF32S,
I32TruncSatF32U => wasm_encoder::Instruction::I32TruncSatF32U,
I32TruncSatF64S => wasm_encoder::Instruction::I32TruncSatF64S,
I32TruncSatF64U => wasm_encoder::Instruction::I32TruncSatF64U,
I64TruncSatF32S => wasm_encoder::Instruction::I64TruncSatF32S,
I64TruncSatF32U => wasm_encoder::Instruction::I64TruncSatF32U,
I64TruncSatF64S => wasm_encoder::Instruction::I64TruncSatF64S,
I64TruncSatF64U => wasm_encoder::Instruction::I64TruncSatF64U,
TypedSelect(ty) => wasm_encoder::Instruction::TypedSelect(translate_val_type(ty)),
RefNull(ty) => wasm_encoder::Instruction::RefNull(translate_val_type(ty)),
RefIsNull => wasm_encoder::Instruction::RefIsNull,
RefFunc(x) => wasm_encoder::Instruction::RefFunc(x),
TableInit { segment, table } => wasm_encoder::Instruction::TableInit { segment, table },
ElemDrop { segment } => wasm_encoder::Instruction::ElemDrop { segment },
TableFill { table } => wasm_encoder::Instruction::TableFill { table },
TableSet { table } => wasm_encoder::Instruction::TableSet { table },
TableGet { table } => wasm_encoder::Instruction::TableGet { table },
TableGrow { table } => wasm_encoder::Instruction::TableGrow { table },
TableSize { table } => wasm_encoder::Instruction::TableSize { table },
TableCopy { src, dst } => wasm_encoder::Instruction::TableCopy { src, dst },
// SIMD instructions.
V128Load { memarg } => wasm_encoder::Instruction::V128Load {
memarg: translate_mem_arg(memarg),
},
V128Load8x8S { memarg } => wasm_encoder::Instruction::V128Load8x8S {
memarg: translate_mem_arg(memarg),
},
V128Load8x8U { memarg } => wasm_encoder::Instruction::V128Load8x8U {
memarg: translate_mem_arg(memarg),
},
V128Load16x4S { memarg } => wasm_encoder::Instruction::V128Load16x4S {
memarg: translate_mem_arg(memarg),
},
V128Load16x4U { memarg } => wasm_encoder::Instruction::V128Load16x4U {
memarg: translate_mem_arg(memarg),
},
V128Load32x2S { memarg } => wasm_encoder::Instruction::V128Load32x2S {
memarg: translate_mem_arg(memarg),
},
V128Load32x2U { memarg } => wasm_encoder::Instruction::V128Load32x2U {
memarg: translate_mem_arg(memarg),
},
V128Load8Splat { memarg } => wasm_encoder::Instruction::V128Load8Splat {
memarg: translate_mem_arg(memarg),
},
V128Load16Splat { memarg } => wasm_encoder::Instruction::V128Load16Splat {
memarg: translate_mem_arg(memarg),
},
V128Load32Splat { memarg } => wasm_encoder::Instruction::V128Load32Splat {
memarg: translate_mem_arg(memarg),
},
V128Load64Splat { memarg } => wasm_encoder::Instruction::V128Load64Splat {
memarg: translate_mem_arg(memarg),
},
V128Load32Zero { memarg } => wasm_encoder::Instruction::V128Load32Zero {
memarg: translate_mem_arg(memarg),
},
V128Load64Zero { memarg } => wasm_encoder::Instruction::V128Load64Zero {
memarg: translate_mem_arg(memarg),
},
V128Store { memarg } => wasm_encoder::Instruction::V128Store {
memarg: translate_mem_arg(memarg),
},
V128Load8Lane { memarg, lane } => wasm_encoder::Instruction::V128Load8Lane {
memarg: translate_mem_arg(memarg),
lane,
},
V128Load16Lane { memarg, lane } => wasm_encoder::Instruction::V128Load16Lane {
memarg: translate_mem_arg(memarg),
lane,
},
V128Load32Lane { memarg, lane } => wasm_encoder::Instruction::V128Load32Lane {
memarg: translate_mem_arg(memarg),
lane,
},
V128Load64Lane { memarg, lane } => wasm_encoder::Instruction::V128Load64Lane {
memarg: translate_mem_arg(memarg),
lane,
},
V128Store8Lane { memarg, lane } => wasm_encoder::Instruction::V128Store8Lane {
memarg: translate_mem_arg(memarg),
lane,
},
V128Store16Lane { memarg, lane } => wasm_encoder::Instruction::V128Store16Lane {
memarg: translate_mem_arg(memarg),
lane,
},
V128Store32Lane { memarg, lane } => wasm_encoder::Instruction::V128Store32Lane {
memarg: translate_mem_arg(memarg),
lane,
},
V128Store64Lane { memarg, lane } => wasm_encoder::Instruction::V128Store64Lane {
memarg: translate_mem_arg(memarg),
lane,
},
V128Const(c) => wasm_encoder::Instruction::V128Const(c),
I8x16Shuffle { lanes } => wasm_encoder::Instruction::I8x16Shuffle { lanes },
I8x16ExtractLaneS { lane } => wasm_encoder::Instruction::I8x16ExtractLaneS { lane },
I8x16ExtractLaneU { lane } => wasm_encoder::Instruction::I8x16ExtractLaneU { lane },
I8x16ReplaceLane { lane } => wasm_encoder::Instruction::I8x16ReplaceLane { lane },
I16x8ExtractLaneS { lane } => wasm_encoder::Instruction::I16x8ExtractLaneS { lane },
I16x8ExtractLaneU { lane } => wasm_encoder::Instruction::I16x8ExtractLaneU { lane },
I16x8ReplaceLane { lane } => wasm_encoder::Instruction::I16x8ReplaceLane { lane },
I32x4ExtractLane { lane } => wasm_encoder::Instruction::I32x4ExtractLane { lane },
I32x4ReplaceLane { lane } => wasm_encoder::Instruction::I32x4ReplaceLane { lane },
I64x2ExtractLane { lane } => wasm_encoder::Instruction::I64x2ExtractLane { lane },
I64x2ReplaceLane { lane } => wasm_encoder::Instruction::I64x2ReplaceLane { lane },
F32x4ExtractLane { lane } => wasm_encoder::Instruction::F32x4ExtractLane { lane },
F32x4ReplaceLane { lane } => wasm_encoder::Instruction::F32x4ReplaceLane { lane },
F64x2ExtractLane { lane } => wasm_encoder::Instruction::F64x2ExtractLane { lane },
F64x2ReplaceLane { lane } => wasm_encoder::Instruction::F64x2ReplaceLane { lane },
I8x16Swizzle => wasm_encoder::Instruction::I8x16Swizzle,
I8x16Splat => wasm_encoder::Instruction::I8x16Splat,
I16x8Splat => wasm_encoder::Instruction::I16x8Splat,
I32x4Splat => wasm_encoder::Instruction::I32x4Splat,
I64x2Splat => wasm_encoder::Instruction::I64x2Splat,
F32x4Splat => wasm_encoder::Instruction::F32x4Splat,
F64x2Splat => wasm_encoder::Instruction::F64x2Splat,
I8x16Eq => wasm_encoder::Instruction::I8x16Eq,
I8x16Ne => wasm_encoder::Instruction::I8x16Ne,
I8x16LtS => wasm_encoder::Instruction::I8x16LtS,
I8x16LtU => wasm_encoder::Instruction::I8x16LtU,
I8x16GtS => wasm_encoder::Instruction::I8x16GtS,
I8x16GtU => wasm_encoder::Instruction::I8x16GtU,
I8x16LeS => wasm_encoder::Instruction::I8x16LeS,
I8x16LeU => wasm_encoder::Instruction::I8x16LeU,
I8x16GeS => wasm_encoder::Instruction::I8x16GeS,
I8x16GeU => wasm_encoder::Instruction::I8x16GeU,
I16x8Eq => wasm_encoder::Instruction::I16x8Eq,
I16x8Ne => wasm_encoder::Instruction::I16x8Ne,
I16x8LtS => wasm_encoder::Instruction::I16x8LtS,
I16x8LtU => wasm_encoder::Instruction::I16x8LtU,
I16x8GtS => wasm_encoder::Instruction::I16x8GtS,
I16x8GtU => wasm_encoder::Instruction::I16x8GtU,
I16x8LeS => wasm_encoder::Instruction::I16x8LeS,
I16x8LeU => wasm_encoder::Instruction::I16x8LeU,
I16x8GeS => wasm_encoder::Instruction::I16x8GeS,
I16x8GeU => wasm_encoder::Instruction::I16x8GeU,
I32x4Eq => wasm_encoder::Instruction::I32x4Eq,
I32x4Ne => wasm_encoder::Instruction::I32x4Ne,
I32x4LtS => wasm_encoder::Instruction::I32x4LtS,
I32x4LtU => wasm_encoder::Instruction::I32x4LtU,
I32x4GtS => wasm_encoder::Instruction::I32x4GtS,
I32x4GtU => wasm_encoder::Instruction::I32x4GtU,
I32x4LeS => wasm_encoder::Instruction::I32x4LeS,
I32x4LeU => wasm_encoder::Instruction::I32x4LeU,
I32x4GeS => wasm_encoder::Instruction::I32x4GeS,
I32x4GeU => wasm_encoder::Instruction::I32x4GeU,
I64x2Eq => wasm_encoder::Instruction::I64x2Eq,
I64x2Ne => wasm_encoder::Instruction::I64x2Ne,
I64x2LtS => wasm_encoder::Instruction::I64x2LtS,
I64x2GtS => wasm_encoder::Instruction::I64x2GtS,
I64x2LeS => wasm_encoder::Instruction::I64x2LeS,
I64x2GeS => wasm_encoder::Instruction::I64x2GeS,
F32x4Eq => wasm_encoder::Instruction::F32x4Eq,
F32x4Ne => wasm_encoder::Instruction::F32x4Ne,
F32x4Lt => wasm_encoder::Instruction::F32x4Lt,
F32x4Gt => wasm_encoder::Instruction::F32x4Gt,
F32x4Le => wasm_encoder::Instruction::F32x4Le,
F32x4Ge => wasm_encoder::Instruction::F32x4Ge,
F64x2Eq => wasm_encoder::Instruction::F64x2Eq,
F64x2Ne => wasm_encoder::Instruction::F64x2Ne,
F64x2Lt => wasm_encoder::Instruction::F64x2Lt,
F64x2Gt => wasm_encoder::Instruction::F64x2Gt,
F64x2Le => wasm_encoder::Instruction::F64x2Le,
F64x2Ge => wasm_encoder::Instruction::F64x2Ge,
V128Not => wasm_encoder::Instruction::V128Not,
V128And => wasm_encoder::Instruction::V128And,
V128AndNot => wasm_encoder::Instruction::V128AndNot,
V128Or => wasm_encoder::Instruction::V128Or,
V128Xor => wasm_encoder::Instruction::V128Xor,
V128Bitselect => wasm_encoder::Instruction::V128Bitselect,
V128AnyTrue => wasm_encoder::Instruction::V128AnyTrue,
I8x16Abs => wasm_encoder::Instruction::I8x16Abs,
I8x16Neg => wasm_encoder::Instruction::I8x16Neg,
I8x16Popcnt => wasm_encoder::Instruction::I8x16Popcnt,
I8x16AllTrue => wasm_encoder::Instruction::I8x16AllTrue,
I8x16Bitmask => wasm_encoder::Instruction::I8x16Bitmask,
I8x16NarrowI16x8S => wasm_encoder::Instruction::I8x16NarrowI16x8S,
I8x16NarrowI16x8U => wasm_encoder::Instruction::I8x16NarrowI16x8U,
I8x16Shl => wasm_encoder::Instruction::I8x16Shl,
I8x16ShrS => wasm_encoder::Instruction::I8x16ShrS,
I8x16ShrU => wasm_encoder::Instruction::I8x16ShrU,
I8x16Add => wasm_encoder::Instruction::I8x16Add,
I8x16AddSatS => wasm_encoder::Instruction::I8x16AddSatS,
I8x16AddSatU => wasm_encoder::Instruction::I8x16AddSatU,
I8x16Sub => wasm_encoder::Instruction::I8x16Sub,
I8x16SubSatS => wasm_encoder::Instruction::I8x16SubSatS,
I8x16SubSatU => wasm_encoder::Instruction::I8x16SubSatU,
I8x16MinS => wasm_encoder::Instruction::I8x16MinS,
I8x16MinU => wasm_encoder::Instruction::I8x16MinU,
I8x16MaxS => wasm_encoder::Instruction::I8x16MaxS,
I8x16MaxU => wasm_encoder::Instruction::I8x16MaxU,
I8x16RoundingAverageU => wasm_encoder::Instruction::I8x16RoundingAverageU,
I16x8ExtAddPairwiseI8x16S => wasm_encoder::Instruction::I16x8ExtAddPairwiseI8x16S,
I16x8ExtAddPairwiseI8x16U => wasm_encoder::Instruction::I16x8ExtAddPairwiseI8x16U,
I16x8Abs => wasm_encoder::Instruction::I16x8Abs,
I16x8Neg => wasm_encoder::Instruction::I16x8Neg,
I16x8Q15MulrSatS => wasm_encoder::Instruction::I16x8Q15MulrSatS,
I16x8AllTrue => wasm_encoder::Instruction::I16x8AllTrue,
I16x8Bitmask => wasm_encoder::Instruction::I16x8Bitmask,
I16x8NarrowI32x4S => wasm_encoder::Instruction::I16x8NarrowI32x4S,
I16x8NarrowI32x4U => wasm_encoder::Instruction::I16x8NarrowI32x4U,
I16x8ExtendLowI8x16S => wasm_encoder::Instruction::I16x8ExtendLowI8x16S,
I16x8ExtendHighI8x16S => wasm_encoder::Instruction::I16x8ExtendHighI8x16S,
I16x8ExtendLowI8x16U => wasm_encoder::Instruction::I16x8ExtendLowI8x16U,
I16x8ExtendHighI8x16U => wasm_encoder::Instruction::I16x8ExtendHighI8x16U,
I16x8Shl => wasm_encoder::Instruction::I16x8Shl,
I16x8ShrS => wasm_encoder::Instruction::I16x8ShrS,
I16x8ShrU => wasm_encoder::Instruction::I16x8ShrU,
I16x8Add => wasm_encoder::Instruction::I16x8Add,
I16x8AddSatS => wasm_encoder::Instruction::I16x8AddSatS,
I16x8AddSatU => wasm_encoder::Instruction::I16x8AddSatU,
I16x8Sub => wasm_encoder::Instruction::I16x8Sub,
I16x8SubSatS => wasm_encoder::Instruction::I16x8SubSatS,
I16x8SubSatU => wasm_encoder::Instruction::I16x8SubSatU,
I16x8Mul => wasm_encoder::Instruction::I16x8Mul,
I16x8MinS => wasm_encoder::Instruction::I16x8MinS,
I16x8MinU => wasm_encoder::Instruction::I16x8MinU,
I16x8MaxS => wasm_encoder::Instruction::I16x8MaxS,
I16x8MaxU => wasm_encoder::Instruction::I16x8MaxU,
I16x8RoundingAverageU => wasm_encoder::Instruction::I16x8RoundingAverageU,
I16x8ExtMulLowI8x16S => wasm_encoder::Instruction::I16x8ExtMulLowI8x16S,
I16x8ExtMulHighI8x16S => wasm_encoder::Instruction::I16x8ExtMulHighI8x16S,
I16x8ExtMulLowI8x16U => wasm_encoder::Instruction::I16x8ExtMulLowI8x16U,
I16x8ExtMulHighI8x16U => wasm_encoder::Instruction::I16x8ExtMulHighI8x16U,
I32x4ExtAddPairwiseI16x8S => wasm_encoder::Instruction::I32x4ExtAddPairwiseI16x8S,
I32x4ExtAddPairwiseI16x8U => wasm_encoder::Instruction::I32x4ExtAddPairwiseI16x8U,
I32x4Abs => wasm_encoder::Instruction::I32x4Abs,
I32x4Neg => wasm_encoder::Instruction::I32x4Neg,
I32x4AllTrue => wasm_encoder::Instruction::I32x4AllTrue,
I32x4Bitmask => wasm_encoder::Instruction::I32x4Bitmask,
I32x4ExtendLowI16x8S => wasm_encoder::Instruction::I32x4ExtendLowI16x8S,
I32x4ExtendHighI16x8S => wasm_encoder::Instruction::I32x4ExtendHighI16x8S,
I32x4ExtendLowI16x8U => wasm_encoder::Instruction::I32x4ExtendLowI16x8U,
I32x4ExtendHighI16x8U => wasm_encoder::Instruction::I32x4ExtendHighI16x8U,
I32x4Shl => wasm_encoder::Instruction::I32x4Shl,
I32x4ShrS => wasm_encoder::Instruction::I32x4ShrS,
I32x4ShrU => wasm_encoder::Instruction::I32x4ShrU,
I32x4Add => wasm_encoder::Instruction::I32x4Add,
I32x4Sub => wasm_encoder::Instruction::I32x4Sub,
I32x4Mul => wasm_encoder::Instruction::I32x4Mul,
I32x4MinS => wasm_encoder::Instruction::I32x4MinS,
I32x4MinU => wasm_encoder::Instruction::I32x4MinU,
I32x4MaxS => wasm_encoder::Instruction::I32x4MaxS,
I32x4MaxU => wasm_encoder::Instruction::I32x4MaxU,
I32x4DotI16x8S => wasm_encoder::Instruction::I32x4DotI16x8S,
I32x4ExtMulLowI16x8S => wasm_encoder::Instruction::I32x4ExtMulLowI16x8S,
I32x4ExtMulHighI16x8S => wasm_encoder::Instruction::I32x4ExtMulHighI16x8S,
I32x4ExtMulLowI16x8U => wasm_encoder::Instruction::I32x4ExtMulLowI16x8U,
I32x4ExtMulHighI16x8U => wasm_encoder::Instruction::I32x4ExtMulHighI16x8U,
I64x2Abs => wasm_encoder::Instruction::I64x2Abs,
I64x2Neg => wasm_encoder::Instruction::I64x2Neg,
I64x2AllTrue => wasm_encoder::Instruction::I64x2AllTrue,
I64x2Bitmask => wasm_encoder::Instruction::I64x2Bitmask,
I64x2ExtendLowI32x4S => wasm_encoder::Instruction::I64x2ExtendLowI32x4S,
I64x2ExtendHighI32x4S => wasm_encoder::Instruction::I64x2ExtendHighI32x4S,
I64x2ExtendLowI32x4U => wasm_encoder::Instruction::I64x2ExtendLowI32x4U,
I64x2ExtendHighI32x4U => wasm_encoder::Instruction::I64x2ExtendHighI32x4U,
I64x2Shl => wasm_encoder::Instruction::I64x2Shl,
I64x2ShrS => wasm_encoder::Instruction::I64x2ShrS,
I64x2ShrU => wasm_encoder::Instruction::I64x2ShrU,
I64x2Add => wasm_encoder::Instruction::I64x2Add,
I64x2Sub => wasm_encoder::Instruction::I64x2Sub,
I64x2Mul => wasm_encoder::Instruction::I64x2Mul,
I64x2ExtMulLowI32x4S => wasm_encoder::Instruction::I64x2ExtMulLowI32x4S,
I64x2ExtMulHighI32x4S => wasm_encoder::Instruction::I64x2ExtMulHighI32x4S,
I64x2ExtMulLowI32x4U => wasm_encoder::Instruction::I64x2ExtMulLowI32x4U,
I64x2ExtMulHighI32x4U => wasm_encoder::Instruction::I64x2ExtMulHighI32x4U,
F32x4Ceil => wasm_encoder::Instruction::F32x4Ceil,
F32x4Floor => wasm_encoder::Instruction::F32x4Floor,
F32x4Trunc => wasm_encoder::Instruction::F32x4Trunc,
F32x4Nearest => wasm_encoder::Instruction::F32x4Nearest,
F32x4Abs => wasm_encoder::Instruction::F32x4Abs,
F32x4Neg => wasm_encoder::Instruction::F32x4Neg,
F32x4Sqrt => wasm_encoder::Instruction::F32x4Sqrt,
F32x4Add => wasm_encoder::Instruction::F32x4Add,
F32x4Sub => wasm_encoder::Instruction::F32x4Sub,
F32x4Mul => wasm_encoder::Instruction::F32x4Mul,
F32x4Div => wasm_encoder::Instruction::F32x4Div,
F32x4Min => wasm_encoder::Instruction::F32x4Min,
F32x4Max => wasm_encoder::Instruction::F32x4Max,
F32x4PMin => wasm_encoder::Instruction::F32x4PMin,
F32x4PMax => wasm_encoder::Instruction::F32x4PMax,
F64x2Ceil => wasm_encoder::Instruction::F64x2Ceil,
F64x2Floor => wasm_encoder::Instruction::F64x2Floor,
F64x2Trunc => wasm_encoder::Instruction::F64x2Trunc,
F64x2Nearest => wasm_encoder::Instruction::F64x2Nearest,
F64x2Abs => wasm_encoder::Instruction::F64x2Abs,
F64x2Neg => wasm_encoder::Instruction::F64x2Neg,
F64x2Sqrt => wasm_encoder::Instruction::F64x2Sqrt,
F64x2Add => wasm_encoder::Instruction::F64x2Add,
F64x2Sub => wasm_encoder::Instruction::F64x2Sub,
F64x2Mul => wasm_encoder::Instruction::F64x2Mul,
F64x2Div => wasm_encoder::Instruction::F64x2Div,
F64x2Min => wasm_encoder::Instruction::F64x2Min,
F64x2Max => wasm_encoder::Instruction::F64x2Max,
F64x2PMin => wasm_encoder::Instruction::F64x2PMin,
F64x2PMax => wasm_encoder::Instruction::F64x2PMax,
I32x4TruncSatF32x4S => wasm_encoder::Instruction::I32x4TruncSatF32x4S,
I32x4TruncSatF32x4U => wasm_encoder::Instruction::I32x4TruncSatF32x4U,
F32x4ConvertI32x4S => wasm_encoder::Instruction::F32x4ConvertI32x4S,
F32x4ConvertI32x4U => wasm_encoder::Instruction::F32x4ConvertI32x4U,
I32x4TruncSatF64x2SZero => wasm_encoder::Instruction::I32x4TruncSatF64x2SZero,
I32x4TruncSatF64x2UZero => wasm_encoder::Instruction::I32x4TruncSatF64x2UZero,
F64x2ConvertLowI32x4S => wasm_encoder::Instruction::F64x2ConvertLowI32x4S,
F64x2ConvertLowI32x4U => wasm_encoder::Instruction::F64x2ConvertLowI32x4U,
F32x4DemoteF64x2Zero => wasm_encoder::Instruction::F32x4DemoteF64x2Zero,
F64x2PromoteLowF32x4 => wasm_encoder::Instruction::F64x2PromoteLowF32x4,
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,42 @@
use arbitrary::{Arbitrary, Unstructured};
use rand::{rngs::SmallRng, RngCore, SeedableRng};
use wasm_smith::Component;
#[test]
fn smoke_test_component() {
const NUM_RUNS: usize = 4096;
let mut rng = SmallRng::seed_from_u64(0);
let mut buf = vec![0; 1024];
let mut ok_count = 0;
for _ in 0..NUM_RUNS {
rng.fill_bytes(&mut buf);
let u = Unstructured::new(&buf);
if let Ok(component) = Component::arbitrary_take_rest(u) {
ok_count += 1;
let component = component.to_bytes();
let mut validator =
wasmparser::Validator::new_with_features(wasmparser::WasmFeatures {
component_model: true,
..Default::default()
});
if let Err(e) = validator.validate_all(&component) {
std::fs::write("component.wasm", &component).unwrap();
panic!(
"generated component should be valid; failing binary written \
to `component.wasm`. Error: {}",
e
);
}
}
}
println!(
"Generated {} / {} ({:.02}%) arbitrary components okay",
ok_count,
NUM_RUNS,
ok_count as f64 / NUM_RUNS as f64 * 100.0
);
}

View File

@ -0,0 +1,297 @@
use arbitrary::{Arbitrary, Unstructured};
use rand::{rngs::SmallRng, RngCore, SeedableRng};
use std::collections::HashMap;
use wasm_smith::{Config, ConfiguredModule, Module, SwarmConfig};
use wasmparser::{Parser, TypeRef, ValType, Validator, WasmFeatures};
#[test]
fn smoke_test_module() {
let mut rng = SmallRng::seed_from_u64(0);
let mut buf = vec![0; 2048];
for _ in 0..1024 {
rng.fill_bytes(&mut buf);
let u = Unstructured::new(&buf);
if let Ok(module) = Module::arbitrary_take_rest(u) {
let wasm_bytes = module.to_bytes();
let mut validator = Validator::new_with_features(wasm_features());
validate(&mut validator, &wasm_bytes);
}
}
}
#[test]
fn smoke_test_ensure_termination() {
let mut rng = SmallRng::seed_from_u64(0);
let mut buf = vec![0; 2048];
for _ in 0..1024 {
rng.fill_bytes(&mut buf);
let u = Unstructured::new(&buf);
if let Ok(mut module) = Module::arbitrary_take_rest(u) {
module.ensure_termination(10);
let wasm_bytes = module.to_bytes();
let mut validator = Validator::new_with_features(wasm_features());
validate(&mut validator, &wasm_bytes);
}
}
}
#[test]
fn smoke_test_swarm_config() {
let mut rng = SmallRng::seed_from_u64(0);
let mut buf = vec![0; 2048];
for _ in 0..1024 {
rng.fill_bytes(&mut buf);
let u = Unstructured::new(&buf);
if let Ok(module) = ConfiguredModule::<SwarmConfig>::arbitrary_take_rest(u) {
let module = module.module;
let wasm_bytes = module.to_bytes();
let mut validator = Validator::new_with_features(wasm_features());
validate(&mut validator, &wasm_bytes);
}
}
}
#[test]
fn multi_value_disabled() {
let mut rng = SmallRng::seed_from_u64(42);
let mut buf = vec![0; 2048];
for _ in 0..10 {
rng.fill_bytes(&mut buf);
let mut u = Unstructured::new(&buf);
let mut cfg = SwarmConfig::arbitrary(&mut u).unwrap();
cfg.multi_value_enabled = false;
if let Ok(module) = Module::new(cfg, &mut u) {
let wasm_bytes = module.to_bytes();
let mut features = wasm_features();
features.multi_value = false;
let mut validator = Validator::new_with_features(features);
validate(&mut validator, &wasm_bytes);
}
}
}
#[test]
fn smoke_can_smith_valid_webassembly_one_point_oh() {
let mut rng = SmallRng::seed_from_u64(42);
let mut buf = vec![0; 10240];
for _ in 0..100 {
rng.fill_bytes(&mut buf);
let mut u = Unstructured::new(&buf);
let mut cfg = SwarmConfig::arbitrary(&mut u).unwrap();
cfg.sign_extension_enabled = false;
cfg.saturating_float_to_int_enabled = false;
cfg.reference_types_enabled = false;
cfg.multi_value_enabled = false;
cfg.bulk_memory_enabled = false;
cfg.simd_enabled = false;
cfg.relaxed_simd_enabled = false;
cfg.exceptions_enabled = false;
cfg.memory64_enabled = false;
cfg.max_memories = 1;
cfg.max_tables = 1;
let features = parser_features_from_config(&cfg);
if let Ok(module) = Module::new(cfg, &mut u) {
let wasm_bytes = module.to_bytes();
// This table should set to `true` only features specified in wasm-core-1 spec.
let mut validator = Validator::new_with_features(features);
validate(&mut validator, &wasm_bytes);
}
}
}
#[test]
fn smoke_test_imports_config() {
let mut n_partial = 0;
let mut global_imports_seen = HashMap::<_, bool>::new();
let mut rng = SmallRng::seed_from_u64(11);
let mut buf = vec![0; 512];
for _ in 0..1024 {
rng.fill_bytes(&mut buf);
let mut u = Unstructured::new(&buf);
let (config, available) = import_config(&mut u);
let features = parser_features_from_config(&config);
if let Ok(module) = Module::new(config, &mut u) {
let wasm_bytes = module.to_bytes();
let mut validator = Validator::new_with_features(features);
validate(&mut validator, &wasm_bytes);
let mut imports_seen = available
.iter()
.map(|(m, f, t)| ((*m, *f), (false, t)))
.collect::<HashMap<_, _>>();
let mut sig_types = Vec::new();
for payload in Parser::new(0).parse_all(&wasm_bytes) {
let payload = payload.unwrap();
if let wasmparser::Payload::TypeSection(mut rdr) = payload {
// Gather the signature types to later check function types against.
while let Ok(ty) = rdr.read() {
match ty {
wasmparser::Type::Func(ft) => sig_types.push(ft),
}
}
} else if let wasmparser::Payload::ImportSection(mut rdr) = payload {
// Read out imports, checking that they all are within the list of expected
// imports (i.e. we don't generate arbitrary ones), and that we handle the
// logic correctly (i.e. signature types are as expected)
while let Ok(import) = rdr.read() {
use AvailableImportKind as I;
let entry = imports_seen.get_mut(&(import.module, import.name));
match (entry, &import.ty) {
(Some((true, _)), _) => panic!("duplicate import of {:?}", import),
(Some((seen, I::Memory)), TypeRef::Memory(_)) => *seen = true,
(Some((seen, I::Global(t))), TypeRef::Global(gt))
if *t == gt.content_type =>
{
*seen = true
}
(Some((seen, I::Table(t))), TypeRef::Table(tt))
if *t == tt.element_type =>
{
*seen = true
}
(Some((seen, I::Func(p, r))), TypeRef::Func(sig_idx))
if &sig_types[*sig_idx as usize].params[..] == *p
&& &sig_types[*sig_idx as usize].returns[..] == *r =>
{
*seen = true
}
(
Some((seen, I::Tag(p))),
TypeRef::Tag(wasmparser::TagType { func_type_idx, .. }),
) if &sig_types[*func_type_idx as usize].params[..] == *p
&& sig_types[*func_type_idx as usize].returns.is_empty() =>
{
*seen = true
}
(Some((_, expected)), _) => panic!(
"import {:?} type mismatch, expected: {:?}",
import, expected
),
(None, _) => panic!("import of an unknown entity: {:?}", import),
}
}
}
}
// Verify that we have seen both instances with partial imports (i.e. we don't always
// just copy over all the imports from the example module) and also that we eventually
// observe all of the imports being used (i.e. selection is reasonably random)
for (m, f, _) in &available[..] {
let seen = imports_seen[&(*m, *f)];
let global_seen = global_imports_seen
.entry((m.to_string(), f.to_string()))
.or_default();
*global_seen |= seen.0;
}
if !imports_seen.values().all(|v| v.0) {
n_partial += 1;
}
}
}
assert!(global_imports_seen.values().all(|v| *v));
assert!(n_partial > 0);
}
fn wasm_features() -> WasmFeatures {
WasmFeatures {
multi_memory: true,
relaxed_simd: true,
memory64: true,
exceptions: true,
..WasmFeatures::default()
}
}
#[derive(Debug)]
enum AvailableImportKind {
Func(&'static [ValType], &'static [ValType]),
Tag(&'static [ValType]),
Global(ValType),
Table(ValType),
Memory,
}
fn import_config(
u: &mut Unstructured,
) -> (
SwarmConfig,
Vec<(&'static str, &'static str, AvailableImportKind)>,
) {
let mut config = SwarmConfig::arbitrary(u).expect("arbitrary swarm");
config.exceptions_enabled = u.arbitrary().expect("exceptions enabled for swarm");
let available = {
use {AvailableImportKind::*, ValType::*};
vec![
("env", "pi", Func(&[I32], &[])),
("env", "pi2", Func(&[I32], &[])),
("env", "pipi2", Func(&[I32, I32], &[])),
("env", "po", Func(&[], &[I32])),
("env", "pipo", Func(&[I32], &[I32])),
("env", "popo", Func(&[], &[I32, I32])),
("env", "mem", Memory),
("env", "tbl", Table(FuncRef)),
("vars", "g", Global(I64)),
("tags", "tag1", Tag(&[I32])),
]
};
config.available_imports = Some(
wat::parse_str(
r#"
(module
(import "env" "pi" (func (param i32)))
(import "env" "pi2" (func (param i32)))
(import "env" "pipi2" (func (param i32 i32)))
(import "env" "po" (func (result i32)))
(import "env" "pipo" (func (param i32) (result i32)))
(import "env" "popo" (func (result i32 i32)))
(import "env" "mem" (memory 1 16))
(import "env" "tbl" (table 1 16 funcref))
(import "vars" "g" (global i64))
(import "tags" "tag1" (tag (param i32)))
)
"#,
)
.unwrap()
.into(),
);
(config, available)
}
fn parser_features_from_config(config: &impl Config) -> WasmFeatures {
WasmFeatures {
mutable_global: true,
saturating_float_to_int: config.saturating_float_to_int_enabled(),
sign_extension: config.sign_extension_ops_enabled(),
reference_types: config.reference_types_enabled(),
multi_value: config.multi_value_enabled(),
bulk_memory: config.bulk_memory_enabled(),
simd: config.simd_enabled(),
relaxed_simd: config.relaxed_simd_enabled(),
multi_memory: config.max_memories() > 1,
exceptions: config.exceptions_enabled(),
memory64: config.memory64_enabled(),
threads: false,
tail_call: false,
deterministic_only: false,
extended_const: false,
component_model: false,
}
}
fn validate(validator: &mut Validator, bytes: &[u8]) {
let err = match validator.validate_all(bytes) {
Ok(_) => return,
Err(e) => e,
};
drop(std::fs::write("test.wasm", &bytes));
if let Ok(text) = wasmprinter::print_bytes(bytes) {
drop(std::fs::write("test.wat", &text));
}
panic!("wasm failed to validate {:?}", err);
}

View File

@ -1,84 +0,0 @@
use arbitrary::{Arbitrary, Unstructured};
use rand::{rngs::SmallRng, RngCore, SeedableRng};
use wasm_smith::{ConfiguredModule, Module, SwarmConfig};
use wasmparser::{Validator, WasmFeatures};
fn wasm_features() -> WasmFeatures {
WasmFeatures {
multi_value: true,
multi_memory: true,
bulk_memory: true,
reference_types: true,
simd: true,
memory64: true,
exceptions: true,
..WasmFeatures::default()
}
}
#[test]
fn smoke_test_module() {
let mut rng = SmallRng::seed_from_u64(0);
let mut buf = vec![0; 1024];
for _ in 0..1024 {
rng.fill_bytes(&mut buf);
let u = Unstructured::new(&buf);
if let Ok(module) = Module::arbitrary_take_rest(u) {
let wasm_bytes = module.to_bytes();
let mut validator = Validator::new();
validator.wasm_features(wasm_features());
validate(&mut validator, &wasm_bytes);
}
}
}
#[test]
fn smoke_test_ensure_termination() {
let mut rng = SmallRng::seed_from_u64(0);
let mut buf = vec![0; 1024];
for _ in 0..1024 {
rng.fill_bytes(&mut buf);
let u = Unstructured::new(&buf);
if let Ok(mut module) = Module::arbitrary_take_rest(u) {
module.ensure_termination(10);
let wasm_bytes = module.to_bytes();
let mut validator = Validator::new();
validator.wasm_features(wasm_features());
validate(&mut validator, &wasm_bytes);
}
}
}
#[test]
fn smoke_test_swarm_config() {
let mut rng = SmallRng::seed_from_u64(0);
let mut buf = vec![0; 1024];
for _ in 0..1024 {
rng.fill_bytes(&mut buf);
let u = Unstructured::new(&buf);
if let Ok(module) = ConfiguredModule::<SwarmConfig>::arbitrary_take_rest(u) {
let module = module.module;
let wasm_bytes = module.to_bytes();
let mut validator = Validator::new();
let mut features = wasm_features();
features.module_linking = module.config().module_linking_enabled();
validator.wasm_features(features);
validate(&mut validator, &wasm_bytes);
}
}
}
fn validate(validator: &mut Validator, bytes: &[u8]) {
let err = match validator.validate_all(bytes) {
Ok(()) => return,
Err(e) => e,
};
drop(std::fs::write("test.wasm", &bytes));
if let Ok(text) = wasmprinter::print_bytes(bytes) {
drop(std::fs::write("test.wat", &text));
}
panic!("wasm failed to validate {:?}", err);
}

View File

@ -1 +1 @@
{"files":{"Cargo.lock":"b05bfb3f2377689cbeadee916519217a4a8bcca36b644458fb0d0975d39451c5","Cargo.toml":"451b39c33f593385348d4be4c29c40c13cf318d690e583e86127227ff1caa62e","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"1c3b4f8db61a673ee2f7dc66118b1008ce8d1a7d0f5197fbe87f1271b23de3bd","benches/benchmark.rs":"e416b75903112d91fa303e2a9cabe16dd14fa83c0f1dcf6872fd4e304ffc7772","compare-with-main.sh":"6feeddbc1d4446c8ee98057dd4befb72d2c1784373819936165e9de280545f76","examples/simple.rs":"606072a46c5c80df29da3ecd98a989feb1289243550033cd3c3e1df6045ce8ce","src/binary_reader.rs":"c79620b270db7dd7d96eeb7edc3ed5653122a4d91e87a8af093c122659c42e20","src/lib.rs":"372776c7339cc879ba2a1109e4692d09441dd6832955ed48aed1806b135b72a4","src/limits.rs":"f66a16a5a479d38d5109b2e7504b72a85bb2e0ea6f5a6b6b76f9533cf5595f46","src/module_resources.rs":"372784b2d889c72df6eea6ac2a5a285ecaec43d9216a263143453860f336dbeb","src/operators_validator.rs":"bd537a3bd065a310d5aa91b4a3565ad968651116822f9e023403c1d1659f639e","src/parser.rs":"ec1f3b40322126c6ea38d3dea484a5f754978dfdfd8f8db62c4bb1ff9cfaa4e3","src/primitives.rs":"1f9372200d04a1f84ef089c87168adb08b90640d6bbe84c0ea15dc6561f7c3ef","src/readers/alias_section.rs":"0837521da591555307d6008606308b36b517ce4cb4ea95f9d4bcf608c5fc1b44","src/readers/code_section.rs":"d7d8be8f8bf158dac6ba7ee1d6583ea386e440f728a1f6ce1aa2e91352f884f4","src/readers/data_section.rs":"be92b58b09823574b83fbdb9b9fd32ff57fa054c842b5c24861672caf4726061","src/readers/element_section.rs":"f168a3cb02439aeaa81621525e2747d3bc4743fac2237dcdf8658b67e010ca08","src/readers/event_section.rs":"3848772ed4e0ca7886d92bf02102f71141af41cb660eba5c0107db2423aeb8d0","src/readers/export_section.rs":"3fe296f1789e789009a79115052194a1352d947f2a8830945d6b7d9983bb8579","src/readers/function_section.rs":"5467d7a375c22a4cc225819212e616f275ef01516f185b346eae2ffbb5c53cb3","src/readers/global_section.rs":"359450911ac662503f90288798baec2415df6d3b80990a7b75794683df7894b8","src/readers/import_section.rs":"80906451f78c64d31a76772d97c96d18d208eeabaaaf82372b0567a8991795c1","src/readers/init_expr.rs":"7020c80013dad4518a5f969c3ab4d624b46d778f03e632871cf343964f63441c","src/readers/instance_section.rs":"178663548499468c1911ac1d25aaab8f02bce48e57b06fd207fe0cce7d3c2fd7","src/readers/linking_section.rs":"db3091a48827a5b035e2f79f40f7ed9a7ea10acd4db6ab2bbd01e17a65a4265e","src/readers/memory_section.rs":"67d8457d3167b39fc9ae2c04f3c3e28bc10be97bbdaccd681675fb8d3eba2bd3","src/readers/mod.rs":"fb788013f1cb28419f44dd9ab111c09b76ef060e053ed5d72e6b05663fd02ec9","src/readers/module_code_section.rs":"8c7be8afdfde8e5feffc0d13a8319eb7de459077369a863cee984aa91957f361","src/readers/module_section.rs":"75b9564a135aac154e7f31fba8023438f7a7babb8a426ec0d8b1d894c64ac960","src/readers/name_section.rs":"d5a448a6bd3a20e06f4a4816a2248b2305add19905eb9ccd045104ff45561759","src/readers/operators.rs":"3800f0321a776ddc5e8fb030828e4f2a65ebafa4b7f0808774384559ddfe49ea","src/readers/producers_section.rs":"77f93449e4bdcd61e4c79e47a685742f49cd5dac837ba002bce14120f14c9470","src/readers/reloc_section.rs":"e48e6acaa5145d6fbe1d74eb406ee59c43235faa47fbf0b07288504e60573a5e","src/readers/section_reader.rs":"e99763ce9c48994fd1e92f011a449936c4206a5c91d50fa580d003b6cc824ec5","src/readers/table_section.rs":"5d94185f68c4c7526a8836a2ebdb5b20fe754af58b68d2d0eb8fea62b7e6fe71","src/readers/type_section.rs":"87a54d238bf900aac0d0508e5c644d71b1e591df99367587feb68146a25a5a61","src/validator.rs":"802b64ce8110d0c241b6011786820be496b835c91deb4bc4557ac46670a1f4e5","src/validator/func.rs":"077d50113587d7ef066acfc23611c89e24776f9d3d4e5c4d980cb54ec84acf56"},"package":"52144d4c78e5cf8b055ceab8e5fa22814ce4315d6002ad32cfd914f37c12fd65"}
{"files":{"Cargo.lock":"46bc00e7077b7968ca066ebe6d60a327b886cdf5e8d4c5d081f905e52802c0d3","Cargo.toml":"a7143b24f92d2e797e3491a04c37e59367cba6932a584379dbfcb85b03e8680f","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"1c3b4f8db61a673ee2f7dc66118b1008ce8d1a7d0f5197fbe87f1271b23de3bd","benches/benchmark.rs":"b4292376262051e0a7b21d0e4c31c9244ea83bc2870c5c88417693bd9d22dceb","compare-with-main.sh":"6feeddbc1d4446c8ee98057dd4befb72d2c1784373819936165e9de280545f76","examples/simple.rs":"e9eb076367cc0932e2a32651372defa4a27ef800f47fad28c0ef840ba8ea7e08","src/binary_reader.rs":"18e4a1a3dd77de2e9b377bff44b0807bcd955da662ae92eb5626b76a44c8536d","src/lib.rs":"513e383504bb1c6453419ca64de08aac62d9b211b1e5cd0e02dc88f9c760ec01","src/limits.rs":"cdd905ec48244145330550b4d37f3c7d1aa85acf35ee68cddcb422c7fc8f432b","src/parser.rs":"91e894c607ccb41f41002eff9e7ef193444a65e3225dc632b12be97976d70efc","src/readers.rs":"6986052ea86daf7e09747e1ba3411a1f6b82022d0d12f2b9c925214592a1d0c0","src/readers/component.rs":"b65a243321477082e7e310db6c1a7987af9a2ae73d69520480f5244dce17f96c","src/readers/component/aliases.rs":"384c20e1c1f4d646a1f325e677a8752a2e8a7092f0686dc30556b9ea452279db","src/readers/component/canonicals.rs":"dd791b39ff03d9133d48b950876a0074bf57be3a3e01e0d921e7e051f0284adb","src/readers/component/exports.rs":"47ca4c6f2dcbc02f7d45f331caef84e0f6ba8033fdfbe7c396e31c0509d41b33","src/readers/component/imports.rs":"ab70ec17bcf301ef6a09b6ee52e6f6133c2110a2dda9b401826435296871ea50","src/readers/component/instances.rs":"80b6e5456a6fe787159753955b042a8232bcc73ac90f9b54e2dc8b657218c049","src/readers/component/start.rs":"201fda6866b7a3293597d8ff7b9793510d0f39f96cad7d9badab715f682788df","src/readers/component/types.rs":"b6ee5a3290e6dc823033036f6c6232617a3f0180b1f5da4d7f8d112f1c0416aa","src/readers/core.rs":"6fa41494fce1e9e6bb9f890db4089c1ba5fa6a440927c37b1754d5b08f7f9c49","src/readers/core/code.rs":"563a20baf2121547762defab467ebb55878e5c42adc374213875bada4412c439","src/readers/core/custom.rs":"f80d3a994e8778a912319834228cbb772c65a4b6b1f25b41fe00d220d388831f","src/readers/core/data.rs":"6060f1d7e791225902b619c124099a130123b1c9f8b803504bfa719d8dd30368","src/readers/core/elements.rs":"b6a89d305b8296d5b54dd331013c53a6541d7e6e10838c75aba9cc5892a3a70d","src/readers/core/exports.rs":"e89609dc8459afd6b8ac21674d1274a3f715a68340b96edddc4548ccdaa5297a","src/readers/core/functions.rs":"a5cd2ea6b23268bceaa508322597223c824eb74fbcc98de784311cedccac4e9d","src/readers/core/globals.rs":"6fa4592234aa129ba50c77b2d8bd9b78c5aff16b4797d17a146c5145a582805c","src/readers/core/imports.rs":"a698e134dae961a0bd23ac8e6f4f0c6ce2a6c4b84011b2f71a9ad3375f9a4dc4","src/readers/core/init.rs":"d85665d1fd7e2714d24d19f59c699efa878ea460182dd755634fc7332f604960","src/readers/core/linking.rs":"bef98836b6e99c3be4631e5000512ee12a89405da33ff275b133d456ead2eda2","src/readers/core/memories.rs":"8b1b3ae7ae755f5ac234fcec00207e6927532f7eecb1ba16870b154fbbcac622","src/readers/core/names.rs":"844eef46d57a41846863377c431eaeafe5bc56d5d5f1ceb486724258ba175454","src/readers/core/operators.rs":"bf9d3bbd9ad8019e7f7741d59500d5e77fecc2cd549fbd7a7ec59ba59d6b5a3d","src/readers/core/producers.rs":"3ddeecdcb31f1314c95151dce97b7f6e7bb9eea892a7027a4bce5cabb751b9ba","src/readers/core/relocs.rs":"de256db170e95ec65e463d03982a93f4b512c5723c9945e1c8237512c36cd3d9","src/readers/core/tables.rs":"a7bae8a527b4dfec7ae7f09d1fb44b725ef269b2b595ead9f301b7e2cbcac3c6","src/readers/core/tags.rs":"84ee3ac75c5787f51886ed397e0460da7a98539568ee9fed70be098cdb6be841","src/readers/core/types.rs":"3de6e5d4ad3eed8e8f45bf415ae95a8bd1eb55d8440fcc3c55ac62f23944a329","src/resources.rs":"17517657f7ca17a31c59e4f45d77b89cce9ed9a9c226d10b6df5cf1a904f558a","src/validator.rs":"e28022c245c5751587369f4ff125a9a95122877a43a4e618d3cb6bcc58ab5d16","src/validator/component.rs":"4b6e410752d6d3676e330284144422535ec31648ee884d9edc34fe88d4ccec36","src/validator/core.rs":"32123d72668f13505f7a77a8646c1be406712fada24b690a6d8cb996e7f6b5cf","src/validator/func.rs":"a865a283a7fb46c65f4f8c85f1ac324b6c1ddb8ff99dadee73f8ab596559d7e3","src/validator/operators.rs":"feb197e9a1f59ff5463e3c58dd4a1c1a8838109779bdb19b5f567c47b3e0282d","src/validator/types.rs":"99668d8d26e32c286534ff302c0e6d9368ea78c772185aad2444f7cb17e7fffb"},"package":"5c04e207cd2e8ecb6f9bd28a2cf3119b4c6bfeee6fe3a25cc1daf8041d00a875"}

View File

@ -4,9 +4,9 @@ version = 3
[[package]]
name = "anyhow"
version = "1.0.40"
version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b"
checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704"
[[package]]
name = "atty"
@ -21,21 +21,21 @@ dependencies = [
[[package]]
name = "autocfg"
version = "1.0.1"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.2.1"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bstr"
version = "0.2.16"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90682c8d613ad3373e66de8c6411e0ae2ab2571e879d2efbf73558cc66f21279"
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
dependencies = [
"lazy_static",
"memchr",
@ -45,21 +45,15 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.6.1"
version = "3.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
[[package]]
name = "cast"
version = "0.2.6"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57cdfa5d50aad6cb4d44dcab6101a7f79925bd59d82ca42f38a9856a28865374"
checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a"
dependencies = [
"rustc_version",
]
@ -72,9 +66,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "2.33.3"
version = "2.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
dependencies = [
"bitflags",
"textwrap",
@ -83,16 +77,16 @@ dependencies = [
[[package]]
name = "criterion"
version = "0.3.4"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab327ed7354547cc2ef43cbe20ef68b988e70b4b593cbd66a2a61733123a3d23"
checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10"
dependencies = [
"atty",
"cast",
"clap",
"criterion-plot",
"csv",
"itertools 0.10.0",
"itertools",
"lazy_static",
"num-traits",
"oorandom",
@ -109,19 +103,19 @@ dependencies = [
[[package]]
name = "criterion-plot"
version = "0.4.3"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e022feadec601fba1649cfa83586381a4ad31c6bf3a9ab7d408118b05dd9889d"
checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57"
dependencies = [
"cast",
"itertools 0.9.0",
"itertools",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.1"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c"
dependencies = [
"cfg-if",
"crossbeam-utils",
@ -129,9 +123,9 @@ dependencies = [
[[package]]
name = "crossbeam-deque"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
dependencies = [
"cfg-if",
"crossbeam-epoch",
@ -140,26 +134,26 @@ dependencies = [
[[package]]
name = "crossbeam-epoch"
version = "0.9.4"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52fb27eab85b17fbb9f6fd667089e07d6a2eb8743d02639ee7f6a7a7729c9c94"
checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"lazy_static",
"memoffset",
"once_cell",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.4"
version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4feb231f0d4d6af81aed15928e58ecf5816aa62a2393e2c82f46973e92a9a278"
checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83"
dependencies = [
"autocfg",
"cfg-if",
"lazy_static",
"once_cell",
]
[[package]]
@ -170,7 +164,7 @@ checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
dependencies = [
"bstr",
"csv-core",
"itoa",
"itoa 0.4.8",
"ryu",
"serde",
]
@ -186,9 +180,9 @@ dependencies = [
[[package]]
name = "either"
version = "1.6.1"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be"
[[package]]
name = "getopts"
@ -201,48 +195,61 @@ dependencies = [
[[package]]
name = "half"
version = "1.7.1"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "hashbrown"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
[[package]]
name = "hermit-abi"
version = "0.1.18"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "itertools"
version = "0.9.0"
name = "indexmap"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
dependencies = [
"either",
"autocfg",
"hashbrown",
]
[[package]]
name = "itertools"
version = "0.10.0"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319"
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "0.4.7"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "itoa"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
[[package]]
name = "js-sys"
version = "0.3.51"
version = "0.3.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062"
checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27"
dependencies = [
"wasm-bindgen",
]
@ -255,73 +262,70 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.94"
version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
[[package]]
name = "log"
version = "0.4.14"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.4.0"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memoffset"
version = "0.6.3"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
[[package]]
name = "num-traits"
version = "0.2.14"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.13.0"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "once_cell"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
[[package]]
name = "oorandom"
version = "11.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]]
name = "pest"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
dependencies = [
"ucd-trie",
]
[[package]]
name = "plotters"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45ca0ae5f169d0917a7c7f5a9c1a3d3d9598f18f529dd2b8373ed988efea307a"
checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a"
dependencies = [
"num-traits",
"plotters-backend",
@ -332,42 +336,42 @@ dependencies = [
[[package]]
name = "plotters-backend"
version = "0.3.0"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b07fffcddc1cb3a1de753caa4e4df03b79922ba43cf882acc1bdd7e8df9f4590"
checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c"
[[package]]
name = "plotters-svg"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b38a02e23bd9604b842a812063aec4ef702b57989c37b655254bb61c471ad211"
checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9"
dependencies = [
"plotters-backend",
]
[[package]]
name = "proc-macro2"
version = "1.0.26"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
dependencies = [
"unicode-xid",
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.9"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rayon"
version = "1.5.1"
version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d"
dependencies = [
"autocfg",
"crossbeam-deque",
@ -377,55 +381,51 @@ dependencies = [
[[package]]
name = "rayon-core"
version = "1.9.1"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"lazy_static",
"num_cpus",
]
[[package]]
name = "regex"
version = "1.5.4"
version = "1.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
dependencies = [
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.1.9"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4"
dependencies = [
"byteorder",
]
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
[[package]]
name = "regex-syntax"
version = "0.6.25"
version = "0.6.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
[[package]]
name = "rustc_version"
version = "0.3.3"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver",
]
[[package]]
name = "ryu"
version = "1.0.5"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
[[package]]
name = "same-file"
@ -444,33 +444,21 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "semver"
version = "0.11.0"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
dependencies = [
"pest",
]
checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1"
[[package]]
name = "serde"
version = "1.0.126"
version = "1.0.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47"
[[package]]
name = "serde_cbor"
version = "0.11.1"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622"
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
dependencies = [
"half",
"serde",
@ -478,9 +466,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.126"
version = "1.0.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c"
dependencies = [
"proc-macro2",
"quote",
@ -489,24 +477,24 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.64"
version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7"
dependencies = [
"itoa",
"itoa 1.0.2",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "1.0.72"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
"unicode-ident",
]
[[package]]
@ -529,22 +517,16 @@ dependencies = [
]
[[package]]
name = "ucd-trie"
version = "0.1.3"
name = "unicode-ident"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
[[package]]
name = "unicode-width"
version = "0.1.8"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "walkdir"
@ -559,9 +541,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.74"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@ -569,9 +551,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.74"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900"
checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a"
dependencies = [
"bumpalo",
"lazy_static",
@ -584,9 +566,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.74"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4"
checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -594,9 +576,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.74"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048"
dependencies = [
"proc-macro2",
"quote",
@ -607,25 +589,26 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.74"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be"
[[package]]
name = "wasmparser"
version = "0.78.2"
version = "0.87.0"
dependencies = [
"anyhow",
"criterion",
"getopts",
"indexmap",
"rayon",
]
[[package]]
name = "web-sys"
version = "0.3.51"
version = "0.3.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582"
checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90"
dependencies = [
"js-sys",
"wasm-bindgen",

View File

@ -3,27 +3,38 @@
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
edition = "2021"
name = "wasmparser"
version = "0.78.2"
version = "0.87.0"
authors = ["Yury Delendik <ydelendik@mozilla.com>"]
description = "A simple event-driven library for parsing WebAssembly binary files.\n"
description = """
A simple event-driven library for parsing WebAssembly binary files.
"""
homepage = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasmparser"
keywords = ["parser", "WebAssembly", "wasm"]
readme = "README.md"
keywords = [
"parser",
"WebAssembly",
"wasm",
]
license = "Apache-2.0 WITH LLVM-exception"
repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasmparser"
resolver = "2"
[[bench]]
name = "benchmark"
harness = false
[dependencies.indexmap]
version = "1.8.0"
[dev-dependencies.anyhow]
version = "1.0"

View File

@ -60,7 +60,7 @@ fn collect_test_files(path: &Path, list: &mut Vec<BenchmarkInput>) -> Result<()>
};
for directive in wast.directives {
match directive {
wast::WastDirective::Module(mut module) => {
wast::WastDirective::Wat(mut module) => {
let wasm = module.encode()?;
list.push(BenchmarkInput::new(path.clone(), wasm));
}
@ -92,18 +92,6 @@ fn read_all_wasm(wasm: &[u8]) -> Result<()> {
item?;
}
}
AliasSection(s) => {
for item in s {
item?;
}
}
InstanceSection(s) => {
for item in s {
for arg in item?.args()? {
arg?;
}
}
}
FunctionSection(s) => {
for item in s {
item?;
@ -119,7 +107,7 @@ fn read_all_wasm(wasm: &[u8]) -> Result<()> {
item?;
}
}
EventSection(s) => {
TagSection(s) => {
for item in s {
item?;
}
@ -168,15 +156,63 @@ fn read_all_wasm(wasm: &[u8]) -> Result<()> {
}
}
// Component sections
ModuleSection { .. } => {}
InstanceSection(s) => {
for item in s {
item?;
}
}
AliasSection(s) => {
for item in s {
item?;
}
}
CoreTypeSection(s) => {
for item in s {
item?;
}
}
ComponentSection { .. } => {}
ComponentInstanceSection(s) => {
for item in s {
item?;
}
}
ComponentAliasSection(s) => {
for item in s {
item?;
}
}
ComponentTypeSection(s) => {
for item in s {
item?;
}
}
ComponentCanonicalSection(s) => {
for item in s {
item?;
}
}
ComponentStartSection { .. } => {}
ComponentImportSection(s) => {
for item in s {
item?;
}
}
ComponentExportSection(s) => {
for item in s {
item?;
}
}
Version { .. }
| StartSection { .. }
| DataCountSection { .. }
| UnknownSection { .. }
| CustomSection { .. }
| CodeSectionStart { .. }
| ModuleSectionStart { .. }
| ModuleSectionEntry { .. }
| End => {}
| End(_) => {}
}
}
Ok(())
@ -205,21 +241,24 @@ fn it_works_benchmark(c: &mut Criterion) {
fn validate_benchmark(c: &mut Criterion) {
fn validator() -> Validator {
let mut ret = Validator::new();
ret.wasm_features(WasmFeatures {
Validator::new_with_features(WasmFeatures {
reference_types: true,
multi_value: true,
simd: true,
relaxed_simd: true,
exceptions: true,
module_linking: true,
component_model: true,
bulk_memory: true,
threads: true,
tail_call: true,
multi_memory: true,
memory64: true,
extended_const: true,
deterministic_only: false,
});
return ret;
mutable_global: true,
saturating_float_to_int: true,
sign_extension: true,
})
}
let mut inputs = collect_benchmark_inputs();
// Filter out all benchmark inputs that fail to validate via `wasmparser`.

View File

@ -18,13 +18,13 @@ fn main() -> Result<()> {
Payload::ExportSection(s) => {
for export in s {
let export = export?;
println!(" Export {} {:?}", export.field, export.kind);
println!(" Export {} {:?}", export.name, export.kind);
}
}
Payload::ImportSection(s) => {
for import in s {
let import = import?;
println!(" Import {}::{}", import.module, import.field.unwrap());
println!(" Import {}::{}", import.module, import.name);
}
}
_other => {

File diff suppressed because it is too large Load Diff

View File

@ -16,27 +16,24 @@
//! A simple event-driven library for parsing WebAssembly binary files
//! (or streams).
//!
//! The parser library reports events as they happend and only stores
//! The parser library reports events as they happen and only stores
//! parsing information for a brief period of time, making it very fast
//! and memory-efficient. The event-driven model, however, has some drawbacks.
//! If you need random access to the entire WebAssembly data-structure,
//! this is not the right library for you. You could however, build such
//! a data-structure using this library.
pub use crate::binary_reader::BinaryReader;
pub use crate::binary_reader::Range;
#![deny(missing_docs)]
pub use crate::module_resources::*;
pub use crate::binary_reader::{BinaryReader, BinaryReaderError, Result};
pub use crate::parser::*;
pub use crate::primitives::*;
pub use crate::readers::*;
pub use crate::resources::*;
pub use crate::validator::*;
mod binary_reader;
mod limits;
mod module_resources;
mod operators_validator;
mod parser;
mod primitives;
mod readers;
mod resources;
mod validator;

View File

@ -17,14 +17,13 @@
// The limits are agreed upon with other engines for consistency.
pub const MAX_WASM_TYPES: usize = 1_000_000;
pub const MAX_WASM_FUNCTIONS: usize = 1_000_000;
pub const MAX_WASM_IMPORTS: usize = 100_000;
pub const MAX_WASM_EXPORTS: usize = 100_000;
pub const MAX_WASM_GLOBALS: usize = 1_000_000;
pub const MAX_WASM_ELEMENT_SEGMENTS: usize = 100_000;
pub const MAX_WASM_DATA_SEGMENTS: usize = 100_000;
pub const MAX_WASM_MEMORY_PAGES: usize = 65536;
pub const MAX_WASM_MEMORY32_PAGES: u64 = 65536;
pub const MAX_WASM_MEMORY64_PAGES: u64 = 1 << 48;
pub const MAX_WASM_STRING_SIZE: usize = 100_000;
pub const _MAX_WASM_MODULE_SIZE: usize = 1024 * 1024 * 1024; //= 1 GiB
pub const MAX_WASM_FUNCTION_SIZE: usize = 128 * 1024;
pub const MAX_WASM_FUNCTION_LOCALS: usize = 50000;
pub const MAX_WASM_FUNCTION_PARAMS: usize = 1000;
@ -33,7 +32,26 @@ pub const _MAX_WASM_TABLE_SIZE: usize = 10_000_000;
pub const MAX_WASM_TABLE_ENTRIES: usize = 10_000_000;
pub const MAX_WASM_TABLES: usize = 100;
pub const MAX_WASM_MEMORIES: usize = 100;
pub const MAX_WASM_TAGS: usize = 1_000_000;
pub const MAX_WASM_BR_TABLE_SIZE: usize = MAX_WASM_FUNCTION_SIZE;
// Component-related limits
pub const MAX_WASM_MODULE_SIZE: usize = 1024 * 1024 * 1024; //= 1 GiB
pub const MAX_WASM_MODULE_TYPE_DECLS: usize = 1000;
pub const MAX_WASM_COMPONENT_TYPE_DECLS: usize = 1000;
pub const MAX_WASM_INSTANCE_TYPE_DECLS: usize = 1000;
pub const MAX_WASM_RECORD_FIELDS: usize = 1000;
pub const MAX_WASM_VARIANT_CASES: usize = 1000;
pub const MAX_WASM_TUPLE_TYPES: usize = 1000;
pub const MAX_WASM_FLAG_NAMES: usize = 1000;
pub const MAX_WASM_ENUM_CASES: usize = 1000;
pub const MAX_WASM_UNION_TYPES: usize = 1000;
pub const MAX_WASM_INSTANTIATION_EXPORTS: usize = 1000;
pub const MAX_WASM_CANONICAL_OPTIONS: usize = 10;
pub const MAX_WASM_INSTANTIATION_ARGS: usize = 1000;
pub const MAX_WASM_START_ARGS: usize = 1000;
pub const MAX_WASM_TYPE_SIZE: usize = 100_000;
pub const MAX_WASM_MODULES: usize = 1_000;
pub const MAX_WASM_COMPONENTS: usize = 1_000;
pub const MAX_WASM_INSTANCES: usize = 1_000;
pub const MAX_WASM_EVENTS: usize = 1_000_000;
pub const MAX_TYPE_SIZE: u32 = 100_000;
pub const MAX_WASM_VALUES: usize = 1_000;

File diff suppressed because it is too large Load Diff

View File

@ -13,29 +13,54 @@
* limitations under the License.
*/
use super::{BinaryReaderError, Range, Result};
use crate::{BinaryReaderError, Result};
use std::ops::Range;
mod component;
mod core;
pub use self::component::*;
pub use self::core::*;
/// A trait implemented by section readers.
pub trait SectionReader {
/// The item returned by the reader.
type Item;
/// Reads an item from the section.
fn read(&mut self) -> Result<Self::Item>;
/// Determines if the reader is at end-of-section.
fn eof(&self) -> bool;
/// Gets the original position of the reader.
fn original_position(&self) -> usize;
fn range(&self) -> Range;
/// Gets the range of the reader.
fn range(&self) -> Range<usize>;
/// Ensures the reader is at the end of the section.
///
/// This methods returns an error if there is more data in the section
/// than what is described by the section's header.
fn ensure_end(&self) -> Result<()> {
if self.eof() {
return Ok(());
}
Err(BinaryReaderError::new(
"Unexpected data at the end of the section",
"section size mismatch: unexpected data at the end of the section",
self.original_position(),
))
}
}
/// Implemented by sections with a limited number of items.
pub trait SectionWithLimitedItems {
/// Gets the count of the items in the section.
fn get_count(&self) -> u32;
}
/// An iterator over items in a section.
pub struct SectionIterator<R>
where
R: SectionReader,
@ -48,6 +73,7 @@ impl<R> SectionIterator<R>
where
R: SectionReader,
{
/// Constructs a new `SectionIterator` for the given section reader.
pub fn new(reader: R) -> SectionIterator<R> {
SectionIterator { reader, err: false }
}
@ -69,6 +95,7 @@ where
}
}
/// An iterator over a limited section iterator.
pub struct SectionIteratorLimited<R>
where
R: SectionReader + SectionWithLimitedItems,
@ -82,6 +109,7 @@ impl<R> SectionIteratorLimited<R>
where
R: SectionReader + SectionWithLimitedItems,
{
/// Constructs a new `SectionIteratorLimited` for the given limited section reader.
pub fn new(reader: R) -> SectionIteratorLimited<R> {
let left = reader.get_count();
SectionIteratorLimited {

View File

@ -1,110 +0,0 @@
use crate::{
BinaryReader, BinaryReaderError, ExternalKind, Range, Result, SectionIteratorLimited,
SectionReader, SectionWithLimitedItems,
};
#[derive(Clone)]
pub struct AliasSectionReader<'a> {
reader: BinaryReader<'a>,
count: u32,
}
#[derive(Clone, Debug)]
pub enum Alias<'a> {
OuterType {
relative_depth: u32,
index: u32,
},
OuterModule {
relative_depth: u32,
index: u32,
},
InstanceExport {
instance: u32,
kind: ExternalKind,
export: &'a str,
},
}
impl<'a> AliasSectionReader<'a> {
pub fn new(data: &'a [u8], offset: usize) -> Result<AliasSectionReader<'a>> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(AliasSectionReader { reader, count })
}
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
pub fn get_count(&self) -> u32 {
self.count
}
pub fn read(&mut self) -> Result<Alias<'a>> {
Ok(match self.reader.read_u8()? {
0x00 => Alias::InstanceExport {
instance: self.reader.read_var_u32()?,
kind: self.reader.read_external_kind()?,
export: self.reader.read_string()?,
},
0x01 => {
let relative_depth = self.reader.read_var_u32()?;
match self.reader.read_external_kind()? {
ExternalKind::Type => Alias::OuterType {
relative_depth,
index: self.reader.read_var_u32()?,
},
ExternalKind::Module => Alias::OuterModule {
relative_depth,
index: self.reader.read_var_u32()?,
},
_ => {
return Err(BinaryReaderError::new(
"invalid external kind in alias",
self.original_position() - 1,
))
}
}
}
_ => {
return Err(BinaryReaderError::new(
"invalid byte in alias",
self.original_position() - 1,
))
}
})
}
}
impl<'a> SectionReader for AliasSectionReader<'a> {
type Item = Alias<'a>;
fn read(&mut self) -> Result<Self::Item> {
AliasSectionReader::read(self)
}
fn eof(&self) -> bool {
self.reader.eof()
}
fn original_position(&self) -> usize {
AliasSectionReader::original_position(self)
}
fn range(&self) -> Range {
self.reader.range()
}
}
impl<'a> SectionWithLimitedItems for AliasSectionReader<'a> {
fn get_count(&self) -> u32 {
AliasSectionReader::get_count(self)
}
}
impl<'a> IntoIterator for AliasSectionReader<'a> {
type Item = Result<Alias<'a>>;
type IntoIter = SectionIteratorLimited<AliasSectionReader<'a>>;
fn into_iter(self) -> Self::IntoIter {
SectionIteratorLimited::new(self)
}
}

View File

@ -0,0 +1,15 @@
mod aliases;
mod canonicals;
mod exports;
mod imports;
mod instances;
mod start;
mod types;
pub use self::aliases::*;
pub use self::canonicals::*;
pub use self::exports::*;
pub use self::imports::*;
pub use self::instances::*;
pub use self::start::*;
pub use self::types::*;

View File

@ -0,0 +1,225 @@
use crate::{
BinaryReader, ComponentExternalKind, ExternalKind, Result, SectionIteratorLimited,
SectionReader, SectionWithLimitedItems,
};
use std::ops::Range;
/// Represents the kind of an outer core alias in a WebAssembly component.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum OuterAliasKind {
/// The alias is to a core type.
Type,
}
/// Represents a core alias for a WebAssembly module.
#[derive(Debug, Clone)]
pub enum Alias<'a> {
/// The alias is to an export of a module instance.
InstanceExport {
/// The alias kind.
kind: ExternalKind,
/// The instance index.
instance_index: u32,
/// The export name.
name: &'a str,
},
/// The alias is to an outer item.
Outer {
/// The alias kind.
kind: OuterAliasKind,
/// The outward count, starting at zero for the current component.
count: u32,
/// The index of the item within the outer component.
index: u32,
},
}
/// A reader for the core alias section of a WebAssembly component.
#[derive(Clone)]
pub struct AliasSectionReader<'a> {
reader: BinaryReader<'a>,
count: u32,
}
impl<'a> AliasSectionReader<'a> {
/// Constructs a new `AliasSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<Self> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(Self { reader, count })
}
/// Gets the original position of the section reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets the count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
/// Reads content of the core alias section.
///
/// # Examples
/// ```
/// use wasmparser::AliasSectionReader;
/// let data: &[u8] = &[0x01, 0x00, 0x00, 0x00, 0x03, b'f', b'o', b'o'];
/// let mut reader = AliasSectionReader::new(data, 0).unwrap();
/// for _ in 0..reader.get_count() {
/// let alias = reader.read().expect("alias");
/// println!("Alias: {:?}", alias);
/// }
/// ```
pub fn read(&mut self) -> Result<Alias<'a>> {
self.reader.read_alias()
}
}
impl<'a> SectionReader for AliasSectionReader<'a> {
type Item = Alias<'a>;
fn read(&mut self) -> Result<Self::Item> {
Self::read(self)
}
fn eof(&self) -> bool {
self.reader.eof()
}
fn original_position(&self) -> usize {
Self::original_position(self)
}
fn range(&self) -> Range<usize> {
self.reader.range()
}
}
impl<'a> SectionWithLimitedItems for AliasSectionReader<'a> {
fn get_count(&self) -> u32 {
Self::get_count(self)
}
}
impl<'a> IntoIterator for AliasSectionReader<'a> {
type Item = Result<Alias<'a>>;
type IntoIter = SectionIteratorLimited<Self>;
fn into_iter(self) -> Self::IntoIter {
SectionIteratorLimited::new(self)
}
}
/// Represents the kind of an outer alias in a WebAssembly component.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ComponentOuterAliasKind {
/// The alias is to a core module.
CoreModule,
/// The alias is to a core type.
CoreType,
/// The alias is to a component type.
Type,
/// The alias is to a component.
Component,
}
/// Represents an alias in a WebAssembly component.
#[derive(Debug, Clone)]
pub enum ComponentAlias<'a> {
/// The alias is to an export of a component instance.
InstanceExport {
/// The alias kind.
kind: ComponentExternalKind,
/// The instance index.
instance_index: u32,
/// The export name.
name: &'a str,
},
/// The alias is to an outer item.
Outer {
/// The alias kind.
kind: ComponentOuterAliasKind,
/// The outward count, starting at zero for the current component.
count: u32,
/// The index of the item within the outer component.
index: u32,
},
}
/// A reader for the alias section of a WebAssembly component.
#[derive(Clone)]
pub struct ComponentAliasSectionReader<'a> {
reader: BinaryReader<'a>,
count: u32,
}
impl<'a> ComponentAliasSectionReader<'a> {
/// Constructs a new `ComponentAliasSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<Self> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(Self { reader, count })
}
/// Gets the original position of the section reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets the count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
/// Reads content of the alias section.
///
/// # Examples
/// ```
/// use wasmparser::ComponentAliasSectionReader;
/// let data: &[u8] = &[0x01, 0x01, 0x00, 0x00, 0x03, b'f', b'o', b'o'];
/// let mut reader = ComponentAliasSectionReader::new(data, 0).unwrap();
/// for _ in 0..reader.get_count() {
/// let alias = reader.read().expect("alias");
/// println!("Alias: {:?}", alias);
/// }
/// ```
pub fn read(&mut self) -> Result<ComponentAlias<'a>> {
self.reader.read_component_alias()
}
}
impl<'a> SectionReader for ComponentAliasSectionReader<'a> {
type Item = ComponentAlias<'a>;
fn read(&mut self) -> Result<Self::Item> {
Self::read(self)
}
fn eof(&self) -> bool {
self.reader.eof()
}
fn original_position(&self) -> usize {
Self::original_position(self)
}
fn range(&self) -> Range<usize> {
self.reader.range()
}
}
impl<'a> SectionWithLimitedItems for ComponentAliasSectionReader<'a> {
fn get_count(&self) -> u32 {
Self::get_count(self)
}
}
impl<'a> IntoIterator for ComponentAliasSectionReader<'a> {
type Item = Result<ComponentAlias<'a>>;
type IntoIter = SectionIteratorLimited<Self>;
fn into_iter(self) -> Self::IntoIter {
SectionIteratorLimited::new(self)
}
}

View File

@ -0,0 +1,124 @@
use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems};
use std::ops::Range;
/// Represents options for component functions.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CanonicalOption {
/// The string types in the function signature are UTF-8 encoded.
UTF8,
/// The string types in the function signature are UTF-16 encoded.
UTF16,
/// The string types in the function signature are compact UTF-16 encoded.
CompactUTF16,
/// The memory to use if the lifting or lowering of a function requires memory access.
///
/// The value is an index to a core memory.
Memory(u32),
/// The realloc function to use if the lifting or lowering of a function requires memory
/// allocation.
///
/// The value is an index to a core function of type `(func (param i32 i32 i32 i32) (result i32))`.
Realloc(u32),
/// The post-return function to use if the lifting of a function requires
/// cleanup after the function returns.
PostReturn(u32),
}
/// Represents a canonical function in a WebAssembly component.
#[derive(Debug, Clone)]
pub enum CanonicalFunction {
/// The function lifts a core WebAssembly function to the canonical ABI.
Lift {
/// The index of the core WebAssembly function to lift.
core_func_index: u32,
/// The index of the lifted function's type.
type_index: u32,
/// The canonical options for the function.
options: Box<[CanonicalOption]>,
},
/// The function lowers a canonical ABI function to a core WebAssembly function.
Lower {
/// The index of the function to lower.
func_index: u32,
/// The canonical options for the function.
options: Box<[CanonicalOption]>,
},
}
/// A reader for the canonical section of a WebAssembly component.
#[derive(Clone)]
pub struct ComponentCanonicalSectionReader<'a> {
reader: BinaryReader<'a>,
count: u32,
}
impl<'a> ComponentCanonicalSectionReader<'a> {
/// Constructs a new `ComponentFunctionSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<Self> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(Self { reader, count })
}
/// Gets the original position of the section reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets the count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
/// Reads function type index from the function section.
///
/// # Examples
///
/// ```
/// use wasmparser::ComponentCanonicalSectionReader;
/// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00];
/// let mut reader = ComponentCanonicalSectionReader::new(data, 0).unwrap();
/// for _ in 0..reader.get_count() {
/// let func = reader.read().expect("func");
/// println!("Function: {:?}", func);
/// }
/// ```
pub fn read(&mut self) -> Result<CanonicalFunction> {
self.reader.read_canonical_func()
}
}
impl<'a> SectionReader for ComponentCanonicalSectionReader<'a> {
type Item = CanonicalFunction;
fn read(&mut self) -> Result<Self::Item> {
Self::read(self)
}
fn eof(&self) -> bool {
self.reader.eof()
}
fn original_position(&self) -> usize {
Self::original_position(self)
}
fn range(&self) -> Range<usize> {
self.reader.range()
}
}
impl<'a> SectionWithLimitedItems for ComponentCanonicalSectionReader<'a> {
fn get_count(&self) -> u32 {
Self::get_count(self)
}
}
impl<'a> IntoIterator for ComponentCanonicalSectionReader<'a> {
type Item = Result<CanonicalFunction>;
type IntoIter = SectionIteratorLimited<Self>;
fn into_iter(self) -> Self::IntoIter {
SectionIteratorLimited::new(self)
}
}

View File

@ -0,0 +1,108 @@
use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems};
use std::ops::Range;
/// Represents the kind of an external items of a WebAssembly component.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ComponentExternalKind {
/// The external kind is a core module.
Module,
/// The external kind is a function.
Func,
/// The external kind is a value.
Value,
/// The external kind is a type.
Type,
/// The external kind is an instance.
Instance,
/// The external kind is a component.
Component,
}
/// Represents an export in a WebAssembly component.
#[derive(Debug, Clone)]
pub struct ComponentExport<'a> {
/// The name of the exported item.
pub name: &'a str,
/// The kind of the export.
pub kind: ComponentExternalKind,
/// The index of the exported item.
pub index: u32,
}
/// A reader for the export section of a WebAssembly component.
#[derive(Clone)]
pub struct ComponentExportSectionReader<'a> {
reader: BinaryReader<'a>,
count: u32,
}
impl<'a> ComponentExportSectionReader<'a> {
/// Constructs a new `ComponentExportSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<Self> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(Self { reader, count })
}
/// Gets the original position of the section reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets the count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
/// Reads content of the export section.
///
/// # Examples
/// ```
/// use wasmparser::ComponentExportSectionReader;
///
/// # let data: &[u8] = &[0x01, 0x03, b'f', b'o', b'o', 0x01, 0x00];
/// let mut reader = ComponentExportSectionReader::new(data, 0).unwrap();
/// for _ in 0..reader.get_count() {
/// let export = reader.read().expect("export");
/// println!("Export: {:?}", export);
/// }
/// ```
pub fn read(&mut self) -> Result<ComponentExport<'a>> {
self.reader.read_component_export()
}
}
impl<'a> SectionReader for ComponentExportSectionReader<'a> {
type Item = ComponentExport<'a>;
fn read(&mut self) -> Result<Self::Item> {
Self::read(self)
}
fn eof(&self) -> bool {
self.reader.eof()
}
fn original_position(&self) -> usize {
Self::original_position(self)
}
fn range(&self) -> Range<usize> {
self.reader.range()
}
}
impl<'a> SectionWithLimitedItems for ComponentExportSectionReader<'a> {
fn get_count(&self) -> u32 {
Self::get_count(self)
}
}
impl<'a> IntoIterator for ComponentExportSectionReader<'a> {
type Item = Result<ComponentExport<'a>>;
type IntoIter = SectionIteratorLimited<Self>;
fn into_iter(self) -> Self::IntoIter {
SectionIteratorLimited::new(self)
}
}

View File

@ -0,0 +1,125 @@
use crate::{
BinaryReader, ComponentValType, Result, SectionIteratorLimited, SectionReader,
SectionWithLimitedItems,
};
use std::ops::Range;
/// Represents the type bounds for imports and exports.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TypeBounds {
/// The type is bounded by equality.
Eq,
}
/// Represents a reference to a component type.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ComponentTypeRef {
/// The reference is to a core module type.
///
/// The index is expected to be core type index to a core module type.
Module(u32),
/// The reference is to a function type.
///
/// The index is expected to be a type index to a function type.
Func(u32),
/// The reference is to a value type.
Value(ComponentValType),
/// The reference is to a bounded type.
///
/// The index is expected to be a type index.
Type(TypeBounds, u32),
/// The reference is to an instance type.
///
/// The index is a type index to an instance type.
Instance(u32),
/// The reference is to a component type.
///
/// The index is a type index to a component type.
Component(u32),
}
/// Represents an import in a WebAssembly component
#[derive(Debug, Copy, Clone)]
pub struct ComponentImport<'a> {
/// The name of the imported item.
pub name: &'a str,
/// The type reference for the import.
pub ty: ComponentTypeRef,
}
/// A reader for the import section of a WebAssembly component.
#[derive(Clone)]
pub struct ComponentImportSectionReader<'a> {
reader: BinaryReader<'a>,
count: u32,
}
impl<'a> ComponentImportSectionReader<'a> {
/// Constructs a new `ComponentImportSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<Self> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(Self { reader, count })
}
/// Gets the original position of the section reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets the count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
/// Reads content of the import section.
///
/// # Examples
/// ```
/// use wasmparser::ComponentImportSectionReader;
/// let data: &[u8] = &[0x01, 0x01, 0x41, 0x01, 0x66, 0x00, 0x00];
/// let mut reader = ComponentImportSectionReader::new(data, 0).unwrap();
/// for _ in 0..reader.get_count() {
/// let import = reader.read().expect("import");
/// println!("Import: {:?}", import);
/// }
/// ```
pub fn read(&mut self) -> Result<ComponentImport<'a>> {
self.reader.read_component_import()
}
}
impl<'a> SectionReader for ComponentImportSectionReader<'a> {
type Item = ComponentImport<'a>;
fn read(&mut self) -> Result<Self::Item> {
Self::read(self)
}
fn eof(&self) -> bool {
self.reader.eof()
}
fn original_position(&self) -> usize {
Self::original_position(self)
}
fn range(&self) -> Range<usize> {
self.reader.range()
}
}
impl<'a> SectionWithLimitedItems for ComponentImportSectionReader<'a> {
fn get_count(&self) -> u32 {
Self::get_count(self)
}
}
impl<'a> IntoIterator for ComponentImportSectionReader<'a> {
type Item = Result<ComponentImport<'a>>;
type IntoIter = SectionIteratorLimited<Self>;
fn into_iter(self) -> Self::IntoIter {
SectionIteratorLimited::new(self)
}
}

View File

@ -0,0 +1,240 @@
use crate::{
BinaryReader, ComponentExport, ComponentExternalKind, Export, Result, SectionIteratorLimited,
SectionReader, SectionWithLimitedItems,
};
use std::ops::Range;
/// Represents the kind of an instantiation argument for a core instance.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum InstantiationArgKind {
/// The instantiation argument is a core instance.
Instance,
}
/// Represents an argument to instantiating a WebAssembly module.
#[derive(Debug, Clone)]
pub struct InstantiationArg<'a> {
/// The name of the module argument.
pub name: &'a str,
/// The kind of the module argument.
pub kind: InstantiationArgKind,
/// The index of the argument item.
pub index: u32,
}
/// Represents an instance of a WebAssembly module.
#[derive(Debug, Clone)]
pub enum Instance<'a> {
/// The instance is from instantiating a WebAssembly module.
Instantiate {
/// The module index.
module_index: u32,
/// The module's instantiation arguments.
args: Box<[InstantiationArg<'a>]>,
},
/// The instance is a from exporting local items.
FromExports(Box<[Export<'a>]>),
}
/// A reader for the core instance section of a WebAssembly component.
#[derive(Clone)]
pub struct InstanceSectionReader<'a> {
reader: BinaryReader<'a>,
count: u32,
}
impl<'a> InstanceSectionReader<'a> {
/// Constructs a new `InstanceSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<Self> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(Self { reader, count })
}
/// Gets the original position of the section reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets the count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
/// Reads content of the instance section.
///
/// # Examples
/// ```
/// use wasmparser::InstanceSectionReader;
/// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x12, 0x00];
/// let mut reader = InstanceSectionReader::new(data, 0).unwrap();
/// for _ in 0..reader.get_count() {
/// let instance = reader.read().expect("instance");
/// println!("Instance: {:?}", instance);
/// }
/// ```
pub fn read(&mut self) -> Result<Instance<'a>> {
self.reader.read_instance()
}
}
impl<'a> SectionReader for InstanceSectionReader<'a> {
type Item = Instance<'a>;
fn read(&mut self) -> Result<Self::Item> {
Self::read(self)
}
fn eof(&self) -> bool {
self.reader.eof()
}
fn original_position(&self) -> usize {
Self::original_position(self)
}
fn range(&self) -> Range<usize> {
self.reader.range()
}
}
impl<'a> SectionWithLimitedItems for InstanceSectionReader<'a> {
fn get_count(&self) -> u32 {
Self::get_count(self)
}
}
impl<'a> IntoIterator for InstanceSectionReader<'a> {
type Item = Result<Instance<'a>>;
type IntoIter = SectionIteratorLimited<Self>;
/// Implements iterator over the instance section.
///
/// # Examples
///
/// ```
/// use wasmparser::InstanceSectionReader;
/// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x12, 0x00];
/// let mut reader = InstanceSectionReader::new(data, 0).unwrap();
/// for inst in reader {
/// println!("Instance {:?}", inst.expect("instance"));
/// }
/// ```
fn into_iter(self) -> Self::IntoIter {
SectionIteratorLimited::new(self)
}
}
/// Represents an argument to instantiating a WebAssembly component.
#[derive(Debug, Clone)]
pub struct ComponentInstantiationArg<'a> {
/// The name of the component argument.
pub name: &'a str,
/// The kind of the component argument.
pub kind: ComponentExternalKind,
/// The index of the argument item.
pub index: u32,
}
/// Represents an instance in a WebAssembly component.
#[derive(Debug, Clone)]
pub enum ComponentInstance<'a> {
/// The instance is from instantiating a WebAssembly component.
Instantiate {
/// The component index.
component_index: u32,
/// The component's instantiation arguments.
args: Box<[ComponentInstantiationArg<'a>]>,
},
/// The instance is a from exporting local items.
FromExports(Box<[ComponentExport<'a>]>),
}
/// A reader for the component instance section of a WebAssembly component.
#[derive(Clone)]
pub struct ComponentInstanceSectionReader<'a> {
reader: BinaryReader<'a>,
count: u32,
}
impl<'a> ComponentInstanceSectionReader<'a> {
/// Constructs a new `ComponentInstanceSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<Self> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(Self { reader, count })
}
/// Gets the original position of the section reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets the count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
/// Reads content of the instance section.
///
/// # Examples
/// ```
/// use wasmparser::ComponentInstanceSectionReader;
/// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x01, 0x00];
/// let mut reader = ComponentInstanceSectionReader::new(data, 0).unwrap();
/// for _ in 0..reader.get_count() {
/// let instance = reader.read().expect("instance");
/// println!("Instance: {:?}", instance);
/// }
/// ```
pub fn read(&mut self) -> Result<ComponentInstance<'a>> {
self.reader.read_component_instance()
}
}
impl<'a> SectionReader for ComponentInstanceSectionReader<'a> {
type Item = ComponentInstance<'a>;
fn read(&mut self) -> Result<Self::Item> {
Self::read(self)
}
fn eof(&self) -> bool {
self.reader.eof()
}
fn original_position(&self) -> usize {
Self::original_position(self)
}
fn range(&self) -> Range<usize> {
self.reader.range()
}
}
impl<'a> SectionWithLimitedItems for ComponentInstanceSectionReader<'a> {
fn get_count(&self) -> u32 {
Self::get_count(self)
}
}
impl<'a> IntoIterator for ComponentInstanceSectionReader<'a> {
type Item = Result<ComponentInstance<'a>>;
type IntoIter = SectionIteratorLimited<Self>;
/// Implements iterator over the instance section.
///
/// # Examples
///
/// ```
/// use wasmparser::ComponentInstanceSectionReader;
/// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x01, 0x00];
/// let mut reader = ComponentInstanceSectionReader::new(data, 0).unwrap();
/// for inst in reader {
/// println!("Instance {:?}", inst.expect("instance"));
/// }
/// ```
fn into_iter(self) -> Self::IntoIter {
SectionIteratorLimited::new(self)
}
}

View File

@ -0,0 +1,64 @@
use crate::{BinaryReader, Result, SectionReader};
use std::ops::Range;
/// Represents the start function in a WebAssembly component.
#[derive(Debug, Clone)]
pub struct ComponentStartFunction {
/// The index to the start function.
pub func_index: u32,
/// The start function arguments.
///
/// The arguments are specified by value index.
pub arguments: Box<[u32]>,
}
/// A reader for the start section of a WebAssembly component.
#[derive(Clone)]
pub struct ComponentStartSectionReader<'a>(BinaryReader<'a>);
impl<'a> ComponentStartSectionReader<'a> {
/// Constructs a new `ComponentStartSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<Self> {
Ok(Self(BinaryReader::new_with_offset(data, offset)))
}
/// Gets the original position of the section reader.
pub fn original_position(&self) -> usize {
self.0.original_position()
}
/// Reads the start function from the section.
///
/// # Examples
/// ```
/// use wasmparser::ComponentStartSectionReader;
///
/// # let data: &[u8] = &[0x00, 0x03, 0x01, 0x02, 0x03];
/// let mut reader = ComponentStartSectionReader::new(data, 0).unwrap();
/// let start = reader.read().expect("start");
/// println!("Start: {:?}", start);
/// ```
pub fn read(&mut self) -> Result<ComponentStartFunction> {
self.0.read_component_start()
}
}
impl<'a> SectionReader for ComponentStartSectionReader<'a> {
type Item = ComponentStartFunction;
fn read(&mut self) -> Result<Self::Item> {
Self::read(self)
}
fn eof(&self) -> bool {
self.0.eof()
}
fn original_position(&self) -> usize {
Self::original_position(self)
}
fn range(&self) -> Range<usize> {
self.0.range()
}
}

View File

@ -0,0 +1,393 @@
use crate::{
Alias, BinaryReader, ComponentAlias, ComponentImport, ComponentTypeRef, FuncType, Import,
Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems, Type, TypeRef,
};
use std::ops::Range;
/// Represents a core type in a WebAssembly component.
#[derive(Debug, Clone)]
pub enum CoreType<'a> {
/// The type is for a core function.
Func(FuncType),
/// The type is for a core module.
Module(Box<[ModuleTypeDeclaration<'a>]>),
}
/// Represents a module type declaration in a WebAssembly component.
#[derive(Debug, Clone)]
pub enum ModuleTypeDeclaration<'a> {
/// The module type definition is for a type.
Type(Type),
/// The module type definition is for an export.
Export {
/// The name of the exported item.
name: &'a str,
/// The type reference of the export.
ty: TypeRef,
},
/// The module type declaration is for an alias.
Alias(Alias<'a>),
/// The module type definition is for an import.
Import(Import<'a>),
}
/// A reader for the core type section of a WebAssembly component.
#[derive(Clone)]
pub struct CoreTypeSectionReader<'a> {
reader: BinaryReader<'a>,
count: u32,
}
impl<'a> CoreTypeSectionReader<'a> {
/// Constructs a new `CoreTypeSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<Self> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(Self { reader, count })
}
/// Gets the original position of the reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets a count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
/// Reads content of the type section.
///
/// # Examples
/// ```
/// use wasmparser::CoreTypeSectionReader;
/// let data: &[u8] = &[0x01, 0x60, 0x00, 0x00];
/// let mut reader = CoreTypeSectionReader::new(data, 0).unwrap();
/// for _ in 0..reader.get_count() {
/// let ty = reader.read().expect("type");
/// println!("Type {:?}", ty);
/// }
/// ```
pub fn read(&mut self) -> Result<CoreType<'a>> {
self.reader.read_core_type()
}
}
impl<'a> SectionReader for CoreTypeSectionReader<'a> {
type Item = CoreType<'a>;
fn read(&mut self) -> Result<Self::Item> {
Self::read(self)
}
fn eof(&self) -> bool {
self.reader.eof()
}
fn original_position(&self) -> usize {
Self::original_position(self)
}
fn range(&self) -> Range<usize> {
self.reader.range()
}
}
impl<'a> SectionWithLimitedItems for CoreTypeSectionReader<'a> {
fn get_count(&self) -> u32 {
Self::get_count(self)
}
}
impl<'a> IntoIterator for CoreTypeSectionReader<'a> {
type Item = Result<CoreType<'a>>;
type IntoIter = SectionIteratorLimited<Self>;
/// Implements iterator over the type section.
///
/// # Examples
/// ```
/// use wasmparser::CoreTypeSectionReader;
/// # let data: &[u8] = &[0x01, 0x60, 0x00, 0x00];
/// let mut reader = CoreTypeSectionReader::new(data, 0).unwrap();
/// for ty in reader {
/// println!("Type {:?}", ty.expect("type"));
/// }
/// ```
fn into_iter(self) -> Self::IntoIter {
SectionIteratorLimited::new(self)
}
}
/// Represents a value type in a WebAssembly component.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ComponentValType {
/// The value type is a primitive type.
Primitive(PrimitiveValType),
/// The value type is a reference to a defined type.
Type(u32),
}
/// Represents a primitive value type.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PrimitiveValType {
/// The type is the unit type.
Unit,
/// The type is a boolean.
Bool,
/// The type is a signed 8-bit integer.
S8,
/// The type is an unsigned 8-bit integer.
U8,
/// The type is a signed 16-bit integer.
S16,
/// The type is an unsigned 16-bit integer.
U16,
/// The type is a signed 32-bit integer.
S32,
/// The type is an unsigned 32-bit integer.
U32,
/// The type is a signed 64-bit integer.
S64,
/// The type is an unsigned 64-bit integer.
U64,
/// The type is a 32-bit floating point number.
Float32,
/// The type is a 64-bit floating point number.
Float64,
/// The type is a Unicode character.
Char,
/// The type is a string.
String,
}
impl PrimitiveValType {
pub(crate) fn requires_realloc(&self) -> bool {
matches!(self, Self::String)
}
pub(crate) fn is_subtype_of(&self, other: &Self) -> bool {
// Subtyping rules according to
// https://github.com/WebAssembly/component-model/blob/17f94ed1270a98218e0e796ca1dad1feb7e5c507/design/mvp/Subtyping.md
self == other
|| matches!(
(self, other),
(_, Self::Unit)
| (Self::S8, Self::S16)
| (Self::S8, Self::S32)
| (Self::S8, Self::S64)
| (Self::U8, Self::U16)
| (Self::U8, Self::U32)
| (Self::U8, Self::U64)
| (Self::U8, Self::S16)
| (Self::U8, Self::S32)
| (Self::U8, Self::S64)
| (Self::S16, Self::S32)
| (Self::S16, Self::S64)
| (Self::U16, Self::U32)
| (Self::U16, Self::U64)
| (Self::U16, Self::S32)
| (Self::U16, Self::S64)
| (Self::S32, Self::S64)
| (Self::U32, Self::U64)
| (Self::U32, Self::S64)
| (Self::Float32, Self::Float64)
)
}
pub(crate) fn type_size(&self) -> usize {
match self {
Self::Unit => 0,
_ => 1,
}
}
}
/// Represents a type in a WebAssembly component.
#[derive(Debug, Clone)]
pub enum ComponentType<'a> {
/// The type is a component defined type.
Defined(ComponentDefinedType<'a>),
/// The type is a function type.
Func(ComponentFuncType<'a>),
/// The type is a component type.
Component(Box<[ComponentTypeDeclaration<'a>]>),
/// The type is an instance type.
Instance(Box<[InstanceTypeDeclaration<'a>]>),
}
/// Represents part of a component type declaration in a WebAssembly component.
#[derive(Debug, Clone)]
pub enum ComponentTypeDeclaration<'a> {
/// The component type declaration is for a core type.
CoreType(CoreType<'a>),
/// The component type declaration is for a type.
Type(ComponentType<'a>),
/// The component type declaration is for an alias.
Alias(ComponentAlias<'a>),
/// The component type declaration is for an export.
Export {
/// The name of the export.
name: &'a str,
/// The type reference for the export.
ty: ComponentTypeRef,
},
/// The component type declaration is for an import.
Import(ComponentImport<'a>),
}
/// Represents an instance type declaration in a WebAssembly component.
#[derive(Debug, Clone)]
pub enum InstanceTypeDeclaration<'a> {
/// The component type declaration is for a core type.
CoreType(CoreType<'a>),
/// The instance type declaration is for a type.
Type(ComponentType<'a>),
/// The instance type declaration is for an alias.
Alias(ComponentAlias<'a>),
/// The instance type declaration is for an export.
Export {
/// The name of the export.
name: &'a str,
/// The type reference for the export.
ty: ComponentTypeRef,
},
}
/// Represents a type of a function in a WebAssembly component.
#[derive(Debug, Clone)]
pub struct ComponentFuncType<'a> {
/// The function parameter types.
pub params: Box<[(Option<&'a str>, ComponentValType)]>,
/// The function result type.
pub result: ComponentValType,
}
/// Represents a case in a variant type.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VariantCase<'a> {
/// The name of the variant case.
pub name: &'a str,
/// The value type of the variant case.
pub ty: ComponentValType,
/// The index of the variant case that is refined by this one.
pub refines: Option<u32>,
}
/// Represents a defined type in a WebAssembly component.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ComponentDefinedType<'a> {
/// The type is one of the primitive value types.
Primitive(PrimitiveValType),
/// The type is a record with the given fields.
Record(Box<[(&'a str, ComponentValType)]>),
/// The type is a variant with the given cases.
Variant(Box<[VariantCase<'a>]>),
/// The type is a list of the given value type.
List(ComponentValType),
/// The type is a tuple of the given value types.
Tuple(Box<[ComponentValType]>),
/// The type is flags with the given names.
Flags(Box<[&'a str]>),
/// The type is an enum with the given tags.
Enum(Box<[&'a str]>),
/// The type is a union of the given value types.
Union(Box<[ComponentValType]>),
/// The type is an option of the given value type.
Option(ComponentValType),
/// The type is an expected type.
Expected {
/// The type returned for success.
ok: ComponentValType,
/// The type returned for failure.
error: ComponentValType,
},
}
/// A reader for the type section of a WebAssembly component.
#[derive(Clone)]
pub struct ComponentTypeSectionReader<'a> {
reader: BinaryReader<'a>,
count: u32,
}
impl<'a> ComponentTypeSectionReader<'a> {
/// Constructs a new `ComponentTypeSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<Self> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(Self { reader, count })
}
/// Gets the original position of the reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets a count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
/// Reads content of the type section.
///
/// # Examples
/// ```
/// use wasmparser::ComponentTypeSectionReader;
/// let data: &[u8] = &[0x01, 0x40, 0x01, 0x01, 0x03, b'f', b'o', b'o', 0x72, 0x72];
/// let mut reader = ComponentTypeSectionReader::new(data, 0).unwrap();
/// for _ in 0..reader.get_count() {
/// let ty = reader.read().expect("type");
/// println!("Type {:?}", ty);
/// }
/// ```
pub fn read(&mut self) -> Result<ComponentType<'a>> {
self.reader.read_component_type()
}
}
impl<'a> SectionReader for ComponentTypeSectionReader<'a> {
type Item = ComponentType<'a>;
fn read(&mut self) -> Result<Self::Item> {
Self::read(self)
}
fn eof(&self) -> bool {
self.reader.eof()
}
fn original_position(&self) -> usize {
Self::original_position(self)
}
fn range(&self) -> Range<usize> {
self.reader.range()
}
}
impl<'a> SectionWithLimitedItems for ComponentTypeSectionReader<'a> {
fn get_count(&self) -> u32 {
Self::get_count(self)
}
}
impl<'a> IntoIterator for ComponentTypeSectionReader<'a> {
type Item = Result<ComponentType<'a>>;
type IntoIter = SectionIteratorLimited<Self>;
/// Implements iterator over the type section.
///
/// # Examples
/// ```
/// use wasmparser::ComponentTypeSectionReader;
/// let data: &[u8] = &[0x01, 0x40, 0x01, 0x01, 0x03, b'f', b'o', b'o', 0x72, 0x72];
/// let mut reader = ComponentTypeSectionReader::new(data, 0).unwrap();
/// for ty in reader {
/// println!("Type {:?}", ty.expect("type"));
/// }
/// ```
fn into_iter(self) -> Self::IntoIter {
SectionIteratorLimited::new(self)
}
}

View File

@ -0,0 +1,37 @@
mod code;
mod custom;
mod data;
mod elements;
mod exports;
mod functions;
mod globals;
mod imports;
mod init;
mod linking;
mod memories;
mod names;
mod operators;
mod producers;
mod relocs;
mod tables;
mod tags;
mod types;
pub use self::code::*;
pub use self::custom::*;
pub use self::data::*;
pub use self::elements::*;
pub use self::exports::*;
pub use self::functions::*;
pub use self::globals::*;
pub use self::imports::*;
pub use self::init::*;
pub use self::linking::*;
pub use self::memories::*;
pub use self::names::*;
pub use self::operators::*;
pub use self::producers::*;
pub use self::relocs::*;
pub use self::tables::*;
pub use self::tags::*;
pub use self::types::*;

View File

@ -13,38 +13,59 @@
* limitations under the License.
*/
use super::{
BinaryReader, BinaryReaderError, OperatorsReader, Range, Result, SectionIteratorLimited,
SectionReader, SectionWithLimitedItems, Type,
use crate::{
BinaryReader, BinaryReaderError, OperatorsReader, Result, SectionIteratorLimited,
SectionReader, SectionWithLimitedItems, ValType,
};
use std::ops::Range;
#[derive(Debug, Clone)]
/// Represents a WebAssembly function body.
#[derive(Debug, Clone, Copy)]
pub struct FunctionBody<'a> {
offset: usize,
data: &'a [u8],
allow_memarg64: bool,
}
impl<'a> FunctionBody<'a> {
/// Constructs a new `FunctionBody` for the given data and offset.
pub fn new(offset: usize, data: &'a [u8]) -> Self {
Self { offset, data }
Self {
offset,
data,
allow_memarg64: false,
}
}
/// Whether or not to allow 64-bit memory arguments in the
/// function body.
///
/// This is intended to be `true` when support for the memory64
/// WebAssembly proposal is also enabled.
pub fn allow_memarg64(&mut self, allow: bool) {
self.allow_memarg64 = allow;
}
/// Gets a binary reader for this function body.
pub fn get_binary_reader<'b>(&self) -> BinaryReader<'b>
where
'a: 'b,
{
BinaryReader::new_with_offset(self.data, self.offset)
let mut reader = BinaryReader::new_with_offset(self.data, self.offset);
reader.allow_memarg64(self.allow_memarg64);
reader
}
fn skip_locals(reader: &mut BinaryReader) -> Result<()> {
let count = reader.read_var_u32()?;
for _ in 0..count {
reader.skip_var_32()?;
reader.skip_type()?;
reader.read_var_u32()?;
reader.read_var_u32()?;
}
Ok(())
}
/// Gets the locals reader for this function body.
pub fn get_locals_reader<'b>(&self) -> Result<LocalsReader<'b>>
where
'a: 'b,
@ -54,6 +75,7 @@ impl<'a> FunctionBody<'a> {
Ok(LocalsReader { reader, count })
}
/// Gets the operators reader for this function body.
pub fn get_operators_reader<'b>(&self) -> Result<OperatorsReader<'b>>
where
'a: 'b,
@ -61,45 +83,44 @@ impl<'a> FunctionBody<'a> {
let mut reader = BinaryReader::new_with_offset(self.data, self.offset);
Self::skip_locals(&mut reader)?;
let pos = reader.position;
Ok(OperatorsReader::new(&self.data[pos..], self.offset + pos))
let mut reader = OperatorsReader::new(&self.data[pos..], self.offset + pos);
reader.allow_memarg64(self.allow_memarg64);
Ok(reader)
}
pub fn range(&self) -> Range {
Range {
start: self.offset,
end: self.offset + self.data.len(),
}
/// Gets the range of the function body.
pub fn range(&self) -> Range<usize> {
self.offset..self.offset + self.data.len()
}
}
/// A reader for a function body's locals.
pub struct LocalsReader<'a> {
reader: BinaryReader<'a>,
count: u32,
}
impl<'a> LocalsReader<'a> {
/// Gets the count of locals in the function body.
pub fn get_count(&self) -> u32 {
self.count
}
/// Gets the original position of the reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
pub fn read(&mut self) -> Result<(u32, Type)> {
/// Reads an item from the reader.
pub fn read(&mut self) -> Result<(u32, ValType)> {
let count = self.reader.read_var_u32()?;
let value_type = self.reader.read_type()?;
let value_type = self.reader.read_val_type()?;
Ok((count, value_type))
}
}
pub struct CodeSectionReader<'a> {
reader: BinaryReader<'a>,
count: u32,
}
impl<'a> IntoIterator for LocalsReader<'a> {
type Item = Result<(u32, Type)>;
type Item = Result<(u32, ValType)>;
type IntoIter = LocalsIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
let count = self.count;
@ -111,6 +132,7 @@ impl<'a> IntoIterator for LocalsReader<'a> {
}
}
/// An iterator over locals in a function body.
pub struct LocalsIterator<'a> {
reader: LocalsReader<'a>,
left: u32,
@ -118,7 +140,7 @@ pub struct LocalsIterator<'a> {
}
impl<'a> Iterator for LocalsIterator<'a> {
type Item = Result<(u32, Type)>;
type Item = Result<(u32, ValType)>;
fn next(&mut self) -> Option<Self::Item> {
if self.err || self.left == 0 {
return None;
@ -134,17 +156,26 @@ impl<'a> Iterator for LocalsIterator<'a> {
}
}
/// A reader for the code section of a WebAssembly module.
pub struct CodeSectionReader<'a> {
reader: BinaryReader<'a>,
count: u32,
}
impl<'a> CodeSectionReader<'a> {
/// Constructs a new `CodeSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<CodeSectionReader<'a>> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(CodeSectionReader { reader, count })
}
/// Gets the original position of the reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets the count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
@ -152,7 +183,7 @@ impl<'a> CodeSectionReader<'a> {
fn verify_body_end(&self, end: usize) -> Result<()> {
if self.reader.buffer.len() < end {
return Err(BinaryReaderError::new(
"Function body extends past end of the code section",
"function body extends past end of the code section",
self.reader.original_offset + self.reader.buffer.len(),
));
}
@ -187,6 +218,7 @@ impl<'a> CodeSectionReader<'a> {
Ok(FunctionBody {
offset: self.reader.original_offset + body_start,
data: &self.reader.buffer[body_start..body_end],
allow_memarg64: false,
})
}
}
@ -202,7 +234,7 @@ impl<'a> SectionReader for CodeSectionReader<'a> {
fn original_position(&self) -> usize {
CodeSectionReader::original_position(self)
}
fn range(&self) -> Range {
fn range(&self) -> Range<usize> {
self.reader.range()
}
}

View File

@ -0,0 +1,63 @@
use crate::{BinaryReader, Result};
use std::ops::Range;
/// A reader for custom sections of a WebAssembly module.
#[derive(Clone)]
pub struct CustomSectionReader<'a> {
// NB: these fields are public to the crate to make testing easier.
pub(crate) name: &'a str,
pub(crate) data_offset: usize,
pub(crate) data: &'a [u8],
pub(crate) range: Range<usize>,
}
impl<'a> CustomSectionReader<'a> {
/// Constructs a new `CustomSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<CustomSectionReader<'a>> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let name = reader.read_string()?;
let data_offset = reader.original_position();
let data = reader.remaining_buffer();
let range = reader.range();
Ok(CustomSectionReader {
name,
data_offset,
data,
range,
})
}
/// The name of the custom section.
pub fn name(&self) -> &'a str {
self.name
}
/// The offset, relative to the start of the original module or component,
/// that the `data` payload for this custom section starts at.
pub fn data_offset(&self) -> usize {
self.data_offset
}
/// The actual contents of the custom section.
pub fn data(&self) -> &'a [u8] {
self.data
}
/// The range of bytes that specify this whole custom section (including
/// both the name of this custom section and its data) specified in
/// offsets relative to the start of the byte stream.
pub fn range(&self) -> Range<usize> {
self.range.clone()
}
}
impl<'a> std::fmt::Debug for CustomSectionReader<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CustomSectionReader")
.field("name", &self.name)
.field("data_offset", &self.data_offset)
.field("data", &"...")
.field("range", &self.range)
.finish()
}
}

View File

@ -13,60 +13,66 @@
* limitations under the License.
*/
use super::{
BinaryReader, BinaryReaderError, InitExpr, Range, Result, SectionIteratorLimited,
SectionReader, SectionWithLimitedItems,
use crate::{
BinaryReader, BinaryReaderError, InitExpr, Result, SectionIteratorLimited, SectionReader,
SectionWithLimitedItems,
};
use std::ops::Range;
#[derive(Debug, Copy, Clone)]
/// Represents a data segment in a core WebAssembly module.
#[derive(Debug, Clone)]
pub struct Data<'a> {
/// The kind of data segment.
pub kind: DataKind<'a>,
/// The data of the data segment.
pub data: &'a [u8],
/// The range of the data segment.
pub range: Range<usize>,
}
/// The kind of data segment.
#[derive(Debug, Copy, Clone)]
pub enum DataKind<'a> {
/// The data segment is passive.
Passive,
/// The data segment is active.
Active {
/// The memory index for the data segment.
memory_index: u32,
/// The initialization expression for the data segment.
init_expr: InitExpr<'a>,
},
}
/// A reader for the data section of a WebAssembly module.
#[derive(Clone)]
pub struct DataSectionReader<'a> {
reader: BinaryReader<'a>,
count: u32,
forbid_bulk_memory: bool,
}
impl<'a> DataSectionReader<'a> {
/// Constructs a new `DataSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<DataSectionReader<'a>> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(DataSectionReader {
reader,
count,
forbid_bulk_memory: false,
})
Ok(DataSectionReader { reader, count })
}
/// Gets the original position of the section reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets the count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
pub fn forbid_bulk_memory(&mut self, forbid: bool) {
self.forbid_bulk_memory = forbid;
}
fn verify_data_end(&self, end: usize) -> Result<()> {
if self.reader.buffer.len() < end {
return Err(BinaryReaderError::new(
"Data segment extends past end of the data section",
"unexpected end of section or function: data segment extends past end of the data section",
self.reader.original_offset + self.reader.buffer.len(),
));
}
@ -95,20 +101,29 @@ impl<'a> DataSectionReader<'a> {
where
'a: 'b,
{
let segment_start = self.reader.original_position();
// The current handling of the flags is largely specified in the `bulk-memory` proposal,
// which at the time this commend is written has been merged to the main specification
// draft.
//
// Notably, this proposal allows multiple different encodings of the memory index 0. `00`
// and `02 00` are both valid ways to specify the 0-th memory. However it also makes
// another encoding of the 0-th memory `80 00` no longer valid.
//
// We, however maintain this by parsing `flags` as a LEB128 integer. In that case, `80 00`
// encoding is parsed out as `0` and is therefore assigned a `memidx` 0, even though the
// current specification draft does not allow for this.
//
// See also https://github.com/WebAssembly/spec/issues/1439
let flags = self.reader.read_var_u32()?;
let kind = if !self.forbid_bulk_memory && flags == 1 {
DataKind::Passive
let kind = match flags {
1 => DataKind::Passive,
0 | 2 => {
let memory_index = if flags == 0 {
0
} else {
let memory_index = match flags {
0 => 0,
_ if self.forbid_bulk_memory => flags,
2 => self.reader.read_var_u32()?,
_ => {
return Err(BinaryReaderError::new(
"invalid flags byte in data segment",
self.reader.original_position() - 1,
));
}
self.reader.read_var_u32()?
};
let init_expr = {
let expr_offset = self.reader.position;
@ -120,13 +135,25 @@ impl<'a> DataSectionReader<'a> {
memory_index,
init_expr,
}
}
_ => {
return Err(BinaryReaderError::new(
"invalid flags byte in data segment",
self.reader.original_position() - 1,
));
}
};
let data_len = self.reader.read_var_u32()? as usize;
let data_end = self.reader.position + data_len;
self.verify_data_end(data_end)?;
let data = &self.reader.buffer[self.reader.position..data_end];
self.reader.skip_to(data_end);
Ok(Data { kind, data })
let segment_end = self.reader.original_position();
let range = segment_start..segment_end;
Ok(Data { kind, data, range })
}
}
@ -141,7 +168,7 @@ impl<'a> SectionReader for DataSectionReader<'a> {
fn original_position(&self) -> usize {
DataSectionReader::original_position(self)
}
fn range(&self) -> Range {
fn range(&self) -> Range<usize> {
self.reader.range()
}
}

View File

@ -13,29 +13,42 @@
* limitations under the License.
*/
use super::{
BinaryReader, BinaryReaderError, InitExpr, Range, Result, SectionIteratorLimited,
SectionReader, SectionWithLimitedItems, Type,
use crate::{
BinaryReader, BinaryReaderError, ExternalKind, InitExpr, Result, SectionIteratorLimited,
SectionReader, SectionWithLimitedItems, ValType,
};
use crate::{ExternalKind, Operator};
use std::ops::Range;
/// Represents a core WebAssembly element segment.
#[derive(Clone)]
pub struct Element<'a> {
/// The kind of the element segment.
pub kind: ElementKind<'a>,
/// The initial elements of the element segment.
pub items: ElementItems<'a>,
pub ty: Type,
/// The type of the elements.
pub ty: ValType,
/// The range of the the element segment.
pub range: Range<usize>,
}
/// The kind of element segment.
#[derive(Clone)]
pub enum ElementKind<'a> {
/// The element segment is passive.
Passive,
/// The element segment is active.
Active {
/// The index of the table being initialized.
table_index: u32,
/// The initial expression of the element segment.
init_expr: InitExpr<'a>,
},
/// The element segment is declared.
Declared,
}
/// Represents the items of an element segment.
#[derive(Debug, Copy, Clone)]
pub struct ElementItems<'a> {
exprs: bool,
@ -43,13 +56,17 @@ pub struct ElementItems<'a> {
data: &'a [u8],
}
/// Represents an individual item of an element segment.
#[derive(Debug)]
pub enum ElementItem {
Null(Type),
pub enum ElementItem<'a> {
/// The item is a function index.
Func(u32),
/// The item is an initialization expression.
Expr(InitExpr<'a>),
}
impl<'a> ElementItems<'a> {
/// Gets an items reader for the items in an element segment.
pub fn get_items_reader<'b>(&self) -> Result<ElementItemsReader<'b>>
where
'a: 'b,
@ -58,6 +75,7 @@ impl<'a> ElementItems<'a> {
}
}
/// A reader for element items in an element segment.
pub struct ElementItemsReader<'a> {
reader: BinaryReader<'a>,
count: u32,
@ -65,6 +83,7 @@ pub struct ElementItemsReader<'a> {
}
impl<'a> ElementItemsReader<'a> {
/// Constructs a new `ElementItemsReader` for the given data and offset.
pub fn new(data: &[u8], offset: usize, exprs: bool) -> Result<ElementItemsReader> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
@ -75,39 +94,35 @@ impl<'a> ElementItemsReader<'a> {
})
}
/// Gets the original position of the reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets the count of element items in the segment.
pub fn get_count(&self) -> u32 {
self.count
}
/// Whether or not initialization expressions are used.
pub fn uses_exprs(&self) -> bool {
self.exprs
}
pub fn read(&mut self) -> Result<ElementItem> {
/// Reads an element item from the segment.
pub fn read(&mut self) -> Result<ElementItem<'a>> {
if self.exprs {
let offset = self.reader.original_position();
let ret = match self.reader.read_operator()? {
Operator::RefNull { ty } => ElementItem::Null(ty),
Operator::RefFunc { function_index } => ElementItem::Func(function_index),
_ => return Err(BinaryReaderError::new("invalid passive segment", offset)),
};
match self.reader.read_operator()? {
Operator::End => {}
_ => return Err(BinaryReaderError::new("invalid passive segment", offset)),
}
Ok(ret)
let expr = self.reader.read_init_expr()?;
Ok(ElementItem::Expr(expr))
} else {
self.reader.read_var_u32().map(ElementItem::Func)
let idx = self.reader.read_var_u32()?;
Ok(ElementItem::Func(idx))
}
}
}
impl<'a> IntoIterator for ElementItemsReader<'a> {
type Item = Result<ElementItem>;
type Item = Result<ElementItem<'a>>;
type IntoIter = ElementItemsIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
let count = self.count;
@ -119,6 +134,7 @@ impl<'a> IntoIterator for ElementItemsReader<'a> {
}
}
/// An iterator over element items in an element segment.
pub struct ElementItemsIterator<'a> {
reader: ElementItemsReader<'a>,
left: u32,
@ -126,7 +142,7 @@ pub struct ElementItemsIterator<'a> {
}
impl<'a> Iterator for ElementItemsIterator<'a> {
type Item = Result<ElementItem>;
type Item = Result<ElementItem<'a>>;
fn next(&mut self) -> Option<Self::Item> {
if self.err || self.left == 0 {
return None;
@ -142,6 +158,7 @@ impl<'a> Iterator for ElementItemsIterator<'a> {
}
}
/// A reader for the element section of a WebAssembly module.
#[derive(Clone)]
pub struct ElementSectionReader<'a> {
reader: BinaryReader<'a>,
@ -149,16 +166,19 @@ pub struct ElementSectionReader<'a> {
}
impl<'a> ElementSectionReader<'a> {
/// Constructs a new `ElementSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<ElementSectionReader<'a>> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(ElementSectionReader { reader, count })
}
/// Gets the original position of the section reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets the count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
@ -189,6 +209,20 @@ impl<'a> ElementSectionReader<'a> {
where
'a: 'b,
{
let elem_start = self.reader.original_position();
// The current handling of the flags is largely specified in the `bulk-memory` proposal,
// which at the time this commend is written has been merged to the main specification
// draft.
//
// Notably, this proposal allows multiple different encodings of the table index 0. `00`
// and `02 00` are both valid ways to specify the 0-th table. However it also makes
// another encoding of the 0-th memory `80 00` no longer valid.
//
// We, however maintain this support by parsing `flags` as a LEB128 integer. In that case,
// `80 00` encoding is parsed out as `0` and is therefore assigned a `tableidx` 0, even
// though the current specification draft does not allow for this.
//
// See also https://github.com/WebAssembly/spec/issues/1439
let flags = self.reader.read_var_u32()?;
if (flags & !0b111) != 0 {
return Err(BinaryReaderError::new(
@ -222,10 +256,10 @@ impl<'a> ElementSectionReader<'a> {
let exprs = flags & 0b100 != 0;
let ty = if flags & 0b011 != 0 {
if exprs {
self.reader.read_type()?
self.reader.read_val_type()?
} else {
match self.reader.read_external_kind()? {
ExternalKind::Function => Type::FuncRef,
ExternalKind::Func => ValType::FuncRef,
_ => {
return Err(BinaryReaderError::new(
"only the function external type is supported in elem segment",
@ -235,7 +269,7 @@ impl<'a> ElementSectionReader<'a> {
}
}
} else {
Type::FuncRef
ValType::FuncRef
};
let data_start = self.reader.position;
let items_count = self.reader.read_var_u32()?;
@ -245,7 +279,7 @@ impl<'a> ElementSectionReader<'a> {
}
} else {
for _ in 0..items_count {
self.reader.skip_var_32()?;
self.reader.read_var_u32()?;
}
}
let data_end = self.reader.position;
@ -254,7 +288,16 @@ impl<'a> ElementSectionReader<'a> {
data: &self.reader.buffer[data_start..data_end],
exprs,
};
Ok(Element { kind, items, ty })
let elem_end = self.reader.original_position();
let range = elem_start..elem_end;
Ok(Element {
kind,
items,
ty,
range,
})
}
}
@ -269,7 +312,7 @@ impl<'a> SectionReader for ElementSectionReader<'a> {
fn original_position(&self) -> usize {
ElementSectionReader::original_position(self)
}
fn range(&self) -> Range {
fn range(&self) -> Range<usize> {
self.reader.range()
}
}

View File

@ -13,18 +13,38 @@
* limitations under the License.
*/
use super::{
BinaryReader, ExternalKind, Range, Result, SectionIteratorLimited, SectionReader,
SectionWithLimitedItems,
};
use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems};
use std::ops::Range;
/// External types as defined [here].
///
/// [here]: https://webassembly.github.io/spec/core/syntax/types.html#external-types
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ExternalKind {
/// The external kind is a function.
Func,
/// The external kind if a table.
Table,
/// The external kind is a memory.
Memory,
/// The external kind is a global.
Global,
/// The external kind is a tag.
Tag,
}
/// Represents an export in a WebAssembly module.
#[derive(Debug, Copy, Clone)]
pub struct Export<'a> {
pub field: &'a str,
/// The name of the exported item.
pub name: &'a str,
/// The kind of the export.
pub kind: ExternalKind,
/// The index of the exported item.
pub index: u32,
}
/// A reader for the export section of a WebAssembly module.
#[derive(Clone)]
pub struct ExportSectionReader<'a> {
reader: BinaryReader<'a>,
@ -32,16 +52,19 @@ pub struct ExportSectionReader<'a> {
}
impl<'a> ExportSectionReader<'a> {
pub fn new(data: &'a [u8], offset: usize) -> Result<ExportSectionReader<'a>> {
/// Constructs a new `ExportSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<Self> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(ExportSectionReader { reader, count })
Ok(Self { reader, count })
}
/// Gets the original position of the section reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets the count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
@ -53,48 +76,46 @@ impl<'a> ExportSectionReader<'a> {
/// use wasmparser::ExportSectionReader;
///
/// # let data: &[u8] = &[0x01, 0x01, 0x65, 0x00, 0x00];
/// let mut export_reader = ExportSectionReader::new(data, 0).unwrap();
/// for _ in 0..export_reader.get_count() {
/// let export = export_reader.read().expect("export");
/// let mut reader = ExportSectionReader::new(data, 0).unwrap();
/// for _ in 0..reader.get_count() {
/// let export = reader.read().expect("export");
/// println!("Export: {:?}", export);
/// }
/// ```
pub fn read<'b>(&mut self) -> Result<Export<'b>>
where
'a: 'b,
{
let field = self.reader.read_string()?;
let kind = self.reader.read_external_kind()?;
let index = self.reader.read_var_u32()?;
Ok(Export { field, kind, index })
pub fn read(&mut self) -> Result<Export<'a>> {
self.reader.read_export()
}
}
impl<'a> SectionReader for ExportSectionReader<'a> {
type Item = Export<'a>;
fn read(&mut self) -> Result<Self::Item> {
ExportSectionReader::read(self)
Self::read(self)
}
fn eof(&self) -> bool {
self.reader.eof()
}
fn original_position(&self) -> usize {
ExportSectionReader::original_position(self)
Self::original_position(self)
}
fn range(&self) -> Range {
fn range(&self) -> Range<usize> {
self.reader.range()
}
}
impl<'a> SectionWithLimitedItems for ExportSectionReader<'a> {
fn get_count(&self) -> u32 {
ExportSectionReader::get_count(self)
Self::get_count(self)
}
}
impl<'a> IntoIterator for ExportSectionReader<'a> {
type Item = Result<Export<'a>>;
type IntoIter = SectionIteratorLimited<ExportSectionReader<'a>>;
type IntoIter = SectionIteratorLimited<Self>;
fn into_iter(self) -> Self::IntoIter {
SectionIteratorLimited::new(self)

View File

@ -13,10 +13,10 @@
* limitations under the License.
*/
use super::{
BinaryReader, Range, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems,
};
use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems};
use std::ops::Range;
/// A reader for the function section of a WebAssembly module.
#[derive(Clone)]
pub struct FunctionSectionReader<'a> {
reader: BinaryReader<'a>,
@ -24,16 +24,19 @@ pub struct FunctionSectionReader<'a> {
}
impl<'a> FunctionSectionReader<'a> {
pub fn new(data: &'a [u8], offset: usize) -> Result<FunctionSectionReader<'a>> {
/// Constructs a new `FunctionSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<Self> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(FunctionSectionReader { reader, count })
Ok(Self { reader, count })
}
/// Gets the original position of the section reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets the count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
@ -45,9 +48,9 @@ impl<'a> FunctionSectionReader<'a> {
/// ```
/// use wasmparser::FunctionSectionReader;
/// # let data: &[u8] = &[0x01, 0x00];
/// let mut function_reader = FunctionSectionReader::new(data, 0).unwrap();
/// for _ in 0..function_reader.get_count() {
/// let ty = function_reader.read().expect("function type index");
/// let mut reader = FunctionSectionReader::new(data, 0).unwrap();
/// for _ in 0..reader.get_count() {
/// let ty = reader.read().expect("function type index");
/// println!("Function type index: {}", ty);
/// }
/// ```
@ -58,29 +61,33 @@ impl<'a> FunctionSectionReader<'a> {
impl<'a> SectionReader for FunctionSectionReader<'a> {
type Item = u32;
fn read(&mut self) -> Result<Self::Item> {
FunctionSectionReader::read(self)
Self::read(self)
}
fn eof(&self) -> bool {
self.reader.eof()
}
fn original_position(&self) -> usize {
FunctionSectionReader::original_position(self)
Self::original_position(self)
}
fn range(&self) -> Range {
fn range(&self) -> Range<usize> {
self.reader.range()
}
}
impl<'a> SectionWithLimitedItems for FunctionSectionReader<'a> {
fn get_count(&self) -> u32 {
FunctionSectionReader::get_count(self)
Self::get_count(self)
}
}
impl<'a> IntoIterator for FunctionSectionReader<'a> {
type Item = Result<u32>;
type IntoIter = SectionIteratorLimited<FunctionSectionReader<'a>>;
type IntoIter = SectionIteratorLimited<Self>;
fn into_iter(self) -> Self::IntoIter {
SectionIteratorLimited::new(self)

View File

@ -13,17 +13,22 @@
* limitations under the License.
*/
use super::{
BinaryReader, GlobalType, InitExpr, Range, Result, SectionIteratorLimited, SectionReader,
use crate::{
BinaryReader, GlobalType, InitExpr, Result, SectionIteratorLimited, SectionReader,
SectionWithLimitedItems,
};
use std::ops::Range;
/// Represents a core WebAssembly global.
#[derive(Debug, Copy, Clone)]
pub struct Global<'a> {
/// The global's type.
pub ty: GlobalType,
/// The global's initialization expression.
pub init_expr: InitExpr<'a>,
}
/// A reader for the global section of a WebAssembly module.
#[derive(Clone)]
pub struct GlobalSectionReader<'a> {
reader: BinaryReader<'a>,
@ -31,16 +36,19 @@ pub struct GlobalSectionReader<'a> {
}
impl<'a> GlobalSectionReader<'a> {
/// Constructs a new `GlobalSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<GlobalSectionReader<'a>> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(GlobalSectionReader { reader, count })
}
/// Gets the original position of the section reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets the count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
@ -65,10 +73,7 @@ impl<'a> GlobalSectionReader<'a> {
'a: 'b,
{
let ty = self.reader.read_global_type()?;
let expr_offset = self.reader.position;
self.reader.skip_init_expr()?;
let data = &self.reader.buffer[expr_offset..self.reader.position];
let init_expr = InitExpr::new(data, self.reader.original_offset + expr_offset);
let init_expr = self.reader.read_init_expr()?;
Ok(Global { ty, init_expr })
}
}
@ -84,7 +89,7 @@ impl<'a> SectionReader for GlobalSectionReader<'a> {
fn original_position(&self) -> usize {
GlobalSectionReader::original_position(self)
}
fn range(&self) -> Range {
fn range(&self) -> Range<usize> {
self.reader.range()
}
}

View File

@ -14,17 +14,44 @@
*/
use crate::{
BinaryReader, ImportSectionEntryType, Range, Result, SectionIteratorLimited, SectionReader,
SectionWithLimitedItems,
BinaryReader, GlobalType, MemoryType, Result, SectionIteratorLimited, SectionReader,
SectionWithLimitedItems, TableType, TagType,
};
use std::ops::Range;
#[derive(Debug, Copy, Clone)]
pub struct Import<'a> {
pub module: &'a str,
pub field: Option<&'a str>,
pub ty: ImportSectionEntryType,
/// Represents a reference to a type definition in a WebAssembly module.
#[derive(Debug, Clone, Copy)]
pub enum TypeRef {
/// The type is a function.
///
/// The value is an index into the type section.
Func(u32),
/// The type is a table.
Table(TableType),
/// The type is a memory.
Memory(MemoryType),
/// The type is a global.
Global(GlobalType),
/// The type is a tag.
///
/// This variant is only used for the exception handling proposal.
///
/// The value is an index in the types index space.
Tag(TagType),
}
/// Represents an import in a WebAssembly module.
#[derive(Debug, Copy, Clone)]
pub struct Import<'a> {
/// The module being imported from.
pub module: &'a str,
/// The name of the imported item.
pub name: &'a str,
/// The type of the imported item.
pub ty: TypeRef,
}
/// A reader for the import section of a WebAssembly module.
#[derive(Clone)]
pub struct ImportSectionReader<'a> {
reader: BinaryReader<'a>,
@ -32,16 +59,19 @@ pub struct ImportSectionReader<'a> {
}
impl<'a> ImportSectionReader<'a> {
pub fn new(data: &'a [u8], offset: usize) -> Result<ImportSectionReader<'a>> {
/// Constructs a new `ImportSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<Self> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(ImportSectionReader { reader, count })
Ok(Self { reader, count })
}
/// Gets the original position of the section reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets the count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
@ -51,46 +81,47 @@ impl<'a> ImportSectionReader<'a> {
/// # Examples
/// ```
/// use wasmparser::ImportSectionReader;
/// # let data: &[u8] = &[0x01, 0x01, 0x41, 0x01, 0x66, 0x00, 0x00];
/// let mut import_reader = ImportSectionReader::new(data, 0).unwrap();
/// for _ in 0..import_reader.get_count() {
/// let import = import_reader.read().expect("import");
/// let data: &[u8] = &[0x01, 0x01, 0x41, 0x01, 0x66, 0x00, 0x00];
/// let mut reader = ImportSectionReader::new(data, 0).unwrap();
/// for _ in 0..reader.get_count() {
/// let import = reader.read().expect("import");
/// println!("Import: {:?}", import);
/// }
/// ```
pub fn read<'b>(&mut self) -> Result<Import<'b>>
where
'a: 'b,
{
pub fn read(&mut self) -> Result<Import<'a>> {
self.reader.read_import()
}
}
impl<'a> SectionReader for ImportSectionReader<'a> {
type Item = Import<'a>;
fn read(&mut self) -> Result<Self::Item> {
ImportSectionReader::read(self)
Self::read(self)
}
fn eof(&self) -> bool {
self.reader.eof()
}
fn original_position(&self) -> usize {
ImportSectionReader::original_position(self)
Self::original_position(self)
}
fn range(&self) -> Range {
fn range(&self) -> Range<usize> {
self.reader.range()
}
}
impl<'a> SectionWithLimitedItems for ImportSectionReader<'a> {
fn get_count(&self) -> u32 {
ImportSectionReader::get_count(self)
Self::get_count(self)
}
}
impl<'a> IntoIterator for ImportSectionReader<'a> {
type Item = Result<Import<'a>>;
type IntoIter = SectionIteratorLimited<ImportSectionReader<'a>>;
type IntoIter = SectionIteratorLimited<Self>;
fn into_iter(self) -> Self::IntoIter {
SectionIteratorLimited::new(self)

View File

@ -13,8 +13,9 @@
* limitations under the License.
*/
use super::{BinaryReader, OperatorsReader};
use crate::{BinaryReader, OperatorsReader};
/// Represents an initialization expression.
#[derive(Debug, Copy, Clone)]
pub struct InitExpr<'a> {
offset: usize,
@ -22,10 +23,12 @@ pub struct InitExpr<'a> {
}
impl<'a> InitExpr<'a> {
/// Constructs a new `InitExpr` from the given data and offset.
pub fn new(data: &[u8], offset: usize) -> InitExpr {
InitExpr { offset, data }
}
/// Gets a binary reader for the initialization expression.
pub fn get_binary_reader<'b>(&self) -> BinaryReader<'b>
where
'a: 'b,
@ -33,6 +36,7 @@ impl<'a> InitExpr<'a> {
BinaryReader::new_with_offset(self.data, self.offset)
}
/// Gets an operators reader for the initialization expression.
pub fn get_operators_reader<'b>(&self) -> OperatorsReader<'b>
where
'a: 'b,

View File

@ -13,36 +13,46 @@
* limitations under the License.
*/
use super::{
BinaryReader, LinkingType, Range, Result, SectionIteratorLimited, SectionReader,
SectionWithLimitedItems,
};
use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems};
use std::ops::Range;
/// Represents a linking type.
#[derive(Debug, Copy, Clone)]
pub enum LinkingType {
/// The linking uses a stack pointer.
StackPointer(u32),
}
/// A reader for the linking custom section of a WebAssembly module.
pub struct LinkingSectionReader<'a> {
reader: BinaryReader<'a>,
count: u32,
}
impl<'a> LinkingSectionReader<'a> {
/// Constructs a new `LinkingSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<LinkingSectionReader<'a>> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(LinkingSectionReader { reader, count })
}
/// Gets the count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
/// Gets the original position of the reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Reads an item from the section.
pub fn read<'b>(&mut self) -> Result<LinkingType>
where
'a: 'b,
{
Ok(self.reader.read_linking_type()?)
self.reader.read_linking_type()
}
}
@ -57,7 +67,7 @@ impl<'a> SectionReader for LinkingSectionReader<'a> {
fn original_position(&self) -> usize {
LinkingSectionReader::original_position(self)
}
fn range(&self) -> Range {
fn range(&self) -> Range<usize> {
self.reader.range()
}
}

View File

@ -13,11 +13,13 @@
* limitations under the License.
*/
use super::{
BinaryReader, MemoryType, Range, Result, SectionIteratorLimited, SectionReader,
use crate::{
BinaryReader, MemoryType, Result, SectionIteratorLimited, SectionReader,
SectionWithLimitedItems,
};
use std::ops::Range;
/// A reader for the memory section of a WebAssembly module.
#[derive(Clone)]
pub struct MemorySectionReader<'a> {
reader: BinaryReader<'a>,
@ -25,16 +27,19 @@ pub struct MemorySectionReader<'a> {
}
impl<'a> MemorySectionReader<'a> {
/// Constructs a new `MemorySectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<MemorySectionReader<'a>> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(MemorySectionReader { reader, count })
}
/// Gets the original position of the section reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets the count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
@ -67,7 +72,7 @@ impl<'a> SectionReader for MemorySectionReader<'a> {
fn original_position(&self) -> usize {
MemorySectionReader::original_position(self)
}
fn range(&self) -> Range {
fn range(&self) -> Range<usize> {
self.reader.range()
}
}

View File

@ -13,18 +13,56 @@
* limitations under the License.
*/
use super::{
BinaryReader, BinaryReaderError, NameType, Naming, Range, Result, SectionIterator,
SectionReader,
};
use crate::{BinaryReader, BinaryReaderError, Result, SectionIterator, SectionReader};
use std::ops::Range;
/// Represents a name for an index from the names section.
#[derive(Debug, Copy, Clone)]
pub struct ModuleName<'a> {
pub struct Naming<'a> {
/// The index being named.
pub index: u32,
/// The name for the index.
pub name: &'a str,
}
/// Represents the type of name.
#[derive(Debug, Copy, Clone)]
pub enum NameType {
/// The name is for a module.
Module,
/// The name is for a function.
Function,
/// The name is for a local.
Local,
/// The name is for a label.
Label,
/// The name is for a type.
Type,
/// The name is for a table.
Table,
/// The name is for a memory.
Memory,
/// The name is for a global.
Global,
/// The name is for an element segment.
Element,
/// The name is for a data segment.
Data,
/// The name is unknown.
///
/// The value is the unknown section identifier.
Unknown(u8),
}
/// Represents a single name in the names custom section.
#[derive(Debug, Copy, Clone)]
pub struct SingleName<'a> {
data: &'a [u8],
offset: usize,
}
impl<'a> ModuleName<'a> {
impl<'a> SingleName<'a> {
/// Gets the name as a string.
pub fn get_name<'b>(&self) -> Result<&'b str>
where
'a: 'b,
@ -33,11 +71,13 @@ impl<'a> ModuleName<'a> {
reader.read_string()
}
/// Gets the original position of the name.
pub fn original_position(&self) -> usize {
self.offset
}
}
/// A reader for direct names in the names custom section.
pub struct NamingReader<'a> {
reader: BinaryReader<'a>,
count: u32,
@ -53,20 +93,23 @@ impl<'a> NamingReader<'a> {
fn skip(reader: &mut BinaryReader) -> Result<()> {
let count = reader.read_var_u32()?;
for _ in 0..count {
reader.skip_var_32()?;
reader.read_var_u32()?;
reader.skip_string()?;
}
Ok(())
}
/// Gets the original position of the reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets the count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
/// Reads a name from the names custom section.
pub fn read<'b>(&mut self) -> Result<Naming<'b>>
where
'a: 'b,
@ -77,13 +120,15 @@ impl<'a> NamingReader<'a> {
}
}
/// Represents a name map from the names custom section.
#[derive(Debug, Copy, Clone)]
pub struct FunctionName<'a> {
pub struct NameMap<'a> {
data: &'a [u8],
offset: usize,
}
impl<'a> FunctionName<'a> {
impl<'a> NameMap<'a> {
/// Gets a naming reader for the map.
pub fn get_map<'b>(&self) -> Result<NamingReader<'b>>
where
'a: 'b,
@ -91,19 +136,23 @@ impl<'a> FunctionName<'a> {
NamingReader::new(self.data, self.offset)
}
/// Gets the original position of the map.
pub fn original_position(&self) -> usize {
self.offset
}
}
/// Represents an indirect name in the names custom section.
#[derive(Debug, Copy, Clone)]
pub struct FunctionLocalName<'a> {
pub func_index: u32,
pub struct IndirectNaming<'a> {
/// The indirect index of the name.
pub indirect_index: u32,
data: &'a [u8],
offset: usize,
}
impl<'a> FunctionLocalName<'a> {
impl<'a> IndirectNaming<'a> {
/// Gets the naming reader for the indirect name.
pub fn get_map<'b>(&self) -> Result<NamingReader<'b>>
where
'a: 'b,
@ -111,88 +160,116 @@ impl<'a> FunctionLocalName<'a> {
NamingReader::new(self.data, self.offset)
}
/// Gets the original position of the indirect name.
pub fn original_position(&self) -> usize {
self.offset
}
}
pub struct FunctionLocalReader<'a> {
/// Represents a reader for indirect names from the names custom section.
pub struct IndirectNamingReader<'a> {
reader: BinaryReader<'a>,
count: u32,
}
impl<'a> FunctionLocalReader<'a> {
fn new(data: &'a [u8], offset: usize) -> Result<FunctionLocalReader<'a>> {
impl<'a> IndirectNamingReader<'a> {
fn new(data: &'a [u8], offset: usize) -> Result<IndirectNamingReader<'a>> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(FunctionLocalReader { reader, count })
Ok(IndirectNamingReader { reader, count })
}
pub fn get_count(&self) -> u32 {
/// Gets the count of indirect names.
pub fn get_indirect_count(&self) -> u32 {
self.count
}
/// Gets the original position of the reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
pub fn read<'b>(&mut self) -> Result<FunctionLocalName<'b>>
/// Reads an indirect name from the reader.
pub fn read<'b>(&mut self) -> Result<IndirectNaming<'b>>
where
'a: 'b,
{
let func_index = self.reader.read_var_u32()?;
let index = self.reader.read_var_u32()?;
let start = self.reader.position;
NamingReader::skip(&mut self.reader)?;
let end = self.reader.position;
Ok(FunctionLocalName {
func_index,
Ok(IndirectNaming {
indirect_index: index,
data: &self.reader.buffer[start..end],
offset: self.reader.original_offset + start,
})
}
}
/// Represents an indirect name map.
#[derive(Debug, Copy, Clone)]
pub struct LocalName<'a> {
pub struct IndirectNameMap<'a> {
data: &'a [u8],
offset: usize,
}
impl<'a> LocalName<'a> {
pub fn get_function_local_reader<'b>(&self) -> Result<FunctionLocalReader<'b>>
impl<'a> IndirectNameMap<'a> {
/// Gets an indirect naming reader for the map.
pub fn get_indirect_map<'b>(&self) -> Result<IndirectNamingReader<'b>>
where
'a: 'b,
{
FunctionLocalReader::new(self.data, self.offset)
IndirectNamingReader::new(self.data, self.offset)
}
/// Gets an original position of the map.
pub fn original_position(&self) -> usize {
self.offset
}
}
#[derive(Debug, Copy, Clone)]
/// Represents a name read from the names custom section.
#[derive(Debug, Clone)]
pub enum Name<'a> {
Module(ModuleName<'a>),
Function(FunctionName<'a>),
Local(LocalName<'a>),
/// The name is for the module.
Module(SingleName<'a>),
/// The name is for the functions.
Function(NameMap<'a>),
/// The name is for the function locals.
Local(IndirectNameMap<'a>),
/// The name is for the function labels.
Label(IndirectNameMap<'a>),
/// The name is for the types.
Type(NameMap<'a>),
/// The name is for the tables.
Table(NameMap<'a>),
/// The name is for the memories.
Memory(NameMap<'a>),
/// The name is for the globals.
Global(NameMap<'a>),
/// The name is for the element segments.
Element(NameMap<'a>),
/// The name is for the data segments.
Data(NameMap<'a>),
/// An unknown [name subsection](https://webassembly.github.io/spec/core/appendix/custom.html#subsections).
Unknown {
/// The identifier for this subsection.
ty: u32,
ty: u8,
/// The contents of this subsection.
data: &'a [u8],
/// The range of bytes, relative to the start of the original data
/// stream, that the contents of this subsection reside in.
range: Range,
range: Range<usize>,
},
}
/// A reader for the name custom section of a WebAssembly module.
pub struct NameSectionReader<'a> {
reader: BinaryReader<'a>,
}
impl<'a> NameSectionReader<'a> {
/// Constructs a new `NameSectionReader` from the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<NameSectionReader<'a>> {
Ok(NameSectionReader {
reader: BinaryReader::new_with_offset(data, offset),
@ -202,21 +279,24 @@ impl<'a> NameSectionReader<'a> {
fn verify_section_end(&self, end: usize) -> Result<()> {
if self.reader.buffer.len() < end {
return Err(BinaryReaderError::new(
"Name entry extends past end of the code section",
"name entry extends past end of the code section",
self.reader.original_offset + self.reader.buffer.len(),
));
}
Ok(())
}
/// Determines if the reader is at the end of the section.
pub fn eof(&self) -> bool {
self.reader.eof()
}
/// Gets the original position of the section reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Reads a name from the section.
pub fn read<'b>(&mut self) -> Result<Name<'b>>
where
'a: 'b,
@ -230,13 +310,20 @@ impl<'a> NameSectionReader<'a> {
let data = &self.reader.buffer[payload_start..payload_end];
self.reader.skip_to(payload_end);
Ok(match ty {
NameType::Module => Name::Module(ModuleName { data, offset }),
NameType::Function => Name::Function(FunctionName { data, offset }),
NameType::Local => Name::Local(LocalName { data, offset }),
NameType::Module => Name::Module(SingleName { data, offset }),
NameType::Function => Name::Function(NameMap { data, offset }),
NameType::Local => Name::Local(IndirectNameMap { data, offset }),
NameType::Label => Name::Label(IndirectNameMap { data, offset }),
NameType::Type => Name::Type(NameMap { data, offset }),
NameType::Table => Name::Table(NameMap { data, offset }),
NameType::Memory => Name::Memory(NameMap { data, offset }),
NameType::Global => Name::Global(NameMap { data, offset }),
NameType::Element => Name::Element(NameMap { data, offset }),
NameType::Data => Name::Data(NameMap { data, offset }),
NameType::Unknown(ty) => Name::Unknown {
ty,
data,
range: Range::new(offset, offset + payload_len),
range: offset..offset + payload_len,
},
})
}
@ -253,7 +340,7 @@ impl<'a> SectionReader for NameSectionReader<'a> {
fn original_position(&self) -> usize {
NameSectionReader::original_position(self)
}
fn range(&self) -> Range {
fn range(&self) -> Range<usize> {
self.reader.range()
}
}

View File

@ -13,290 +13,47 @@
* limitations under the License.
*/
use std::error::Error;
use std::fmt;
use std::result;
use crate::{BinaryReader, BinaryReaderError, Result, ValType};
#[derive(Debug, Clone)]
pub struct BinaryReaderError {
// Wrap the actual error data in a `Box` so that the error is just one
// word. This means that we can continue returning small `Result`s in
// registers.
pub(crate) inner: Box<BinaryReaderErrorInner>,
}
#[derive(Debug, Clone)]
pub(crate) struct BinaryReaderErrorInner {
pub(crate) message: String,
pub(crate) offset: usize,
pub(crate) needed_hint: Option<usize>,
}
pub type Result<T, E = BinaryReaderError> = result::Result<T, E>;
impl Error for BinaryReaderError {}
impl fmt::Display for BinaryReaderError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{} (at offset {})",
self.inner.message, self.inner.offset
)
}
}
impl BinaryReaderError {
pub(crate) fn new(message: impl Into<String>, offset: usize) -> Self {
let message = message.into();
BinaryReaderError {
inner: Box::new(BinaryReaderErrorInner {
message,
offset,
needed_hint: None,
}),
}
}
pub(crate) fn eof(offset: usize, needed_hint: usize) -> Self {
BinaryReaderError {
inner: Box::new(BinaryReaderErrorInner {
message: "Unexpected EOF".to_string(),
offset,
needed_hint: Some(needed_hint),
}),
}
}
/// Get this error's message.
pub fn message(&self) -> &str {
&self.inner.message
}
/// Get the offset within the Wasm binary where the error occured.
pub fn offset(&self) -> usize {
self.inner.offset
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum CustomSectionKind {
Unknown,
Name,
Producers,
SourceMappingURL,
Reloc,
Linking,
}
/// Section code as defined [here].
///
/// [here]: https://webassembly.github.io/spec/core/binary/modules.html#sections
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum SectionCode<'a> {
Custom {
name: &'a str,
kind: CustomSectionKind,
},
Type, // Function signature declarations
Alias, // Aliased indices from nested/parent modules
Import, // Import declarations
Module, // Module declarations
Instance, // Instance definitions
Function, // Function declarations
Table, // Indirect function table and other tables
Memory, // Memory attributes
Global, // Global declarations
Export, // Exports
Start, // Start function declaration
Element, // Elements section
ModuleCode, // Module definitions
Code, // Function bodies (code)
Data, // Data segments
DataCount, // Count of passive data segments
Event, // Event declarations
}
/// Types as defined [here].
///
/// [here]: https://webassembly.github.io/spec/core/syntax/types.html#types
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Type {
I32,
I64,
F32,
F64,
V128,
FuncRef,
ExternRef,
ExnRef,
Func,
EmptyBlockType,
}
/// Either a value type or a function type.
/// Represents a block type.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TypeOrFuncType {
/// A value type.
pub enum BlockType {
/// The block produces consumes nor produces any values.
Empty,
/// The block produces a singular value of the given type ([] -> \[t]).
Type(ValType),
/// The block is described by a function type.
///
/// When used as the type for a block, this type is the optional result
/// type: `[] -> [t?]`.
Type(Type),
/// A function type (referenced as an index into the types section).
/// The index is to a function type in the types section.
FuncType(u32),
}
/// External types as defined [here].
///
/// [here]: https://webassembly.github.io/spec/core/syntax/types.html#external-types
#[derive(Debug, Copy, Clone)]
pub enum ExternalKind {
Function,
Table,
Memory,
Event,
Global,
Type,
Module,
Instance,
}
#[derive(Debug, Clone)]
pub enum TypeDef<'a> {
Func(FuncType),
Instance(InstanceType<'a>),
Module(ModuleType<'a>),
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct FuncType {
pub params: Box<[Type]>,
pub returns: Box<[Type]>,
}
#[derive(Debug, Clone)]
pub struct InstanceType<'a> {
pub exports: Box<[ExportType<'a>]>,
}
#[derive(Debug, Clone)]
pub struct ModuleType<'a> {
pub imports: Box<[crate::Import<'a>]>,
pub exports: Box<[ExportType<'a>]>,
}
#[derive(Debug, Clone)]
pub struct ExportType<'a> {
pub name: &'a str,
pub ty: ImportSectionEntryType,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ResizableLimits {
pub initial: u32,
pub maximum: Option<u32>,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ResizableLimits64 {
pub initial: u64,
pub maximum: Option<u64>,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct TableType {
pub element_type: Type,
pub limits: ResizableLimits,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MemoryType {
M32 {
limits: ResizableLimits,
shared: bool,
},
M64 {
limits: ResizableLimits64,
shared: bool,
},
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct EventType {
pub type_index: u32,
}
impl MemoryType {
pub fn index_type(&self) -> Type {
match self {
MemoryType::M32 { .. } => Type::I32,
MemoryType::M64 { .. } => Type::I64,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct GlobalType {
pub content_type: Type,
pub mutable: bool,
}
#[derive(Debug, Copy, Clone)]
pub enum ImportSectionEntryType {
Function(u32),
Table(TableType),
Memory(MemoryType),
Event(EventType),
Global(GlobalType),
Module(u32),
Instance(u32),
}
/// Represents a memory immediate in a WebAssembly memory instruction.
#[derive(Debug, Copy, Clone)]
pub struct MemoryImmediate {
/// Alignment, stored as `n` where the actual alignment is `2^n`
pub align: u8,
pub offset: u32,
/// A fixed byte-offset that this memory immediate specifies.
///
/// Note that the memory64 proposal can specify a full 64-bit byte offset
/// while otherwise only 32-bit offsets are allowed. Once validated
/// memory immediates for 32-bit memories are guaranteed to be at most
/// `u32::MAX` whereas 64-bit memories can use the full 64-bits.
pub offset: u64,
/// The index of the memory this immediate points to.
///
/// Note that this points within the module's own memory index space, and
/// is always zero unless the multi-memory proposal of WebAssembly is
/// enabled.
pub memory: u32,
}
#[derive(Debug, Copy, Clone)]
pub struct Naming<'a> {
pub index: u32,
pub name: &'a str,
}
#[derive(Debug, Copy, Clone)]
pub enum NameType {
Module,
Function,
Local,
Unknown(u32),
}
#[derive(Debug, Copy, Clone)]
pub enum LinkingType {
StackPointer(u32),
}
#[derive(Debug, Copy, Clone)]
pub enum RelocType {
FunctionIndexLEB,
TableIndexSLEB,
TableIndexI32,
GlobalAddrLEB,
GlobalAddrSLEB,
GlobalAddrI32,
TypeIndexLEB,
GlobalIndexLEB,
}
/// A br_table entries representation.
#[derive(Clone)]
pub struct BrTable<'a> {
pub(crate) reader: crate::BinaryReader<'a>,
pub(crate) cnt: usize,
pub(crate) cnt: u32,
pub(crate) default: u32,
}
/// An IEEE binary32 immediate floating point value, represented as a u32
@ -307,6 +64,7 @@ pub struct BrTable<'a> {
pub struct Ieee32(pub(crate) u32);
impl Ieee32 {
/// Gets the underlying bits of the 32-bit float.
pub fn bits(self) -> u32 {
self.0
}
@ -320,41 +78,51 @@ impl Ieee32 {
pub struct Ieee64(pub(crate) u64);
impl Ieee64 {
/// Gets the underlying bits of the 64-bit float.
pub fn bits(self) -> u64 {
self.0
}
}
/// Represents a 128-bit vector value.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct V128(pub(crate) [u8; 16]);
impl V128 {
/// Gets the bytes of the vector value.
pub fn bytes(&self) -> &[u8; 16] {
&self.0
}
/// Gets a signed 128-bit integer value from the vector's bytes.
pub fn i128(&self) -> i128 {
i128::from_le_bytes(self.0)
}
}
/// Represents a SIMD lane index.
pub type SIMDLaneIndex = u8;
/// Instructions as defined [here].
///
/// [here]: https://webassembly.github.io/spec/core/binary/instructions.html
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub enum Operator<'a> {
Unreachable,
Nop,
Block {
ty: TypeOrFuncType,
ty: BlockType,
},
Loop {
ty: TypeOrFuncType,
ty: BlockType,
},
If {
ty: TypeOrFuncType,
ty: BlockType,
},
Else,
Try {
ty: TypeOrFuncType,
ty: BlockType,
},
Catch {
index: u32,
@ -365,7 +133,6 @@ pub enum Operator<'a> {
Rethrow {
relative_depth: u32,
},
Unwind,
End,
Br {
relative_depth: u32,
@ -383,6 +150,7 @@ pub enum Operator<'a> {
CallIndirect {
index: u32,
table_index: u32,
table_byte: u8,
},
ReturnCall {
function_index: u32,
@ -398,7 +166,7 @@ pub enum Operator<'a> {
Drop,
Select,
TypedSelect {
ty: Type,
ty: ValType,
},
LocalGet {
local_index: u32,
@ -505,7 +273,7 @@ pub enum Operator<'a> {
value: Ieee64,
},
RefNull {
ty: Type,
ty: ValType,
},
RefIsNull,
RefFunc {
@ -1220,4 +988,191 @@ pub enum Operator<'a> {
F64x2ConvertLowI32x4U,
F32x4DemoteF64x2Zero,
F64x2PromoteLowF32x4,
I8x16RelaxedSwizzle,
I32x4RelaxedTruncSatF32x4S,
I32x4RelaxedTruncSatF32x4U,
I32x4RelaxedTruncSatF64x2SZero,
I32x4RelaxedTruncSatF64x2UZero,
F32x4Fma,
F32x4Fms,
F64x2Fma,
F64x2Fms,
I8x16LaneSelect,
I16x8LaneSelect,
I32x4LaneSelect,
I64x2LaneSelect,
F32x4RelaxedMin,
F32x4RelaxedMax,
F64x2RelaxedMin,
F64x2RelaxedMax,
}
/// A reader for a core WebAssembly function's operators.
#[derive(Clone)]
pub struct OperatorsReader<'a> {
pub(crate) reader: BinaryReader<'a>,
}
impl<'a> OperatorsReader<'a> {
pub(crate) fn new<'b>(data: &'a [u8], offset: usize) -> OperatorsReader<'b>
where
'a: 'b,
{
OperatorsReader {
reader: BinaryReader::new_with_offset(data, offset),
}
}
/// Determines if the reader is at the end of the operators.
pub fn eof(&self) -> bool {
self.reader.eof()
}
/// Gets the original position of the reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Whether or not to allow 64-bit memory arguments in the
/// the operators being read.
///
/// This is intended to be `true` when support for the memory64
/// WebAssembly proposal is also enabled.
pub fn allow_memarg64(&mut self, allow: bool) {
self.reader.allow_memarg64(allow);
}
/// Ensures the reader is at the end.
///
/// This function returns an error if there is extra data after the operators.
pub fn ensure_end(&self) -> Result<()> {
if self.eof() {
return Ok(());
}
Err(BinaryReaderError::new(
"unexpected data at the end of operators",
self.reader.original_position(),
))
}
/// Reads an operator from the reader.
pub fn read<'b>(&mut self) -> Result<Operator<'b>>
where
'a: 'b,
{
self.reader.read_operator()
}
/// Converts to an iterator of operators paired with offsets.
pub fn into_iter_with_offsets<'b>(self) -> OperatorsIteratorWithOffsets<'b>
where
'a: 'b,
{
OperatorsIteratorWithOffsets {
reader: self,
err: false,
}
}
/// Reads an operator with its offset.
pub fn read_with_offset<'b>(&mut self) -> Result<(Operator<'b>, usize)>
where
'a: 'b,
{
let pos = self.reader.original_position();
Ok((self.read()?, pos))
}
/// Gets a binary reader from this operators reader.
pub fn get_binary_reader(&self) -> BinaryReader<'a> {
self.reader.clone()
}
}
impl<'a> IntoIterator for OperatorsReader<'a> {
type Item = Result<Operator<'a>>;
type IntoIter = OperatorsIterator<'a>;
/// Reads content of the code section.
///
/// # Examples
/// ```
/// use wasmparser::{Operator, CodeSectionReader, Result};
/// # let data: &[u8] = &[
/// # 0x01, 0x03, 0x00, 0x01, 0x0b];
/// let mut code_reader = CodeSectionReader::new(data, 0).unwrap();
/// for _ in 0..code_reader.get_count() {
/// let body = code_reader.read().expect("function body");
/// let mut op_reader = body.get_operators_reader().expect("op reader");
/// let ops = op_reader.into_iter().collect::<Result<Vec<Operator>>>().expect("ops");
/// assert!(
/// if let [Operator::Nop, Operator::End] = ops.as_slice() { true } else { false },
/// "found {:?}",
/// ops
/// );
/// }
/// ```
fn into_iter(self) -> Self::IntoIter {
OperatorsIterator {
reader: self,
err: false,
}
}
}
/// An iterator over a function's operators.
pub struct OperatorsIterator<'a> {
reader: OperatorsReader<'a>,
err: bool,
}
impl<'a> Iterator for OperatorsIterator<'a> {
type Item = Result<Operator<'a>>;
fn next(&mut self) -> Option<Self::Item> {
if self.err || self.reader.eof() {
return None;
}
let result = self.reader.read();
self.err = result.is_err();
Some(result)
}
}
/// An iterator over a function's operators with offsets.
pub struct OperatorsIteratorWithOffsets<'a> {
reader: OperatorsReader<'a>,
err: bool,
}
impl<'a> Iterator for OperatorsIteratorWithOffsets<'a> {
type Item = Result<(Operator<'a>, usize)>;
/// Reads content of the code section with offsets.
///
/// # Examples
/// ```
/// use wasmparser::{Operator, CodeSectionReader, Result};
/// # let data: &[u8] = &[
/// # 0x01, 0x03, 0x00, /* offset = 23 */ 0x01, 0x0b];
/// let mut code_reader = CodeSectionReader::new(data, 20).unwrap();
/// for _ in 0..code_reader.get_count() {
/// let body = code_reader.read().expect("function body");
/// let mut op_reader = body.get_operators_reader().expect("op reader");
/// let ops = op_reader.into_iter_with_offsets().collect::<Result<Vec<(Operator, usize)>>>().expect("ops");
/// assert!(
/// if let [(Operator::Nop, 23), (Operator::End, 24)] = ops.as_slice() { true } else { false },
/// "found {:?}",
/// ops
/// );
/// }
/// ```
fn next(&mut self) -> Option<Self::Item> {
if self.err || self.reader.eof() {
return None;
}
let result = self.reader.read_with_offset();
self.err = result.is_err();
Some(result)
}
}

View File

@ -13,26 +13,31 @@
* limitations under the License.
*/
use super::{
BinaryReader, Range, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems,
};
use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems};
use std::ops::Range;
/// Represents a field value in the producers custom section.
#[derive(Debug, Copy, Clone)]
pub struct ProducersFieldValue<'a> {
/// The field name.
pub name: &'a str,
/// The field version.
pub version: &'a str,
}
/// A reader for fields in the producers custom section.
pub struct ProducersFieldValuesReader<'a> {
reader: BinaryReader<'a>,
count: u32,
}
impl<'a> ProducersFieldValuesReader<'a> {
/// Gets the count of items in the reader.
pub fn get_count(&self) -> u32 {
self.count
}
/// Gets the original position of the reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
@ -45,6 +50,7 @@ impl<'a> ProducersFieldValuesReader<'a> {
Ok(())
}
/// Reads a field from the reader.
pub fn read<'b>(&mut self) -> Result<ProducersFieldValue<'b>>
where
'a: 'b,
@ -68,6 +74,7 @@ impl<'a> IntoIterator for ProducersFieldValuesReader<'a> {
}
}
/// An iterator over fields in the producers custom section.
pub struct ProducersFieldValuesIterator<'a> {
reader: ProducersFieldValuesReader<'a>,
left: u32,
@ -91,8 +98,10 @@ impl<'a> Iterator for ProducersFieldValuesIterator<'a> {
}
}
/// A field from the producers custom section.
#[derive(Debug, Copy, Clone)]
pub struct ProducersField<'a> {
/// The name of the field.
pub name: &'a str,
values_count: u32,
values_data: &'a [u8],
@ -100,6 +109,7 @@ pub struct ProducersField<'a> {
}
impl<'a> ProducersField<'a> {
/// Gets a reader of values for the field.
pub fn get_producer_field_values_reader<'b>(&self) -> Result<ProducersFieldValuesReader<'b>>
where
'a: 'b,
@ -111,6 +121,7 @@ impl<'a> ProducersField<'a> {
}
}
/// A reader for the producers custom section of a WebAssembly module.
pub struct ProducersSectionReader<'a> {
reader: BinaryReader<'a>,
count: u32,
@ -139,14 +150,17 @@ impl<'a> ProducersSectionReader<'a> {
Ok(ProducersSectionReader { reader, count })
}
/// Gets the original position of the reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets the count of items in the reader.
pub fn get_count(&self) -> u32 {
self.count
}
/// Reads an item from the reader.
pub fn read<'b>(&mut self) -> Result<ProducersField<'b>>
where
'a: 'b,
@ -176,7 +190,7 @@ impl<'a> SectionReader for ProducersSectionReader<'a> {
fn original_position(&self) -> usize {
ProducersSectionReader::original_position(self)
}
fn range(&self) -> Range {
fn range(&self) -> Range<usize> {
self.reader.range()
}
}

View File

@ -13,19 +13,94 @@
* limitations under the License.
*/
use super::{
BinaryReader, Range, RelocType, Result, SectionCode, SectionIteratorLimited, SectionReader,
SectionWithLimitedItems,
};
use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems};
use std::ops::Range;
/// Represents a relocation type.
#[derive(Debug, Copy, Clone)]
#[allow(missing_docs)]
pub enum RelocType {
FunctionIndexLEB,
TableIndexSLEB,
TableIndexI32,
GlobalAddrLEB,
GlobalAddrSLEB,
GlobalAddrI32,
TypeIndexLEB,
GlobalIndexLEB,
}
/// Represents known custom section kinds.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum CustomSectionKind {
/// The custom section is not known.
Unknown,
/// The name custom section.
Name,
/// The producers custom section.
Producers,
/// The source mapping URL custom section.
SourceMappingURL,
/// The reloc custom section.
Reloc,
/// The linking custom section.
Linking,
}
/// Section code as defined [here].
///
/// [here]: https://webassembly.github.io/spec/core/binary/modules.html#sections
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum SectionCode<'a> {
/// The custom section.
Custom {
/// The name of the custom section.
name: &'a str,
/// The kind of the custom section.
kind: CustomSectionKind,
},
/// The type section.
Type,
/// The import section.
Import,
/// The function section.
Function,
/// The table section.
Table,
/// The memory section.
Memory,
/// The global section.
Global,
/// The export section.
Export,
/// The start section.
Start,
/// The element section.
Element,
/// The code section.
Code,
/// The data section.
Data,
/// The passive data count section.
DataCount,
/// The tag section.
Tag,
}
/// Represents a relocation entry.
#[derive(Debug, Copy, Clone)]
pub struct Reloc {
/// The relocation type.
pub ty: RelocType,
/// The relocation offset.
pub offset: u32,
/// The relocation index.
pub index: u32,
/// The relocation addend.
pub addend: Option<u32>,
}
/// A reader for the relocations custom section of a WebAssembly module.
pub struct RelocSectionReader<'a> {
reader: BinaryReader<'a>,
section_code: SectionCode<'a>,
@ -33,11 +108,12 @@ pub struct RelocSectionReader<'a> {
}
impl<'a> RelocSectionReader<'a> {
/// Constructs a new `RelocSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<RelocSectionReader<'a>> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let section_id_position = reader.position;
let section_id = reader.read_var_u7()?;
let section_id = reader.read_u7()?;
let section_code = reader.read_section_code(section_id, section_id_position)?;
let count = reader.read_var_u32()?;
@ -48,10 +124,12 @@ impl<'a> RelocSectionReader<'a> {
})
}
/// Gets a count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
/// Gets the section code from the section.
pub fn get_section_code<'b>(&self) -> SectionCode<'b>
where
'a: 'b,
@ -59,10 +137,12 @@ impl<'a> RelocSectionReader<'a> {
self.section_code
}
/// Gets the original position of the reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Reads an item from the reader.
pub fn read(&mut self) -> Result<Reloc> {
let ty = self.reader.read_reloc_type()?;
let offset = self.reader.read_var_u32()?;
@ -97,7 +177,7 @@ impl<'a> SectionReader for RelocSectionReader<'a> {
fn original_position(&self) -> usize {
RelocSectionReader::original_position(self)
}
fn range(&self) -> Range {
fn range(&self) -> Range<usize> {
self.reader.range()
}
}

View File

@ -13,11 +13,12 @@
* limitations under the License.
*/
use super::{
BinaryReader, Range, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems,
TableType,
use crate::{
BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems, TableType,
};
use std::ops::Range;
/// A reader for the table section of a WebAssembly module.
#[derive(Clone)]
pub struct TableSectionReader<'a> {
reader: BinaryReader<'a>,
@ -25,16 +26,19 @@ pub struct TableSectionReader<'a> {
}
impl<'a> TableSectionReader<'a> {
/// Constructs a new `TableSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<TableSectionReader<'a>> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(TableSectionReader { reader, count })
}
/// Gets the original position of the section reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets the count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
@ -68,7 +72,7 @@ impl<'a> SectionReader for TableSectionReader<'a> {
fn original_position(&self) -> usize {
TableSectionReader::original_position(self)
}
fn range(&self) -> Range {
fn range(&self) -> Range<usize> {
self.reader.range()
}
}

View File

@ -13,74 +13,78 @@
* limitations under the License.
*/
use super::{
BinaryReader, EventType, Range, Result, SectionIteratorLimited, SectionReader,
SectionWithLimitedItems,
use crate::{
BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems, TagType,
};
use std::ops::Range;
/// A reader for the tags section of a WebAssembly module.
#[derive(Clone)]
pub struct EventSectionReader<'a> {
pub struct TagSectionReader<'a> {
reader: BinaryReader<'a>,
count: u32,
}
impl<'a> EventSectionReader<'a> {
pub fn new(data: &'a [u8], offset: usize) -> Result<EventSectionReader<'a>> {
impl<'a> TagSectionReader<'a> {
/// Constructs a new `TagSectionReader` for the given data and offset.
pub fn new(data: &'a [u8], offset: usize) -> Result<TagSectionReader<'a>> {
let mut reader = BinaryReader::new_with_offset(data, offset);
let count = reader.read_var_u32()?;
Ok(EventSectionReader { reader, count })
Ok(TagSectionReader { reader, count })
}
/// Gets the original position of the section reader.
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
/// Gets the count of items in the section.
pub fn get_count(&self) -> u32 {
self.count
}
/// Reads content of the event section.
/// Reads content of the tag section.
///
/// # Examples
/// ```
/// use wasmparser::EventSectionReader;
/// use wasmparser::TagSectionReader;
/// # let data: &[u8] = &[0x01, 0x00, 0x01];
/// let mut event_reader = EventSectionReader::new(data, 0).unwrap();
/// for _ in 0..event_reader.get_count() {
/// let et = event_reader.read().expect("event_type");
/// println!("Event: {:?}", et);
/// let mut reader = TagSectionReader::new(data, 0).unwrap();
/// for _ in 0..reader.get_count() {
/// let ty = reader.read().expect("tag type");
/// println!("Tag type: {:?}", ty);
/// }
/// ```
pub fn read(&mut self) -> Result<EventType> {
self.reader.read_event_type()
pub fn read(&mut self) -> Result<TagType> {
self.reader.read_tag_type()
}
}
impl<'a> SectionReader for EventSectionReader<'a> {
type Item = EventType;
impl<'a> SectionReader for TagSectionReader<'a> {
type Item = TagType;
fn read(&mut self) -> Result<Self::Item> {
EventSectionReader::read(self)
TagSectionReader::read(self)
}
fn eof(&self) -> bool {
self.reader.eof()
}
fn original_position(&self) -> usize {
EventSectionReader::original_position(self)
TagSectionReader::original_position(self)
}
fn range(&self) -> Range {
fn range(&self) -> Range<usize> {
self.reader.range()
}
}
impl<'a> SectionWithLimitedItems for EventSectionReader<'a> {
impl<'a> SectionWithLimitedItems for TagSectionReader<'a> {
fn get_count(&self) -> u32 {
EventSectionReader::get_count(self)
TagSectionReader::get_count(self)
}
}
impl<'a> IntoIterator for EventSectionReader<'a> {
type Item = Result<EventType>;
type IntoIter = SectionIteratorLimited<EventSectionReader<'a>>;
impl<'a> IntoIterator for TagSectionReader<'a> {
type Item = Result<TagType>;
type IntoIter = SectionIteratorLimited<TagSectionReader<'a>>;
fn into_iter(self) -> Self::IntoIter {
SectionIteratorLimited::new(self)

Some files were not shown because too many files have changed in this diff Show More