chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

169
vendor/wasm-encoder/src/component.rs vendored Normal file
View File

@@ -0,0 +1,169 @@
mod aliases;
mod builder;
mod canonicals;
mod components;
mod exports;
mod imports;
mod instances;
mod modules;
mod names;
mod start;
mod types;
pub use self::aliases::*;
pub use self::builder::*;
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::names::*;
pub use self::start::*;
pub use self::types::*;
use crate::{CustomSection, Encode, ProducersSection, RawCustomSection};
use alloc::vec::Vec;
// 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;
/// Appends this section to the specified destination list of bytes.
fn append_to_component(&self, dst: &mut Vec<u8>) {
dst.push(self.id());
self.encode(dst);
}
}
/// 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 type section.
CoreType = 3,
/// The section is a component section.
Component = 4,
/// The section is an instance section.
Instance = 5,
/// The section is an alias section.
Alias = 6,
/// The section is a type section.
Type = 7,
/// The section is a canonical function section.
CanonicalFunction = 8,
/// The section is a start section.
Start = 9,
/// The section is an import section.
Import = 10,
/// The section is an export section.
Export = 11,
}
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 {
/// The 8-byte header at the beginning of all components.
#[rustfmt::skip]
pub const HEADER: [u8; 8] = [
// Magic
0x00, 0x61, 0x73, 0x6D,
// Version
0x0d, 0x00, 0x01, 0x00,
];
/// Begin writing a new `Component`.
pub fn new() -> Self {
Self {
bytes: Self::HEADER.to_vec(),
}
}
/// 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
}
/// View the encoded bytes.
pub fn as_slice(&self) -> &[u8] {
&self.bytes
}
}
impl Default for Component {
fn default() -> Self {
Self::new()
}
}
impl ComponentSection for CustomSection<'_> {
fn id(&self) -> u8 {
ComponentSectionId::CoreCustom.into()
}
}
impl ComponentSection for RawCustomSection<'_> {
fn id(&self) -> u8 {
ComponentSectionId::CoreCustom.into()
}
}
impl ComponentSection for ProducersSection {
fn id(&self) -> u8 {
ComponentSectionId::CoreCustom.into()
}
}

View File

@@ -0,0 +1,161 @@
use super::{COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, CORE_TYPE_SORT, TYPE_SORT};
use crate::{
ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind, encode_section,
};
use alloc::vec::Vec;
/// 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, Alias, ComponentAliasSection, ComponentExportKind, ComponentOuterAliasKind};
///
/// let mut aliases = ComponentAliasSection::new();
/// aliases.alias(Alias::InstanceExport { instance: 0, kind: ComponentExportKind::Func, name: "f" });
/// aliases.alias(Alias::Outer { count: 0, kind: ComponentOuterAliasKind::Type, index: 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,
}
/// Different forms of aliases that can be inserted into a
/// [`ComponentAliasSection`].
#[derive(Copy, Clone, Debug)]
pub enum Alias<'a> {
/// An alias of a component instance export.
InstanceExport {
/// The index of the component instance that's being aliased from.
instance: u32,
/// The kind of item that's being extracted from the component
/// instance.
kind: ComponentExportKind,
/// The name of the export that's being aliased.
name: &'a str,
},
/// Same as `InstanceExport`, but for core instances.
#[allow(missing_docs)]
CoreInstanceExport {
instance: u32,
kind: ExportKind,
name: &'a str,
},
/// Aliasing an item from an outer component.
Outer {
/// The kind of item being aliased, either a type or a component.
kind: ComponentOuterAliasKind,
/// Number of levels "up" to go to lookup the index within. Level 0 is
/// the current scope and level 1 is the enclosing scope, and so on.
count: u32,
/// The index of the item to alias within the scope referenced by
/// `count`.
index: 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 a component instance's export.
pub fn alias(&mut self, alias: Alias<'_>) -> &mut Self {
alias.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()
}
}
impl Encode for Alias<'_> {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
Alias::InstanceExport {
instance,
kind,
name,
} => {
kind.encode(sink);
sink.push(0x00);
instance.encode(sink);
name.encode(sink);
}
Alias::CoreInstanceExport {
instance,
kind,
name,
} => {
sink.push(CORE_SORT);
kind.encode(sink);
sink.push(0x01);
instance.encode(sink);
name.encode(sink);
}
Alias::Outer { kind, count, index } => {
kind.encode(sink);
sink.push(0x02);
count.encode(sink);
index.encode(sink);
}
}
}
}

View File

@@ -0,0 +1,826 @@
use crate::component::*;
use crate::{ExportKind, Module, NameMap, RawSection, ValType};
use alloc::format;
use alloc::vec::Vec;
use core::mem;
/// Convenience type to build a component incrementally and automatically keep
/// track of index spaces.
///
/// This type is intended to be a wrapper around the [`Component`] encoding type
/// which is useful for building it up incrementally over time. This type will
/// automatically collect definitions into sections and reports the index of all
/// items added by keeping track of indices internally.
#[derive(Debug, Default)]
pub struct ComponentBuilder {
/// The binary component that's being built.
component: Component,
/// The last section which was appended to during encoding. This type is
/// generated by the `section_accessors` macro below.
///
/// When something is encoded this is used if it matches the kind of item
/// being encoded, otherwise it's "flushed" to the output component and a
/// new section is started.
last_section: LastSection,
// Core index spaces
core_modules: Namespace,
core_funcs: Namespace,
core_types: Namespace,
core_memories: Namespace,
core_tables: Namespace,
core_instances: Namespace,
core_tags: Namespace,
core_globals: Namespace,
// Component index spaces
funcs: Namespace,
instances: Namespace,
types: Namespace,
components: Namespace,
values: Namespace,
}
impl ComponentBuilder {
/// Returns the current number of core modules.
pub fn core_module_count(&self) -> u32 {
self.core_modules.count
}
/// Returns the current number of core funcs.
pub fn core_func_count(&self) -> u32 {
self.core_funcs.count
}
/// Returns the current number of core types.
pub fn core_type_count(&self) -> u32 {
self.core_types.count
}
/// Returns the current number of core memories.
pub fn core_memory_count(&self) -> u32 {
self.core_memories.count
}
/// Returns the current number of core tables.
pub fn core_table_count(&self) -> u32 {
self.core_tables.count
}
/// Returns the current number of core instances.
pub fn core_instance_count(&self) -> u32 {
self.core_instances.count
}
/// Returns the current number of core tags.
pub fn core_tag_count(&self) -> u32 {
self.core_tags.count
}
/// Returns the current number of core globals.
pub fn core_global_count(&self) -> u32 {
self.core_globals.count
}
/// Returns the current number of component funcs.
pub fn func_count(&self) -> u32 {
self.funcs.count
}
/// Returns the current number of component instances.
pub fn instance_count(&self) -> u32 {
self.instances.count
}
/// Returns the current number of component values.
pub fn value_count(&self) -> u32 {
self.values.count
}
/// Returns the current number of components.
pub fn component_count(&self) -> u32 {
self.components.count
}
/// Returns the current number of component types.
pub fn type_count(&self) -> u32 {
self.types.count
}
/// Add all debug names registered to the component.
pub fn append_names(&mut self) {
let mut names = ComponentNameSection::new();
if !self.core_funcs.names.is_empty() {
names.core_funcs(&self.core_funcs.names);
}
if !self.core_tables.names.is_empty() {
names.core_tables(&self.core_tables.names);
}
if !self.core_memories.names.is_empty() {
names.core_memories(&self.core_memories.names);
}
if !self.core_globals.names.is_empty() {
names.core_globals(&self.core_globals.names);
}
if !self.core_tags.names.is_empty() {
names.core_tags(&self.core_tags.names);
}
if !self.core_types.names.is_empty() {
names.core_types(&self.core_types.names);
}
if !self.core_modules.names.is_empty() {
names.core_modules(&self.core_modules.names);
}
if !self.core_instances.names.is_empty() {
names.core_instances(&self.core_instances.names);
}
if !self.instances.names.is_empty() {
names.instances(&self.instances.names);
}
if !self.funcs.names.is_empty() {
names.funcs(&self.funcs.names);
}
if !self.types.names.is_empty() {
names.types(&self.types.names);
}
if !self.components.names.is_empty() {
names.components(&self.components.names);
}
if !self.instances.names.is_empty() {
names.instances(&self.instances.names);
}
if !names.is_empty() {
self.custom_section(&names.as_custom());
}
}
/// Completes this component and returns the binary encoding of the entire
/// component.
pub fn finish(mut self) -> Vec<u8> {
self.flush();
self.component.finish()
}
/// Encodes a core wasm `Module` into this component, returning its index.
pub fn core_module(&mut self, debug_name: Option<&str>, module: &Module) -> u32 {
self.flush();
self.component.section(&ModuleSection(module));
self.core_modules.add(debug_name)
}
/// Encodes a core wasm `module` into this component, returning its index.
pub fn core_module_raw(&mut self, debug_name: Option<&str>, module: &[u8]) -> u32 {
self.flush();
self.component.section(&RawSection {
id: ComponentSectionId::CoreModule.into(),
data: module,
});
self.core_modules.add(debug_name)
}
/// Instantiates a core wasm module at `module_index` with the `args`
/// provided.
///
/// Returns the index of the core wasm instance created.
pub fn core_instantiate<'a, A>(
&mut self,
debug_name: Option<&str>,
module_index: u32,
args: A,
) -> u32
where
A: IntoIterator<Item = (&'a str, ModuleArg)>,
A::IntoIter: ExactSizeIterator,
{
self.instances().instantiate(module_index, args);
self.core_instances.add(debug_name)
}
/// Creates a new core wasm instance from the `exports` provided.
///
/// Returns the index of the core wasm instance created.
pub fn core_instantiate_exports<'a, E>(&mut self, debug_name: Option<&str>, exports: E) -> u32
where
E: IntoIterator<Item = (&'a str, ExportKind, u32)>,
E::IntoIter: ExactSizeIterator,
{
self.instances().export_items(exports);
self.core_instances.add(debug_name)
}
/// Creates a new aliased item where the core `instance` specified has its
/// export `name` aliased out with the `kind` specified.
///
/// Returns the index of the item created.
pub fn core_alias_export(
&mut self,
debug_name: Option<&str>,
instance: u32,
name: &str,
kind: ExportKind,
) -> u32 {
self.alias(
debug_name,
Alias::CoreInstanceExport {
instance,
kind,
name,
},
)
}
/// Adds a new alias to this component
pub fn alias(&mut self, debug_name: Option<&str>, alias: Alias<'_>) -> u32 {
self.aliases().alias(alias);
match alias {
Alias::InstanceExport { kind, .. } => self.inc_kind(debug_name, kind),
Alias::CoreInstanceExport { kind, .. } => self.inc_core_kind(debug_name, kind),
Alias::Outer {
kind: ComponentOuterAliasKind::Type,
..
} => self.types.add(debug_name),
Alias::Outer {
kind: ComponentOuterAliasKind::CoreModule,
..
} => self.core_modules.add(debug_name),
Alias::Outer {
kind: ComponentOuterAliasKind::Component,
..
} => self.components.add(debug_name),
Alias::Outer {
kind: ComponentOuterAliasKind::CoreType,
..
} => self.core_types.add(debug_name),
}
}
/// Creates an alias to a previous component instance's exported item.
///
/// The `instance` provided is the instance to access and the `name` is the
/// item to access.
///
/// Returns the index of the new item defined.
pub fn alias_export(&mut self, instance: u32, name: &str, kind: ComponentExportKind) -> u32 {
self.alias(
Some(name),
Alias::InstanceExport {
instance,
kind,
name,
},
)
}
fn inc_kind(&mut self, debug_name: Option<&str>, kind: ComponentExportKind) -> u32 {
match kind {
ComponentExportKind::Func => self.funcs.add(debug_name),
ComponentExportKind::Module => self.core_modules.add(debug_name),
ComponentExportKind::Type => self.types.add(debug_name),
ComponentExportKind::Component => self.components.add(debug_name),
ComponentExportKind::Instance => self.instances.add(debug_name),
ComponentExportKind::Value => self.values.add(debug_name),
}
}
fn inc_core_kind(&mut self, debug_name: Option<&str>, kind: ExportKind) -> u32 {
match kind {
ExportKind::Func => self.core_funcs.add(debug_name),
ExportKind::Table => self.core_tables.add(debug_name),
ExportKind::Memory => self.core_memories.add(debug_name),
ExportKind::Global => self.core_globals.add(debug_name),
ExportKind::Tag => self.core_tags.add(debug_name),
}
}
/// Lowers the `func_index` component function into a core wasm function
/// using the `options` provided.
///
/// Returns the index of the core wasm function created.
pub fn lower_func<O>(&mut self, debug_name: Option<&str>, func_index: u32, options: O) -> u32
where
O: IntoIterator<Item = CanonicalOption>,
O::IntoIter: ExactSizeIterator,
{
self.canonical_functions().lower(func_index, options);
self.core_funcs.add(debug_name)
}
/// Lifts the core wasm `core_func_index` function with the component
/// function type `type_index` and `options`.
///
/// Returns the index of the component function created.
pub fn lift_func<O>(
&mut self,
debug_name: Option<&str>,
core_func_index: u32,
type_index: u32,
options: O,
) -> u32
where
O: IntoIterator<Item = CanonicalOption>,
O::IntoIter: ExactSizeIterator,
{
self.canonical_functions()
.lift(core_func_index, type_index, options);
self.funcs.add(debug_name)
}
/// Imports a new item into this component with the `name` and `ty` specified.
pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> u32 {
let ret = match &ty {
ComponentTypeRef::Instance(_) => self.instances.add(Some(name)),
ComponentTypeRef::Func(_) => self.funcs.add(Some(name)),
ComponentTypeRef::Type(..) => self.types.add(Some(name)),
ComponentTypeRef::Component(_) => self.components.add(Some(name)),
ComponentTypeRef::Module(_) => self.core_modules.add(Some(name)),
ComponentTypeRef::Value(_) => self.values.add(Some(name)),
};
self.imports().import(name, ty);
ret
}
/// Exports a new item from this component with the `name` and `kind`
/// specified.
///
/// The `idx` is the item to export and the `ty` is an optional type to
/// ascribe to the export.
pub fn export(
&mut self,
name: &str,
kind: ComponentExportKind,
idx: u32,
ty: Option<ComponentTypeRef>,
) -> u32 {
self.exports().export(name, kind, idx, ty);
self.inc_kind(Some(name), kind)
}
/// Creates a new encoder for the next core type in this component.
pub fn core_type(&mut self, debug_name: Option<&str>) -> (u32, ComponentCoreTypeEncoder<'_>) {
(self.core_types.add(debug_name), self.core_types().ty())
}
/// Creates a new encoder for the next type in this component.
pub fn ty(&mut self, debug_name: Option<&str>) -> (u32, ComponentTypeEncoder<'_>) {
(self.types.add(debug_name), self.types().ty())
}
/// Creates a new instance type within this component.
pub fn type_instance(&mut self, debug_name: Option<&str>, ty: &InstanceType) -> u32 {
self.types().instance(ty);
self.types.add(debug_name)
}
/// Creates a new component type within this component.
pub fn type_component(&mut self, debug_name: Option<&str>, ty: &ComponentType) -> u32 {
self.types().component(ty);
self.types.add(debug_name)
}
/// Creates a new defined component type within this component.
pub fn type_defined(
&mut self,
debug_name: Option<&str>,
) -> (u32, ComponentDefinedTypeEncoder<'_>) {
(self.types.add(debug_name), self.types().defined_type())
}
/// Creates a new component function type within this component.
pub fn type_function(
&mut self,
debug_name: Option<&str>,
) -> (u32, ComponentFuncTypeEncoder<'_>) {
(self.types.add(debug_name), self.types().function())
}
/// Declares a new resource type within this component.
pub fn type_resource(
&mut self,
debug_name: Option<&str>,
rep: ValType,
dtor: Option<u32>,
) -> u32 {
self.types().resource(rep, dtor);
self.types.add(debug_name)
}
/// Defines a new subcomponent of this component.
pub fn component(&mut self, debug_name: Option<&str>, mut builder: ComponentBuilder) -> u32 {
builder.flush();
self.flush();
self.component
.section(&NestedComponentSection(&builder.component));
self.components.add(debug_name)
}
/// Defines a new subcomponent of this component.
pub fn component_raw(&mut self, debug_name: Option<&str>, data: &[u8]) -> u32 {
let raw_section = RawSection {
id: ComponentSectionId::Component.into(),
data,
};
self.flush();
self.component.section(&raw_section);
self.components.add(debug_name)
}
/// Instantiates the `component_index` specified with the `args` specified.
pub fn instantiate<A, S>(
&mut self,
debug_name: Option<&str>,
component_index: u32,
args: A,
) -> u32
where
A: IntoIterator<Item = (S, ComponentExportKind, u32)>,
A::IntoIter: ExactSizeIterator,
S: AsRef<str>,
{
self.component_instances()
.instantiate(component_index, args);
self.instances.add(debug_name)
}
/// Declares a new `resource.drop` intrinsic.
pub fn resource_drop(&mut self, ty: u32) -> u32 {
self.canonical_functions().resource_drop(ty);
self.core_funcs.add(Some("resource.drop"))
}
/// Declares a new `resource.drop` intrinsic.
pub fn resource_drop_async(&mut self, ty: u32) -> u32 {
self.canonical_functions().resource_drop_async(ty);
self.core_funcs.add(Some("resource.drop async"))
}
/// Declares a new `resource.new` intrinsic.
pub fn resource_new(&mut self, ty: u32) -> u32 {
self.canonical_functions().resource_new(ty);
self.core_funcs.add(Some("resource.new"))
}
/// Declares a new `resource.rep` intrinsic.
pub fn resource_rep(&mut self, ty: u32) -> u32 {
self.canonical_functions().resource_rep(ty);
self.core_funcs.add(Some("resource.rep"))
}
/// Declares a new `thread.spawn_ref` intrinsic.
pub fn thread_spawn_ref(&mut self, ty: u32) -> u32 {
self.canonical_functions().thread_spawn_ref(ty);
self.core_funcs.add(Some("thread.spawn-ref"))
}
/// Declares a new `thread.available_parallelism` intrinsic.
pub fn thread_available_parallelism(&mut self) -> u32 {
self.canonical_functions().thread_available_parallelism();
self.core_funcs.add(Some("thread.available-parallelism"))
}
/// Declares a new `backpressure.inc` intrinsic.
pub fn backpressure_inc(&mut self) -> u32 {
self.canonical_functions().backpressure_inc();
self.core_funcs.add(Some("backpressure.inc"))
}
/// Declares a new `backpressure.dec` intrinsic.
pub fn backpressure_dec(&mut self) -> u32 {
self.canonical_functions().backpressure_dec();
self.core_funcs.add(Some("backpressure.dec"))
}
/// Declares a new `task.return` intrinsic.
pub fn task_return<O>(&mut self, ty: Option<ComponentValType>, options: O) -> u32
where
O: IntoIterator<Item = CanonicalOption>,
O::IntoIter: ExactSizeIterator,
{
self.canonical_functions().task_return(ty, options);
self.core_funcs.add(Some("task.return"))
}
/// Declares a new `task.cancel` intrinsic.
pub fn task_cancel(&mut self) -> u32 {
self.canonical_functions().task_cancel();
self.core_funcs.add(Some("task.cancel"))
}
/// Declares a new `context.get` intrinsic.
pub fn context_get(&mut self, i: u32) -> u32 {
self.canonical_functions().context_get(i);
self.core_funcs.add(Some(&format!("context.get {i}")))
}
/// Declares a new `context.set` intrinsic.
pub fn context_set(&mut self, i: u32) -> u32 {
self.canonical_functions().context_set(i);
self.core_funcs.add(Some(&format!("context.set {i}")))
}
/// Declares a new `thread.yield` intrinsic.
pub fn thread_yield(&mut self, cancellable: bool) -> u32 {
self.canonical_functions().thread_yield(cancellable);
self.core_funcs.add(Some("thread.yield"))
}
/// Declares a new `subtask.drop` intrinsic.
pub fn subtask_drop(&mut self) -> u32 {
self.canonical_functions().subtask_drop();
self.core_funcs.add(Some("subtask.drop"))
}
/// Declares a new `subtask.cancel` intrinsic.
pub fn subtask_cancel(&mut self, async_: bool) -> u32 {
self.canonical_functions().subtask_cancel(async_);
self.core_funcs.add(Some("subtask.cancel"))
}
/// Declares a new `stream.new` intrinsic.
pub fn stream_new(&mut self, ty: u32) -> u32 {
self.canonical_functions().stream_new(ty);
self.core_funcs.add(Some("stream.new"))
}
/// Declares a new `stream.read` intrinsic.
pub fn stream_read<O>(&mut self, ty: u32, options: O) -> u32
where
O: IntoIterator<Item = CanonicalOption>,
O::IntoIter: ExactSizeIterator,
{
self.canonical_functions().stream_read(ty, options);
self.core_funcs.add(Some("stream.read"))
}
/// Declares a new `stream.write` intrinsic.
pub fn stream_write<O>(&mut self, ty: u32, options: O) -> u32
where
O: IntoIterator<Item = CanonicalOption>,
O::IntoIter: ExactSizeIterator,
{
self.canonical_functions().stream_write(ty, options);
self.core_funcs.add(Some("stream.write"))
}
/// Declares a new `stream.cancel-read` intrinsic.
pub fn stream_cancel_read(&mut self, ty: u32, async_: bool) -> u32 {
self.canonical_functions().stream_cancel_read(ty, async_);
self.core_funcs.add(Some("stream.cancel-read"))
}
/// Declares a new `stream.cancel-write` intrinsic.
pub fn stream_cancel_write(&mut self, ty: u32, async_: bool) -> u32 {
self.canonical_functions().stream_cancel_write(ty, async_);
self.core_funcs.add(Some("stream.cancel-write"))
}
/// Declares a new `stream.drop-readable` intrinsic.
pub fn stream_drop_readable(&mut self, ty: u32) -> u32 {
self.canonical_functions().stream_drop_readable(ty);
self.core_funcs.add(Some("stream.drop-readable"))
}
/// Declares a new `stream.drop-writable` intrinsic.
pub fn stream_drop_writable(&mut self, ty: u32) -> u32 {
self.canonical_functions().stream_drop_writable(ty);
self.core_funcs.add(Some("stream.drop-writable"))
}
/// Declares a new `future.new` intrinsic.
pub fn future_new(&mut self, ty: u32) -> u32 {
self.canonical_functions().future_new(ty);
self.core_funcs.add(Some("future.new"))
}
/// Declares a new `future.read` intrinsic.
pub fn future_read<O>(&mut self, ty: u32, options: O) -> u32
where
O: IntoIterator<Item = CanonicalOption>,
O::IntoIter: ExactSizeIterator,
{
self.canonical_functions().future_read(ty, options);
self.core_funcs.add(Some("future.read"))
}
/// Declares a new `future.write` intrinsic.
pub fn future_write<O>(&mut self, ty: u32, options: O) -> u32
where
O: IntoIterator<Item = CanonicalOption>,
O::IntoIter: ExactSizeIterator,
{
self.canonical_functions().future_write(ty, options);
self.core_funcs.add(Some("future.write"))
}
/// Declares a new `future.cancel-read` intrinsic.
pub fn future_cancel_read(&mut self, ty: u32, async_: bool) -> u32 {
self.canonical_functions().future_cancel_read(ty, async_);
self.core_funcs.add(Some("future.cancel-read"))
}
/// Declares a new `future.cancel-write` intrinsic.
pub fn future_cancel_write(&mut self, ty: u32, async_: bool) -> u32 {
self.canonical_functions().future_cancel_write(ty, async_);
self.core_funcs.add(Some("future.cancel-write"))
}
/// Declares a new `future.drop-readable` intrinsic.
pub fn future_drop_readable(&mut self, ty: u32) -> u32 {
self.canonical_functions().future_drop_readable(ty);
self.core_funcs.add(Some("future.drop-readable"))
}
/// Declares a new `future.drop-writable` intrinsic.
pub fn future_drop_writable(&mut self, ty: u32) -> u32 {
self.canonical_functions().future_drop_writable(ty);
self.core_funcs.add(Some("future.drop-writable"))
}
/// Declares a new `error-context.new` intrinsic.
pub fn error_context_new<O>(&mut self, options: O) -> u32
where
O: IntoIterator<Item = CanonicalOption>,
O::IntoIter: ExactSizeIterator,
{
self.canonical_functions().error_context_new(options);
self.core_funcs.add(Some("error-context.new"))
}
/// Declares a new `error-context.debug-message` intrinsic.
pub fn error_context_debug_message<O>(&mut self, options: O) -> u32
where
O: IntoIterator<Item = CanonicalOption>,
O::IntoIter: ExactSizeIterator,
{
self.canonical_functions()
.error_context_debug_message(options);
self.core_funcs.add(Some("error-context.debug-message"))
}
/// Declares a new `error-context.drop` intrinsic.
pub fn error_context_drop(&mut self) -> u32 {
self.canonical_functions().error_context_drop();
self.core_funcs.add(Some("error-context.drop"))
}
/// Declares a new `waitable-set.new` intrinsic.
pub fn waitable_set_new(&mut self) -> u32 {
self.canonical_functions().waitable_set_new();
self.core_funcs.add(Some("waitable-set.new"))
}
/// Declares a new `waitable-set.wait` intrinsic.
pub fn waitable_set_wait(&mut self, cancellable: bool, memory: u32) -> u32 {
self.canonical_functions()
.waitable_set_wait(cancellable, memory);
self.core_funcs.add(Some("waitable-set.wait"))
}
/// Declares a new `waitable-set.poll` intrinsic.
pub fn waitable_set_poll(&mut self, cancellable: bool, memory: u32) -> u32 {
self.canonical_functions()
.waitable_set_poll(cancellable, memory);
self.core_funcs.add(Some("waitable-set.poll"))
}
/// Declares a new `waitable-set.drop` intrinsic.
pub fn waitable_set_drop(&mut self) -> u32 {
self.canonical_functions().waitable_set_drop();
self.core_funcs.add(Some("waitable-set.drop"))
}
/// Declares a new `waitable.join` intrinsic.
pub fn waitable_join(&mut self) -> u32 {
self.canonical_functions().waitable_join();
self.core_funcs.add(Some("waitable.join"))
}
/// Declares a new `thread.index` intrinsic.
pub fn thread_index(&mut self) -> u32 {
self.canonical_functions().thread_index();
self.core_funcs.add(Some("thread.index"))
}
/// Declares a new `thread.new-indirect` intrinsic.
pub fn thread_new_indirect(&mut self, func_ty_idx: u32, table_index: u32) -> u32 {
self.canonical_functions()
.thread_new_indirect(func_ty_idx, table_index);
self.core_funcs.add(Some("thread.new-indirect"))
}
/// Declares a new `thread.switch-to` intrinsic.
pub fn thread_switch_to(&mut self, cancellable: bool) -> u32 {
self.canonical_functions().thread_switch_to(cancellable);
self.core_funcs.add(Some("thread.switch-to"))
}
/// Declares a new `thread.suspend` intrinsic.
pub fn thread_suspend(&mut self, cancellable: bool) -> u32 {
self.canonical_functions().thread_suspend(cancellable);
self.core_funcs.add(Some("thread.suspend"))
}
/// Declares a new `thread.resume-later` intrinsic.
pub fn thread_resume_later(&mut self) -> u32 {
self.canonical_functions().thread_resume_later();
self.core_funcs.add(Some("thread.resume-later"))
}
/// Declares a new `thread.yield-to` intrinsic.
pub fn thread_yield_to(&mut self, cancellable: bool) -> u32 {
self.canonical_functions().thread_yield_to(cancellable);
self.core_funcs.add(Some("thread.yield-to"))
}
/// Adds a new custom section to this component.
pub fn custom_section(&mut self, section: &CustomSection<'_>) {
self.flush();
self.component.section(section);
}
/// Adds a new custom section to this component.
pub fn raw_custom_section(&mut self, section: &[u8]) {
self.flush();
self.component.section(&RawCustomSection(section));
}
}
// Helper macro to generate methods on `ComponentBuilder` to get specific
// section encoders that automatically flush and write out prior sections as
// necessary.
macro_rules! section_accessors {
($($method:ident => $section:ident)*) => (
#[derive(Debug, Default)]
enum LastSection {
#[default]
None,
$($section($section),)*
}
impl ComponentBuilder {
$(
fn $method(&mut self) -> &mut $section {
match &self.last_section {
// The last encoded section matches the section that's
// being requested, so no change is necessary.
LastSection::$section(_) => {}
// Otherwise the last section didn't match this section,
// so flush any prior section if needed and start
// encoding the desired section of this method.
_ => {
self.flush();
self.last_section = LastSection::$section($section::new());
}
}
match &mut self.last_section {
LastSection::$section(ret) => ret,
_ => unreachable!()
}
}
)*
/// Writes out the last section into the final component binary if
/// there is a section specified, otherwise does nothing.
fn flush(&mut self) {
match mem::take(&mut self.last_section) {
LastSection::None => {}
$(
LastSection::$section(section) => {
self.component.section(&section);
}
)*
}
}
}
)
}
section_accessors! {
component_instances => ComponentInstanceSection
instances => InstanceSection
canonical_functions => CanonicalFunctionSection
aliases => ComponentAliasSection
exports => ComponentExportSection
imports => ComponentImportSection
types => ComponentTypeSection
core_types => CoreTypeSection
}
#[derive(Debug, Default)]
struct Namespace {
count: u32,
names: NameMap,
}
impl Namespace {
fn add(&mut self, name: Option<&str>) -> u32 {
let ret = self.count;
self.count += 1;
if let Some(name) = name {
self.names.append(ret, name);
}
ret
}
}

View File

@@ -0,0 +1,584 @@
use crate::{ComponentSection, ComponentSectionId, ComponentValType, Encode, encode_section};
use alloc::vec::Vec;
/// 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),
/// Indicates that specified function should be lifted or lowered using the `async` ABI.
Async,
/// The function to use if the async lifting of a function should receive task/stream/future progress events
/// using a callback.
Callback(u32),
/// The core function type to lower a component function into.
CoreType(u32),
/// Use the GC variant of the canonical ABI.
Gc,
}
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);
}
Self::Async => {
sink.push(0x06);
}
Self::Callback(idx) => {
sink.push(0x07);
idx.encode(sink);
}
Self::CoreType(idx) => {
sink.push(0x08);
idx.encode(sink);
}
Self::Gc => {
sink.push(0x09);
}
}
}
}
/// 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,
{
self.bytes.push(0x00);
self.bytes.push(0x00);
core_func_index.encode(&mut self.bytes);
self.encode_options(options);
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,
{
self.bytes.push(0x01);
self.bytes.push(0x00);
func_index.encode(&mut self.bytes);
self.encode_options(options);
self.num_added += 1;
self
}
/// Defines a function which will create an owned handle to the resource
/// specified by `ty_index`.
pub fn resource_new(&mut self, ty_index: u32) -> &mut Self {
self.bytes.push(0x02);
ty_index.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Defines a function which will drop the specified type of handle.
pub fn resource_drop(&mut self, ty_index: u32) -> &mut Self {
self.bytes.push(0x03);
ty_index.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Defines a function which will drop the specified type of handle.
pub fn resource_drop_async(&mut self, ty_index: u32) -> &mut Self {
self.bytes.push(0x07);
ty_index.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Defines a function which will return the representation of the specified
/// resource type.
pub fn resource_rep(&mut self, ty_index: u32) -> &mut Self {
self.bytes.push(0x04);
ty_index.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Defines a function which will spawn a new thread by invoking a shared
/// function of type `ty_index`.
pub fn thread_spawn_ref(&mut self, ty_index: u32) -> &mut Self {
self.bytes.push(0x40);
ty_index.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Defines a function which will spawn a new thread by invoking a shared
/// function indirectly through a `funcref` table.
pub fn thread_spawn_indirect(&mut self, ty_index: u32, table_index: u32) -> &mut Self {
self.bytes.push(0x41);
ty_index.encode(&mut self.bytes);
table_index.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Defines a function which will return the number of threads that can be
/// expected to execute concurrently.
pub fn thread_available_parallelism(&mut self) -> &mut Self {
self.bytes.push(0x42);
self.num_added += 1;
self
}
/// Defines a function which tells the host to increment the backpressure
/// counter.
pub fn backpressure_inc(&mut self) -> &mut Self {
self.bytes.push(0x24);
self.num_added += 1;
self
}
/// Defines a function which tells the host to decrement the backpressure
/// counter.
pub fn backpressure_dec(&mut self) -> &mut Self {
self.bytes.push(0x25);
self.num_added += 1;
self
}
/// Defines a function which returns a result to the caller of a lifted
/// export function. This allows the callee to continue executing after
/// returning a result.
pub fn task_return<O>(&mut self, ty: Option<ComponentValType>, options: O) -> &mut Self
where
O: IntoIterator<Item = CanonicalOption>,
O::IntoIter: ExactSizeIterator,
{
self.bytes.push(0x09);
crate::encode_resultlist(&mut self.bytes, ty);
self.encode_options(options);
self.num_added += 1;
self
}
/// Defines a function to acknowledge cancellation of the current task.
pub fn task_cancel(&mut self) -> &mut Self {
self.bytes.push(0x05);
self.num_added += 1;
self
}
/// Defines a new `context.get` intrinsic of the ith slot.
pub fn context_get(&mut self, i: u32) -> &mut Self {
self.bytes.push(0x0a);
self.bytes.push(0x7f);
i.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Defines a new `context.set` intrinsic of the ith slot.
pub fn context_set(&mut self, i: u32) -> &mut Self {
self.bytes.push(0x0b);
self.bytes.push(0x7f);
i.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Defines a function which yields control to the host so that other tasks
/// are able to make progress, if any.
///
/// If `cancellable` is true, the caller instance may be reentered.
pub fn thread_yield(&mut self, cancellable: bool) -> &mut Self {
self.bytes.push(0x0c);
self.bytes.push(if cancellable { 1 } else { 0 });
self.num_added += 1;
self
}
/// Defines a function to drop a specified task which has completed.
pub fn subtask_drop(&mut self) -> &mut Self {
self.bytes.push(0x0d);
self.num_added += 1;
self
}
/// Defines a function to cancel an in-progress task.
pub fn subtask_cancel(&mut self, async_: bool) -> &mut Self {
self.bytes.push(0x06);
self.bytes.push(if async_ { 1 } else { 0 });
self.num_added += 1;
self
}
/// Defines a function to create a new `stream` handle of the specified
/// type.
pub fn stream_new(&mut self, ty: u32) -> &mut Self {
self.bytes.push(0x0e);
ty.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Defines a function to read from a `stream` of the specified type.
pub fn stream_read<O>(&mut self, ty: u32, options: O) -> &mut Self
where
O: IntoIterator<Item = CanonicalOption>,
O::IntoIter: ExactSizeIterator,
{
self.bytes.push(0x0f);
ty.encode(&mut self.bytes);
self.encode_options(options);
self.num_added += 1;
self
}
/// Defines a function to write to a `stream` of the specified type.
pub fn stream_write<O>(&mut self, ty: u32, options: O) -> &mut Self
where
O: IntoIterator<Item = CanonicalOption>,
O::IntoIter: ExactSizeIterator,
{
self.bytes.push(0x10);
ty.encode(&mut self.bytes);
self.encode_options(options);
self.num_added += 1;
self
}
/// Defines a function to cancel an in-progress read from a `stream` of the
/// specified type.
pub fn stream_cancel_read(&mut self, ty: u32, async_: bool) -> &mut Self {
self.bytes.push(0x11);
ty.encode(&mut self.bytes);
self.bytes.push(if async_ { 1 } else { 0 });
self.num_added += 1;
self
}
/// Defines a function to cancel an in-progress write to a `stream` of the
/// specified type.
pub fn stream_cancel_write(&mut self, ty: u32, async_: bool) -> &mut Self {
self.bytes.push(0x12);
ty.encode(&mut self.bytes);
self.bytes.push(if async_ { 1 } else { 0 });
self.num_added += 1;
self
}
/// Defines a function to drop the readable end of a `stream` of the
/// specified type.
pub fn stream_drop_readable(&mut self, ty: u32) -> &mut Self {
self.bytes.push(0x13);
ty.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Defines a function to drop the writable end of a `stream` of the
/// specified type.
pub fn stream_drop_writable(&mut self, ty: u32) -> &mut Self {
self.bytes.push(0x14);
ty.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Defines a function to create a new `future` handle of the specified
/// type.
pub fn future_new(&mut self, ty: u32) -> &mut Self {
self.bytes.push(0x15);
ty.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Defines a function to read from a `future` of the specified type.
pub fn future_read<O>(&mut self, ty: u32, options: O) -> &mut Self
where
O: IntoIterator<Item = CanonicalOption>,
O::IntoIter: ExactSizeIterator,
{
self.bytes.push(0x16);
ty.encode(&mut self.bytes);
self.encode_options(options);
self.num_added += 1;
self
}
/// Defines a function to write to a `future` of the specified type.
pub fn future_write<O>(&mut self, ty: u32, options: O) -> &mut Self
where
O: IntoIterator<Item = CanonicalOption>,
O::IntoIter: ExactSizeIterator,
{
self.bytes.push(0x17);
ty.encode(&mut self.bytes);
self.encode_options(options);
self.num_added += 1;
self
}
/// Defines a function to cancel an in-progress read from a `future` of the
/// specified type.
pub fn future_cancel_read(&mut self, ty: u32, async_: bool) -> &mut Self {
self.bytes.push(0x18);
ty.encode(&mut self.bytes);
self.bytes.push(if async_ { 1 } else { 0 });
self.num_added += 1;
self
}
/// Defines a function to cancel an in-progress write to a `future` of the
/// specified type.
pub fn future_cancel_write(&mut self, ty: u32, async_: bool) -> &mut Self {
self.bytes.push(0x19);
ty.encode(&mut self.bytes);
self.bytes.push(if async_ { 1 } else { 0 });
self.num_added += 1;
self
}
/// Defines a function to drop the readable end of a `future` of the
/// specified type.
pub fn future_drop_readable(&mut self, ty: u32) -> &mut Self {
self.bytes.push(0x1a);
ty.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Defines a function to drop the writable end of a `future` of the
/// specified type.
pub fn future_drop_writable(&mut self, ty: u32) -> &mut Self {
self.bytes.push(0x1b);
ty.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Defines a function to create a new `error-context` with a specified
/// debug message.
pub fn error_context_new<O>(&mut self, options: O) -> &mut Self
where
O: IntoIterator<Item = CanonicalOption>,
O::IntoIter: ExactSizeIterator,
{
self.bytes.push(0x1c);
self.encode_options(options);
self.num_added += 1;
self
}
/// Defines a function to get the debug message for a specified
/// `error-context`.
///
/// Note that the debug message might not necessarily match what was passed
/// to `error-context.new`.
pub fn error_context_debug_message<O>(&mut self, options: O) -> &mut Self
where
O: IntoIterator<Item = CanonicalOption>,
O::IntoIter: ExactSizeIterator,
{
self.bytes.push(0x1d);
self.encode_options(options);
self.num_added += 1;
self
}
/// Defines a function to drop a specified `error-context`.
pub fn error_context_drop(&mut self) -> &mut Self {
self.bytes.push(0x1e);
self.num_added += 1;
self
}
/// Declare a new `waitable-set.new` intrinsic, used to create a
/// `waitable-set` pseudo-resource.
pub fn waitable_set_new(&mut self) -> &mut Self {
self.bytes.push(0x1f);
self.num_added += 1;
self
}
/// Declare a new `waitable-set.wait` intrinsic, used to block on a
/// `waitable-set`.
pub fn waitable_set_wait(&mut self, async_: bool, memory: u32) -> &mut Self {
self.bytes.push(0x20);
self.bytes.push(if async_ { 1 } else { 0 });
memory.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Declare a new `waitable-set.wait` intrinsic, used to check, without
/// blocking, if anything in a `waitable-set` is ready.
pub fn waitable_set_poll(&mut self, async_: bool, memory: u32) -> &mut Self {
self.bytes.push(0x21);
self.bytes.push(if async_ { 1 } else { 0 });
memory.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Declare a new `waitable-set.drop` intrinsic, used to dispose a
/// `waitable-set` pseudo-resource.
pub fn waitable_set_drop(&mut self) -> &mut Self {
self.bytes.push(0x22);
self.num_added += 1;
self
}
/// Declare a new `waitable.join` intrinsic, used to add an item to a
/// `waitable-set`.
pub fn waitable_join(&mut self) -> &mut Self {
self.bytes.push(0x23);
self.num_added += 1;
self
}
/// Declare a new `thread.index` intrinsic, used to get the index of the
/// current thread.
pub fn thread_index(&mut self) -> &mut Self {
self.bytes.push(0x26);
self.num_added += 1;
self
}
/// Declare a new `thread.new-indirect` intrinsic, used to create a new
/// thread by invoking a function indirectly through a `funcref` table.
pub fn thread_new_indirect(&mut self, ty_index: u32, table_index: u32) -> &mut Self {
self.bytes.push(0x27);
ty_index.encode(&mut self.bytes);
table_index.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Declare a new `thread.switch-to` intrinsic, used to switch execution to
/// another thread.
pub fn thread_switch_to(&mut self, cancellable: bool) -> &mut Self {
self.bytes.push(0x28);
self.bytes.push(if cancellable { 1 } else { 0 });
self.num_added += 1;
self
}
/// Declare a new `thread.suspend` intrinsic, used to suspend execution of
/// the current thread.
pub fn thread_suspend(&mut self, cancellable: bool) -> &mut Self {
self.bytes.push(0x29);
self.bytes.push(if cancellable { 1 } else { 0 });
self.num_added += 1;
self
}
/// Declare a new `thread.resume-later` intrinsic, used to resume execution
/// of the given thread.
pub fn thread_resume_later(&mut self) -> &mut Self {
self.bytes.push(0x2a);
self.num_added += 1;
self
}
/// Declare a new `thread.yield-to` intrinsic, used to yield execution to
/// a given thread.
pub fn thread_yield_to(&mut self, cancellable: bool) -> &mut Self {
self.bytes.push(0x2b);
self.bytes.push(if cancellable { 1 } else { 0 });
self.num_added += 1;
self
}
fn encode_options<O>(&mut self, options: O) -> &mut Self
where
O: IntoIterator<Item = CanonicalOption>,
O::IntoIter: ExactSizeIterator,
{
let options = options.into_iter();
options.len().encode(&mut self.bytes);
for option in options {
option.encode(&mut self.bytes);
}
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,30 @@
use crate::{Component, ComponentSection, ComponentSectionId, Encode};
use alloc::vec::Vec;
/// 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,130 @@
use super::{
COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, FUNCTION_SORT, INSTANCE_SORT, TYPE_SORT,
VALUE_SORT,
};
use crate::{ComponentSection, ComponentSectionId, ComponentTypeRef, Encode, encode_section};
use alloc::vec::Vec;
/// 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, None);
///
/// 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,
ty: Option<ComponentTypeRef>,
) -> &mut Self {
crate::encode_component_export_name(&mut self.bytes, name);
kind.encode(&mut self.bytes);
index.encode(&mut self.bytes);
match ty {
Some(ty) => {
self.bytes.push(0x01);
ty.encode(&mut self.bytes);
}
None => {
self.bytes.push(0x00);
}
}
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()
}
}
/// For more information on this see `encode_component_import_name`.
pub(crate) fn encode_component_export_name(bytes: &mut Vec<u8>, name: &str) {
bytes.push(0x00);
name.encode(bytes);
}

View File

@@ -0,0 +1,170 @@
use crate::{
ComponentExportKind, ComponentSection, ComponentSectionId, ComponentValType, Encode,
encode_section,
};
use alloc::vec::Vec;
/// Represents the possible type bounds for type references.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum TypeBounds {
/// The type is bounded by equality to the type index specified.
Eq(u32),
/// This type is a fresh resource type,
SubResource,
}
impl Encode for TypeBounds {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
Self::Eq(i) => {
sink.push(0x00);
i.encode(sink);
}
Self::SubResource => sink.push(0x01),
}
}
}
/// 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.
Type(TypeBounds),
/// 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) => bounds.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()
/// .params(
/// [
/// ("a", PrimitiveValType::String),
/// ("b", PrimitiveValType::String)
/// ]
/// )
/// .result(Some(PrimitiveValType::String.into()));
///
/// // 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 {
encode_component_import_name(&mut self.bytes, name);
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()
}
}
/// Prior to WebAssembly/component-model#263 import and export names were
/// discriminated with a leading byte indicating what kind of import they are.
/// After that PR though names are always prefixed with a 0x00 byte.
///
/// On 2023-10-28 in bytecodealliance/wasm-tools#1262 was landed to start
/// transitioning to "always lead with 0x00". That updated the validator/parser
/// to accept either 0x00 or 0x01 but the encoder wasn't updated at the time.
///
/// On 2024-09-03 in bytecodealliance/wasm-tools#TODO this encoder was updated
/// to always emit 0x00 as a leading byte.
///
/// This function corresponds with the `importname'` production in the
/// specification.
pub(crate) fn encode_component_import_name(bytes: &mut Vec<u8>, name: &str) {
bytes.push(0x00);
name.encode(bytes);
}

View File

@@ -0,0 +1,200 @@
use super::CORE_INSTANCE_SORT;
use crate::{
ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind, encode_section,
};
use alloc::vec::Vec;
/// 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, S>(&mut self, module_index: u32, args: A) -> &mut Self
where
A: IntoIterator<Item = (S, ModuleArg)>,
A::IntoIter: ExactSizeIterator,
S: AsRef<str>,
{
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.as_ref().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<E, S>(&mut self, exports: E) -> &mut Self
where
E: IntoIterator<Item = (S, ExportKind, u32)>,
E::IntoIter: ExactSizeIterator,
S: AsRef<str>,
{
let exports = exports.into_iter();
self.bytes.push(0x01);
exports.len().encode(&mut self.bytes);
for (name, kind, index) in exports {
name.as_ref().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, S>(&mut self, component_index: u32, args: A) -> &mut Self
where
A: IntoIterator<Item = (S, ComponentExportKind, u32)>,
A::IntoIter: ExactSizeIterator,
S: AsRef<str>,
{
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.as_ref().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 {
crate::encode_component_export_name(&mut self.bytes, name);
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,30 @@
use crate::{ComponentSection, ComponentSectionId, Encode, Module};
use alloc::vec::Vec;
/// 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,162 @@
use alloc::borrow::Cow;
use alloc::vec::Vec;
use super::*;
use crate::{ExportKind, NameMap, SectionId, encoding_size};
/// Encoding for the `component-name` custom section which assigns
/// human-readable names to items within a component.
#[derive(Clone, Debug, Default)]
pub struct ComponentNameSection {
bytes: Vec<u8>,
}
enum Subsection {
Component,
Decls,
}
impl ComponentNameSection {
/// Creates a new blank `name` custom section.
pub fn new() -> Self {
Self::default()
}
/// Appends a component name subsection to this section.
///
/// This will indicate that the name of the entire component should be the
/// `name` specified. Note that this should be encoded first before other
/// subsections.
pub fn component(&mut self, name: &str) {
let len = encoding_size(u32::try_from(name.len()).unwrap());
self.subsection_header(Subsection::Component, len + name.len());
name.encode(&mut self.bytes);
}
/// Appends a decls name subsection to name core functions within the
/// component.
pub fn core_funcs(&mut self, names: &NameMap) {
self.core_decls(ExportKind::Func as u8, names)
}
/// Appends a decls name subsection to name core tables within the
/// component.
pub fn core_tables(&mut self, names: &NameMap) {
self.core_decls(ExportKind::Table as u8, names)
}
/// Appends a decls name subsection to name core memories within the
/// component.
pub fn core_memories(&mut self, names: &NameMap) {
self.core_decls(ExportKind::Memory as u8, names)
}
/// Appends a decls name subsection to name core globals within the
/// component.
pub fn core_globals(&mut self, names: &NameMap) {
self.core_decls(ExportKind::Global as u8, names)
}
/// Appends a decls name subsection to name core tags within the
/// component.
pub fn core_tags(&mut self, names: &NameMap) {
self.core_decls(ExportKind::Tag as u8, names)
}
/// Appends a decls name subsection to name core types within the
/// component.
pub fn core_types(&mut self, names: &NameMap) {
self.core_decls(CORE_TYPE_SORT, names)
}
/// Appends a decls name subsection to name core modules within the
/// component.
pub fn core_modules(&mut self, names: &NameMap) {
self.core_decls(CORE_MODULE_SORT, names)
}
/// Appends a decls name subsection to name core instances within the
/// component.
pub fn core_instances(&mut self, names: &NameMap) {
self.core_decls(CORE_INSTANCE_SORT, names)
}
/// Appends a decls name subsection to name component functions within the
/// component.
pub fn funcs(&mut self, names: &NameMap) {
self.component_decls(FUNCTION_SORT, names)
}
/// Appends a decls name subsection to name component values within the
/// component.
pub fn values(&mut self, names: &NameMap) {
self.component_decls(VALUE_SORT, names)
}
/// Appends a decls name subsection to name component type within the
/// component.
pub fn types(&mut self, names: &NameMap) {
self.component_decls(TYPE_SORT, names)
}
/// Appends a decls name subsection to name components within the
/// component.
pub fn components(&mut self, names: &NameMap) {
self.component_decls(COMPONENT_SORT, names)
}
/// Appends a decls name subsection to name component instances within the
/// component.
pub fn instances(&mut self, names: &NameMap) {
self.component_decls(INSTANCE_SORT, names)
}
/// Appends a raw subsection with the given id and data.
pub fn raw(&mut self, id: u8, data: &[u8]) {
self.bytes.push(id);
data.encode(&mut self.bytes);
}
fn component_decls(&mut self, kind: u8, names: &NameMap) {
self.subsection_header(Subsection::Decls, 1 + names.size());
self.bytes.push(kind);
names.encode(&mut self.bytes);
}
fn core_decls(&mut self, kind: u8, names: &NameMap) {
self.subsection_header(Subsection::Decls, 2 + names.size());
self.bytes.push(CORE_SORT);
self.bytes.push(kind);
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);
}
/// Returns whether this section is empty, or nothing has been encoded.
pub fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
/// View the encoded section as a CustomSection.
pub fn as_custom<'a>(&'a self) -> CustomSection<'a> {
CustomSection {
name: "component-name".into(),
data: Cow::Borrowed(&self.bytes),
}
}
}
impl Encode for ComponentNameSection {
fn encode(&self, sink: &mut Vec<u8>) {
self.as_custom().encode(sink);
}
}
impl ComponentSection for ComponentNameSection {
fn id(&self) -> u8 {
SectionId::Custom.into()
}
}

View File

@@ -0,0 +1,53 @@
use crate::{ComponentSection, ComponentSectionId, Encode};
use alloc::vec::Vec;
/// An encoder for the start section of WebAssembly components.
///
/// # Example
///
/// ```
/// use wasm_encoder::{Component, ComponentStartSection};
///
/// let start = ComponentStartSection { function_index: 0, args: [0, 1], results: 1 };
///
/// 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,
/// The number of expected results for the start function.
///
/// This should match the number of results for the type of
/// the function referenced by `function_index`.
pub results: u32,
}
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);
self.results.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,816 @@
use super::CORE_TYPE_SORT;
use crate::{
Alias, ComponentExportKind, ComponentOuterAliasKind, ComponentSection, ComponentSectionId,
ComponentTypeRef, CoreTypeEncoder, Encode, EntityType, ValType, encode_section,
};
use alloc::vec::Vec;
/// 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 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 {
push_prefix_if_component_core_type: false,
bytes: &mut self.bytes,
}
}
/// 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);
self.bytes.push(CORE_TYPE_SORT);
self.bytes.push(0x01); // outer
count.encode(&mut self.bytes);
index.encode(&mut self.bytes);
self.num_added += 1;
self.types_added += 1;
self
}
/// 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 ComponentCoreTypeEncoder<'a>(pub(crate) &'a mut Vec<u8>);
impl<'a> ComponentCoreTypeEncoder<'a> {
/// Define a module type.
pub fn module(self, ty: &ModuleType) {
ty.encode(self.0);
}
/// Define any core type other than a module type.
#[must_use = "the encoder must be used to encode the type"]
pub fn core(self) -> CoreTypeEncoder<'a> {
CoreTypeEncoder {
bytes: self.0,
push_prefix_if_component_core_type: true,
}
}
}
/// An encoder for the core type section of WebAssembly components.
///
/// # Example
///
/// ```rust
/// use wasm_encoder::{Component, CoreTypeSection, ModuleType};
///
/// let mut types = CoreTypeSection::new();
///
/// types.ty().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) -> ComponentCoreTypeEncoder<'_> {
self.num_added += 1;
ComponentCoreTypeEncoder(&mut self.bytes)
}
}
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,
instances_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) -> ComponentCoreTypeEncoder<'_> {
self.bytes.push(0x00);
self.num_added += 1;
self.core_types_added += 1;
ComponentCoreTypeEncoder(&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 alias for an exported item of a prior instance or an
/// outer type.
pub fn alias(&mut self, alias: Alias<'_>) -> &mut Self {
self.bytes.push(0x02);
alias.encode(&mut self.bytes);
self.num_added += 1;
match &alias {
Alias::InstanceExport {
kind: ComponentExportKind::Type,
..
}
| Alias::Outer {
kind: ComponentOuterAliasKind::Type,
..
} => self.types_added += 1,
Alias::Outer {
kind: ComponentOuterAliasKind::CoreType,
..
} => self.core_types_added += 1,
Alias::InstanceExport {
kind: ComponentExportKind::Instance,
..
} => self.instances_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);
crate::encode_component_import_name(&mut self.bytes, name);
ty.encode(&mut self.bytes);
self.num_added += 1;
match ty {
ComponentTypeRef::Type(..) => self.types_added += 1,
ComponentTypeRef::Instance(..) => self.instances_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);
crate::encode_component_export_name(&mut self.bytes, name);
ty.encode(&mut self.bytes);
self.num_added += 1;
match ty {
ComponentTypeRef::Type(..) => self.types_added += 1,
ComponentTypeRef::Instance(..) => self.instances_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
}
/// Gets the number of instances that have been defined in this component
/// type through imports, exports, or aliases.
pub fn instance_count(&self) -> u32 {
self.instances_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(ComponentType);
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) -> ComponentCoreTypeEncoder<'_> {
self.0.core_type()
}
/// 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.0.ty()
}
/// Defines an outer core type alias in this component type.
pub fn alias(&mut self, alias: Alias<'_>) -> &mut Self {
self.0.alias(alias);
self
}
/// Defines an export in this instance type.
pub fn export(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self {
self.0.export(name, ty);
self
}
/// Gets the number of core types that have been added to this instance type.
pub fn core_type_count(&self) -> u32 {
self.0.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.0.types_added
}
/// Gets the number of instances that have been imported or exported or
/// aliased in this instance type.
pub fn instance_count(&self) -> u32 {
self.0.instances_added
}
/// Returns whether or not this instance type is empty.
pub fn is_empty(&self) -> bool {
self.0.num_added == 0
}
/// Returns the number of entries added to this instance types.
pub fn len(&self) -> u32 {
self.0.num_added
}
}
impl Encode for InstanceType {
fn encode(&self, sink: &mut Vec<u8>) {
sink.push(0x42);
self.0.num_added.encode(sink);
sink.extend(&self.0.bytes);
}
}
/// Used to encode component function types.
#[derive(Debug)]
pub struct ComponentFuncTypeEncoder<'a> {
async_encoded: bool,
params_encoded: bool,
results_encoded: bool,
sink: &'a mut Vec<u8>,
}
impl<'a> ComponentFuncTypeEncoder<'a> {
fn new(sink: &'a mut Vec<u8>) -> Self {
Self {
async_encoded: false,
params_encoded: false,
results_encoded: false,
sink,
}
}
/// Indicates whether this is an `async` function or not.
///
/// If this function is not invoked then the function type will not be
/// `async`.
///
/// # Panics
///
/// This method will panic if parameters or results have already been
/// encoded.
pub fn async_(&mut self, is_async: bool) -> &mut Self {
assert!(!self.params_encoded);
assert!(!self.results_encoded);
assert!(!self.async_encoded);
self.async_encoded = true;
if is_async {
self.sink.push(0x43);
} else {
self.sink.push(0x40);
}
self
}
/// Defines named parameters.
///
/// Parameters must be defined before defining results.
///
/// # Panics
///
/// This method will panic if the function is called twice since parameters
/// can only be encoded once.
pub fn params<'b, P, T>(&mut self, params: P) -> &mut Self
where
P: IntoIterator<Item = (&'b str, T)>,
P::IntoIter: ExactSizeIterator,
T: Into<ComponentValType>,
{
assert!(!self.params_encoded);
if !self.async_encoded {
self.async_(false);
}
self.params_encoded = true;
let params = params.into_iter();
params.len().encode(self.sink);
for (name, ty) in params {
name.encode(self.sink);
ty.into().encode(self.sink);
}
self
}
/// Defines a single unnamed result.
///
/// This method cannot be used with `results`.
///
/// # Panics
///
/// This method will panic if the function is called twice, called before
/// the `params` method, or called in addition to the `results` method.
pub fn result(&mut self, ty: Option<ComponentValType>) -> &mut Self {
assert!(self.async_encoded);
assert!(self.params_encoded);
assert!(!self.results_encoded);
self.results_encoded = true;
encode_resultlist(self.sink, ty);
self
}
}
pub(crate) fn encode_resultlist(sink: &mut Vec<u8>, ty: Option<ComponentValType>) {
match ty {
Some(ty) => {
sink.push(0x00);
ty.encode(sink);
}
None => {
sink.push(0x01);
sink.push(0x00);
}
}
}
/// 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(self) -> ComponentFuncTypeEncoder<'a> {
ComponentFuncTypeEncoder::new(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)
}
/// Define a resource type.
pub fn resource(self, rep: ValType, dtor: Option<u32>) {
self.0.push(0x3f);
rep.encode(self.0);
match dtor {
Some(i) => {
self.0.push(0x01);
i.encode(self.0);
}
None => self.0.push(0x00),
}
}
}
/// Represents a primitive component value type.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PrimitiveValType {
/// 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 with only one NaN.
F32,
/// The type is a 64-bit floating point number with only one NaN.
F64,
/// The type is a Unicode character.
Char,
/// The type is a string.
String,
/// Type for `error-context` added with async support in the component model.
ErrorContext,
}
impl Encode for PrimitiveValType {
fn encode(&self, sink: &mut Vec<u8>) {
sink.push(match self {
Self::Bool => 0x7f,
Self::S8 => 0x7e,
Self::U8 => 0x7d,
Self::S16 => 0x7c,
Self::U16 => 0x7b,
Self::S32 => 0x7a,
Self::U32 => 0x79,
Self::S64 => 0x78,
Self::U64 => 0x77,
Self::F32 => 0x76,
Self::F64 => 0x75,
Self::Char => 0x74,
Self::String => 0x73,
Self::ErrorContext => 0x64,
});
}
}
/// 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(0x72);
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>(self, cases: C)
where
C: IntoIterator<Item = (&'a str, Option<ComponentValType>, Option<u32>)>,
C::IntoIter: ExactSizeIterator,
{
let cases = cases.into_iter();
self.0.push(0x71);
cases.len().encode(self.0);
for (name, ty, refines) in cases {
name.encode(self.0);
ty.encode(self.0);
refines.encode(self.0);
}
}
/// Define a list type.
pub fn list(self, ty: impl Into<ComponentValType>) {
self.0.push(0x70);
ty.into().encode(self.0);
}
/// Define a map type.
pub fn map(self, key: impl Into<ComponentValType>, value: impl Into<ComponentValType>) {
self.0.push(0x63);
key.into().encode(self.0);
value.into().encode(self.0);
}
/// Define a fixed size list type.
pub fn fixed_size_list(self, ty: impl Into<ComponentValType>, elements: u32) {
self.0.push(0x67);
ty.into().encode(self.0);
elements.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(0x6F);
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(0x6E);
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(0x6D);
tags.len().encode(self.0);
for tag in tags {
tag.encode(self.0);
}
}
/// Define an option type.
pub fn option(self, ty: impl Into<ComponentValType>) {
self.0.push(0x6B);
ty.into().encode(self.0);
}
/// Define a result type.
pub fn result(self, ok: Option<ComponentValType>, err: Option<ComponentValType>) {
self.0.push(0x6A);
ok.encode(self.0);
err.encode(self.0);
}
/// Define a `own` handle type
pub fn own(self, idx: u32) {
self.0.push(0x69);
idx.encode(self.0);
}
/// Define a `borrow` handle type
pub fn borrow(self, idx: u32) {
self.0.push(0x68);
idx.encode(self.0);
}
/// Define a `future` type with the specified payload.
pub fn future(self, payload: Option<ComponentValType>) {
self.0.push(0x65);
payload.encode(self.0);
}
/// Define a `stream` type with the specified payload.
pub fn stream(self, payload: Option<ComponentValType>) {
self.0.push(0x66);
payload.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()
/// .params(
/// [
/// ("a", PrimitiveValType::String),
/// ("b", PrimitiveValType::String)
/// ]
/// )
/// .result(Some(PrimitiveValType::String.into()));
///
/// 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(&mut self) -> ComponentFuncTypeEncoder<'_> {
self.ty().function()
}
/// 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()
}
/// Defines a new resource type.
pub fn resource(&mut self, rep: ValType, dtor: Option<u32>) -> &mut Self {
self.ty().resource(rep, dtor);
self
}
}
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()
}
}

179
vendor/wasm-encoder/src/core.rs vendored Normal file
View File

@@ -0,0 +1,179 @@
mod branch_hints;
mod code;
mod custom;
mod data;
mod dump;
mod elements;
mod exports;
mod functions;
mod globals;
mod imports;
mod instructions;
mod linking;
mod memories;
mod names;
mod producers;
mod start;
mod tables;
mod tags;
mod types;
pub use branch_hints::*;
pub use code::*;
pub use custom::*;
pub use data::*;
pub use dump::*;
pub use elements::*;
pub use exports::*;
pub use functions::*;
pub use globals::*;
pub use imports::*;
pub use instructions::*;
pub use linking::*;
pub use memories::*;
pub use names::*;
pub use producers::*;
pub use start::*;
pub use tables::*;
pub use tags::*;
pub use types::*;
use crate::Encode;
use alloc::vec::Vec;
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;
pub(crate) const CORE_FUNCTION_EXACT_SORT: u8 = 0x20;
/// 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;
/// Appends this section to the specified destination list of bytes.
fn append_to(&self, dst: &mut Vec<u8>) {
dst.push(self.id());
self.encode(dst);
}
}
/// 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 {
/// The 8-byte header at the beginning of all core wasm modules.
#[rustfmt::skip]
pub const HEADER: [u8; 8] = [
// Magic
0x00, 0x61, 0x73, 0x6D,
// Version
0x01, 0x00, 0x00, 0x00,
];
/// Begin writing a new `Module`.
#[rustfmt::skip]
pub fn new() -> Self {
Module {
bytes: Self::HEADER.to_vec(),
}
}
/// 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
}
/// Give the current size of the module in bytes.
pub fn len(&self) -> usize {
self.bytes.len()
}
/// 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()
}
}

View File

@@ -0,0 +1,127 @@
use crate::{CustomSection, Encode, Section, SectionId};
use alloc::borrow::Cow;
use alloc::vec::Vec;
/// Helper structure to encode the `metadata.code.branch_hint` custom section.
///
/// This section was defined in the branch-hinting proposal for WebAssembly:
/// <https://github.com/WebAssembly/branch-hinting>.
///
/// # Example
///
/// ```
/// use wasm_encoder::*;
///
/// let mut module = Module::new();
///
/// let mut types = TypeSection::new();
/// types.ty().function([], []);
/// module.section(&types);
///
/// let mut funcs = FunctionSection::new();
/// funcs.function(0);
/// module.section(&funcs);
///
/// let mut code = CodeSection::new();
/// let mut body = Function::new([]);
///
/// body.instructions().i32_const(1);
/// let if_offset = body.byte_len();
/// body.instructions()
/// .if_(BlockType::Empty)
/// .end()
/// .end();
/// code.function(&body);
///
/// let mut hints = BranchHints::new();
/// hints.function_hints(0, [BranchHint {
/// branch_func_offset: if_offset as u32,
/// branch_hint_value: 1, // taken
/// }]);
/// module.section(&hints);
/// module.section(&code);
///
/// let wasm = module.finish();
/// let wat = wasmprinter::print_bytes(&wasm).unwrap();
/// assert_eq!(wat, r#"(module
/// (type (;0;) (func))
/// (func (;0;) (type 0)
/// i32.const 1
/// (@metadata.code.branch_hint "\01")
/// if ;; label = @1
/// end
/// )
/// )
/// "#);
///
/// ```
#[derive(Default, Debug)]
pub struct BranchHints {
bytes: Vec<u8>,
num_hints: u32,
}
/// A single branch hint within a function.
#[derive(Debug, Clone, Copy)]
pub struct BranchHint {
/// The offset, in bytes from the beginning of the function, to the `if`
/// instruction that this is hinting.
pub branch_func_offset: u32,
/// The value of the hint, 0 for not taken and 1 for taken.
pub branch_hint_value: u32,
}
impl BranchHints {
/// Construct an empty encoder for the branch hints custom section.
pub fn new() -> Self {
Self::default()
}
/// Adds a new set of function hints for the `func` specified.
pub fn function_hints<I>(&mut self, func: u32, hints: I)
where
I: IntoIterator<Item = BranchHint>,
I::IntoIter: ExactSizeIterator,
{
self.num_hints += 1;
func.encode(&mut self.bytes);
let hints = hints.into_iter();
hints.len().encode(&mut self.bytes);
for hint in hints {
hint.branch_func_offset.encode(&mut self.bytes);
1u32.encode(&mut self.bytes);
hint.branch_hint_value.encode(&mut self.bytes);
}
}
/// Returns if this is an empty section.
pub fn is_empty(&self) -> bool {
self.num_hints == 0
}
/// Returns the number of functions that have hints registered in this
/// sectino.
pub fn len(&self) -> u32 {
self.num_hints
}
}
impl Encode for BranchHints {
fn encode(&self, sink: &mut Vec<u8>) {
let mut data = Vec::new();
self.num_hints.encode(&mut data);
data.extend(&self.bytes);
CustomSection {
name: "metadata.code.branch_hint".into(),
data: Cow::Borrowed(&data),
}
.encode(sink);
}
}
impl Section for BranchHints {
fn id(&self) -> u8 {
SectionId::Custom.into()
}
}

2464
vendor/wasm-encoder/src/core/code.rs vendored Normal file

File diff suppressed because it is too large Load Diff

74
vendor/wasm-encoder/src/core/custom.rs vendored Normal file
View File

@@ -0,0 +1,74 @@
use crate::{Encode, Section, SectionId, encoding_size};
use alloc::borrow::Cow;
use alloc::vec::Vec;
/// A custom section holding arbitrary data.
#[derive(Clone, Debug, PartialEq)]
pub struct CustomSection<'a> {
/// The name of this custom section.
pub name: Cow<'a, str>,
/// This custom section's data.
pub data: Cow<'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()
}
}
/// A raw custom section where the bytes specified contain the leb-encoded
/// length of the custom section, the custom section's name, and the custom
/// section's data.
#[derive(Clone, Debug)]
pub struct RawCustomSection<'a>(pub &'a [u8]);
impl Encode for RawCustomSection<'_> {
fn encode(&self, sink: &mut Vec<u8>) {
sink.extend(self.0);
}
}
impl Section for RawCustomSection<'_> {
fn id(&self) -> u8 {
SectionId::Custom.into()
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
#[test]
fn test_custom_section() {
let custom = CustomSection {
name: "test".into(),
data: Cow::Borrowed(&[11, 22, 33, 44]),
};
let mut encoded = vec![];
custom.encode(&mut encoded);
#[rustfmt::skip]
assert_eq!(encoded, vec![
// LEB128 length of section.
9,
// LEB128 length of name.
4,
// Name.
b't', b'e', b's', b't',
// Data.
11, 22, 33, 44,
]);
}
}

187
vendor/wasm-encoder/src/core/data.rs vendored Normal file
View File

@@ -0,0 +1,187 @@
use crate::{ConstExpr, Encode, Section, SectionId, encode_section, encoding_size};
use alloc::vec::Vec;
/// An encoder for the data section.
///
/// Data sections are only supported for modules.
///
/// # Example
///
/// ```
/// use wasm_encoder::{
/// ConstExpr, DataSection, Instruction, MemorySection, MemoryType,
/// Module,
/// };
///
/// let mut memory = MemorySection::new();
/// memory.memory(MemoryType {
/// minimum: 1,
/// maximum: None,
/// memory64: false,
/// shared: false,
/// page_size_log2: None,
/// });
///
/// let mut data = DataSection::new();
/// let memory_index = 0;
/// let offset = ConstExpr::i32_const(42);
/// let segment_data = b"hello";
/// data.active(memory_index, &offset, segment_data.iter().copied());
///
/// let mut module = Module::new();
/// module
/// .section(&memory)
/// .section(&data);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Default, Debug)]
pub struct DataSection {
bytes: Vec<u8>,
num_added: u32,
}
/// A segment in the data section.
#[derive(Clone, Debug)]
pub struct DataSegment<'a, D> {
/// This data segment's mode.
pub mode: DataSegmentMode<'a>,
/// This data segment's data.
pub data: D,
}
/// A data segment's mode.
#[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: &'a ConstExpr,
},
/// A passive data segment.
///
/// Passive data segments are part of the bulk memory proposal.
Passive,
}
impl DataSection {
/// Create a new data section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of data 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 a data segment.
pub fn segment<D>(&mut self, segment: DataSegment<D>) -> &mut Self
where
D: IntoIterator<Item = u8>,
D::IntoIter: ExactSizeIterator,
{
match segment.mode {
DataSegmentMode::Passive => {
self.bytes.push(0x01);
}
DataSegmentMode::Active {
memory_index: 0,
offset,
} => {
self.bytes.push(0x00);
offset.encode(&mut self.bytes);
}
DataSegmentMode::Active {
memory_index,
offset,
} => {
self.bytes.push(0x02);
memory_index.encode(&mut self.bytes);
offset.encode(&mut self.bytes);
}
}
let data = segment.data.into_iter();
data.len().encode(&mut self.bytes);
self.bytes.extend(data);
self.num_added += 1;
self
}
/// Define an active data segment.
pub fn active<D>(&mut self, memory_index: u32, offset: &ConstExpr, data: D) -> &mut Self
where
D: IntoIterator<Item = u8>,
D::IntoIter: ExactSizeIterator,
{
self.segment(DataSegment {
mode: DataSegmentMode::Active {
memory_index,
offset,
},
data,
})
}
/// Define a passive data segment.
///
/// Passive data segments are part of the bulk memory proposal.
pub fn passive<D>(&mut self, data: D) -> &mut Self
where
D: IntoIterator<Item = u8>,
D::IntoIter: ExactSizeIterator,
{
self.segment(DataSegment {
mode: DataSegmentMode::Passive,
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()
}
}
/// An encoder for the data count section.
#[derive(Clone, Copy, Debug)]
pub struct DataCountSection {
/// The number of segments in the data section.
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()
}
}

629
vendor/wasm-encoder/src/core/dump.rs vendored Normal file
View File

@@ -0,0 +1,629 @@
use crate::{CustomSection, Encode, Ieee32, Ieee64, Section};
use alloc::borrow::Cow;
use alloc::string::String;
use alloc::vec;
use alloc::vec::Vec;
/// The "core" custom section for coredumps, as described in the
/// [tool-conventions
/// repository](https://github.com/WebAssembly/tool-conventions/blob/main/Coredump.md).
///
/// There are four sections that comprise a core dump:
/// - "core", which contains the name of the core dump
/// - "coremodules", a listing of modules
/// - "coreinstances", a listing of module instances
/// - "corestack", a listing of frames for a specific thread
///
/// # Example of how these could be constructed and encoded into a module:
///
/// ```
/// use wasm_encoder::{
/// CoreDumpInstancesSection, CoreDumpModulesSection, CoreDumpSection, CoreDumpStackSection,
/// CoreDumpValue, Module,
/// };
/// let core = CoreDumpSection::new("MyModule.wasm");
///
/// let mut modules = CoreDumpModulesSection::new();
/// modules.module("my_module");
///
/// let mut instances = CoreDumpInstancesSection::new();
/// let module_idx = 0;
/// let memories = vec![1];
/// let globals = vec![2];
/// instances.instance(module_idx, memories, globals);
///
/// let mut thread = CoreDumpStackSection::new("main");
/// let instance_index = 0;
/// let func_index = 42;
/// let code_offset = 0x1234;
/// let locals = vec![CoreDumpValue::I32(1)];
/// let stack = vec![CoreDumpValue::I32(2)];
/// thread.frame(instance_index, func_index, code_offset, locals, stack);
///
/// let mut module = Module::new();
/// module.section(&core);
/// module.section(&modules);
/// module.section(&instances);
/// module.section(&thread);
/// ```
#[derive(Clone, Debug, Default)]
pub struct CoreDumpSection {
name: String,
}
impl CoreDumpSection {
/// Create a new core dump section encoder
pub fn new(name: impl Into<String>) -> Self {
let name = name.into();
CoreDumpSection { name }
}
/// View the encoded section as a CustomSection.
fn as_custom<'a>(&'a self) -> CustomSection<'a> {
let mut data = vec![0];
self.name.encode(&mut data);
CustomSection {
name: "core".into(),
data: Cow::Owned(data),
}
}
}
impl Encode for CoreDumpSection {
fn encode(&self, sink: &mut Vec<u8>) {
self.as_custom().encode(sink);
}
}
impl Section for CoreDumpSection {
fn id(&self) -> u8 {
crate::core::SectionId::Custom as u8
}
}
/// The "coremodules" custom section for coredumps which lists the names of the
/// modules
///
/// # Example
///
/// ```
/// use wasm_encoder::{CoreDumpModulesSection, Module};
/// let mut modules_section = CoreDumpModulesSection::new();
/// modules_section.module("my_module");
/// let mut module = Module::new();
/// module.section(&modules_section);
/// ```
#[derive(Debug)]
pub struct CoreDumpModulesSection {
num_added: u32,
bytes: Vec<u8>,
}
impl CoreDumpModulesSection {
/// Create a new core dump modules section encoder.
pub fn new() -> Self {
CoreDumpModulesSection {
bytes: vec![],
num_added: 0,
}
}
/// View the encoded section as a CustomSection.
pub fn as_custom(&self) -> CustomSection<'_> {
let mut data = vec![];
self.num_added.encode(&mut data);
data.extend(self.bytes.iter().copied());
CustomSection {
name: "coremodules".into(),
data: Cow::Owned(data),
}
}
/// Encode a module name into the section's bytes.
pub fn module(&mut self, module_name: impl AsRef<str>) -> &mut Self {
self.bytes.push(0x0);
module_name.as_ref().encode(&mut self.bytes);
self.num_added += 1;
self
}
/// The number of modules that are encoded in the section.
pub fn len(&self) -> u32 {
self.num_added
}
}
impl Encode for CoreDumpModulesSection {
fn encode(&self, sink: &mut Vec<u8>) {
self.as_custom().encode(sink);
}
}
impl Section for CoreDumpModulesSection {
fn id(&self) -> u8 {
crate::core::SectionId::Custom as u8
}
}
/// The "coreinstances" section for the core dump
#[derive(Debug)]
pub struct CoreDumpInstancesSection {
num_added: u32,
bytes: Vec<u8>,
}
impl CoreDumpInstancesSection {
/// Create a new core dump instances section encoder.
pub fn new() -> Self {
CoreDumpInstancesSection {
bytes: vec![],
num_added: 0,
}
}
/// View the encoded section as a CustomSection.
pub fn as_custom(&self) -> CustomSection<'_> {
let mut data = vec![];
self.num_added.encode(&mut data);
data.extend(self.bytes.iter().copied());
CustomSection {
name: "coreinstances".into(),
data: Cow::Owned(data),
}
}
/// Encode an instance into the section's bytes.
pub fn instance<M, G>(&mut self, module_index: u32, memories: M, globals: G) -> &mut Self
where
M: IntoIterator<Item = u32>,
<M as IntoIterator>::IntoIter: ExactSizeIterator,
G: IntoIterator<Item = u32>,
<G as IntoIterator>::IntoIter: ExactSizeIterator,
{
self.bytes.push(0x0);
module_index.encode(&mut self.bytes);
crate::encode_vec(memories, &mut self.bytes);
crate::encode_vec(globals, &mut self.bytes);
self.num_added += 1;
self
}
/// The number of modules that are encoded in the section.
pub fn len(&self) -> u32 {
self.num_added
}
}
impl Encode for CoreDumpInstancesSection {
fn encode(&self, sink: &mut Vec<u8>) {
self.as_custom().encode(sink);
}
}
impl Section for CoreDumpInstancesSection {
fn id(&self) -> u8 {
crate::core::SectionId::Custom as u8
}
}
/// A "corestack" custom section as described in the [tool-conventions
/// repository](https://github.com/WebAssembly/tool-conventions/blob/main/Coredump.md)
///
/// # Example
///
/// ```
/// use wasm_encoder::{CoreDumpStackSection, Module, CoreDumpValue};
/// let mut thread = CoreDumpStackSection::new("main");
///
/// let instance_index = 0;
/// let func_index = 42;
/// let code_offset = 0x1234;
/// let locals = vec![CoreDumpValue::I32(1)];
/// let stack = vec![CoreDumpValue::I32(2)];
/// thread.frame(instance_index, func_index, code_offset, locals, stack);
///
/// let mut module = Module::new();
/// module.section(&thread);
/// ```
#[derive(Clone, Debug, Default)]
pub struct CoreDumpStackSection {
frame_bytes: Vec<u8>,
count: u32,
name: String,
}
impl CoreDumpStackSection {
/// Create a new core dump stack section encoder.
pub fn new(name: impl Into<String>) -> Self {
let name = name.into();
CoreDumpStackSection {
frame_bytes: Vec::new(),
count: 0,
name,
}
}
/// Add a stack frame to this coredump stack section.
pub fn frame<L, S>(
&mut self,
instanceidx: u32,
funcidx: u32,
codeoffset: u32,
locals: L,
stack: S,
) -> &mut Self
where
L: IntoIterator<Item = CoreDumpValue>,
<L as IntoIterator>::IntoIter: ExactSizeIterator,
S: IntoIterator<Item = CoreDumpValue>,
<S as IntoIterator>::IntoIter: ExactSizeIterator,
{
self.count += 1;
self.frame_bytes.push(0);
instanceidx.encode(&mut self.frame_bytes);
funcidx.encode(&mut self.frame_bytes);
codeoffset.encode(&mut self.frame_bytes);
crate::encode_vec(locals, &mut self.frame_bytes);
crate::encode_vec(stack, &mut self.frame_bytes);
self
}
/// View the encoded section as a CustomSection.
pub fn as_custom<'a>(&'a self) -> CustomSection<'a> {
let mut data = vec![0];
self.name.encode(&mut data);
self.count.encode(&mut data);
data.extend(&self.frame_bytes);
CustomSection {
name: "corestack".into(),
data: Cow::Owned(data),
}
}
}
impl Encode for CoreDumpStackSection {
fn encode(&self, sink: &mut Vec<u8>) {
self.as_custom().encode(sink);
}
}
impl Section for CoreDumpStackSection {
fn id(&self) -> u8 {
crate::core::SectionId::Custom as u8
}
}
/// Local and stack values are encoded using one byte for the type (similar to
/// Wasm's Number Types) followed by bytes representing the actual value
/// See the tool-conventions repo for more details.
#[derive(Clone, Debug)]
pub enum CoreDumpValue {
/// a missing value (usually missing because it was optimized out)
Missing,
/// An i32 value
I32(i32),
/// An i64 value
I64(i64),
/// An f32 value
F32(Ieee32),
/// An f64 value
F64(Ieee64),
}
impl Encode for CoreDumpValue {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
CoreDumpValue::Missing => sink.push(0x01),
CoreDumpValue::I32(x) => {
sink.push(0x7F);
x.encode(sink);
}
CoreDumpValue::I64(x) => {
sink.push(0x7E);
x.encode(sink);
}
CoreDumpValue::F32(x) => {
sink.push(0x7D);
x.encode(sink);
}
CoreDumpValue::F64(x) => {
sink.push(0x7C);
x.encode(sink);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Module;
use wasmparser::{KnownCustom, Parser, Payload};
// Create new core dump section and test whether it is properly encoded and
// parsed back out by wasmparser
#[test]
fn test_roundtrip_core() {
let core = CoreDumpSection::new("test.wasm");
let mut module = Module::new();
module.section(&core);
let wasm_bytes = module.finish();
let mut parser = Parser::new(0).parse_all(&wasm_bytes);
match parser.next() {
Some(Ok(Payload::Version { .. })) => {}
_ => panic!(""),
}
let payload = parser
.next()
.expect("parser is not empty")
.expect("element is a payload");
match payload {
Payload::CustomSection(section) => {
assert_eq!(section.name(), "core");
let core = match section.as_known() {
KnownCustom::CoreDump(s) => s,
_ => panic!("not coredump"),
};
assert_eq!(core.name, "test.wasm");
}
_ => panic!("unexpected payload"),
}
}
#[test]
fn test_roundtrip_coremodules() {
let mut coremodules = CoreDumpModulesSection::new();
coremodules.module("test_module");
let mut module = crate::Module::new();
module.section(&coremodules);
let wasm_bytes = module.finish();
let mut parser = Parser::new(0).parse_all(&wasm_bytes);
match parser.next() {
Some(Ok(Payload::Version { .. })) => {}
_ => panic!(""),
}
let payload = parser
.next()
.expect("parser is not empty")
.expect("element is a payload");
match payload {
Payload::CustomSection(section) => {
assert_eq!(section.name(), "coremodules");
let modules = match section.as_known() {
KnownCustom::CoreDumpModules(s) => s,
_ => panic!("not coremodules"),
};
assert_eq!(modules.modules[0], "test_module");
}
_ => panic!("unexpected payload"),
}
}
#[test]
fn test_roundtrip_coreinstances() {
let mut coreinstances = CoreDumpInstancesSection::new();
let module_index = 0;
let memories = vec![42];
let globals = vec![17];
coreinstances.instance(module_index, memories, globals);
let mut module = Module::new();
module.section(&coreinstances);
let wasm_bytes = module.finish();
let mut parser = Parser::new(0).parse_all(&wasm_bytes);
match parser.next() {
Some(Ok(Payload::Version { .. })) => {}
_ => panic!(""),
}
let payload = parser
.next()
.expect("parser is not empty")
.expect("element is a payload");
match payload {
Payload::CustomSection(section) => {
assert_eq!(section.name(), "coreinstances");
let coreinstances = match section.as_known() {
KnownCustom::CoreDumpInstances(s) => s,
_ => panic!("not coreinstances"),
};
assert_eq!(coreinstances.instances.len(), 1);
let instance = coreinstances
.instances
.first()
.expect("instance is encoded");
assert_eq!(instance.module_index, 0);
assert_eq!(instance.memories.len(), 1);
assert_eq!(instance.globals.len(), 1);
}
_ => panic!("unexpected payload"),
}
}
// Create new corestack section and test whether it is properly encoded and
// parsed back out by wasmparser
#[test]
fn test_roundtrip_corestack() {
let mut corestack = CoreDumpStackSection::new("main");
corestack.frame(
0,
12,
0,
vec![CoreDumpValue::I32(10)],
vec![CoreDumpValue::I32(42)],
);
let mut module = Module::new();
module.section(&corestack);
let wasm_bytes = module.finish();
let mut parser = Parser::new(0).parse_all(&wasm_bytes);
match parser.next() {
Some(Ok(Payload::Version { .. })) => {}
_ => panic!(""),
}
let payload = parser
.next()
.expect("parser is not empty")
.expect("element is a payload");
match payload {
Payload::CustomSection(section) => {
assert_eq!(section.name(), "corestack");
let corestack = match section.as_known() {
KnownCustom::CoreDumpStack(s) => s,
_ => panic!("not a corestack section"),
};
assert_eq!(corestack.name, "main");
assert_eq!(corestack.frames.len(), 1);
let frame = corestack
.frames
.first()
.expect("frame is encoded in corestack");
assert_eq!(frame.instanceidx, 0);
assert_eq!(frame.funcidx, 12);
assert_eq!(frame.codeoffset, 0);
assert_eq!(frame.locals.len(), 1);
match frame.locals.first().expect("frame contains a local") {
&wasmparser::CoreDumpValue::I32(val) => assert_eq!(val, 10),
_ => panic!("unexpected local value"),
}
assert_eq!(frame.stack.len(), 1);
match frame.stack.first().expect("stack contains a value") {
&wasmparser::CoreDumpValue::I32(val) => assert_eq!(val, 42),
_ => panic!("unexpected stack value"),
}
}
_ => panic!("unexpected payload"),
}
}
#[test]
fn test_encode_coredump_section() {
let core = CoreDumpSection::new("test");
let mut encoded = vec![];
core.encode(&mut encoded);
#[rustfmt::skip]
assert_eq!(encoded, vec![
// section length
11,
// name length
4,
// section name (core)
b'c',b'o',b'r',b'e',
// process-info (0, data length, data)
0, 4, b't', b'e', b's', b't',
]);
}
#[test]
fn test_encode_coremodules_section() {
let mut modules = CoreDumpModulesSection::new();
modules.module("mod1");
modules.module("mod2");
let mut encoded = vec![];
modules.encode(&mut encoded);
#[rustfmt::skip]
assert_eq!(encoded, vec![
// section length
25,
// name length
11,
// section name (coremodules)
b'c',b'o',b'r',b'e',b'm',b'o',b'd',b'u',b'l',b'e',b's',
// module count
2,
// 0x0, name-length, module name (mod1)
0x0, 4, b'm',b'o',b'd',b'1',
// 0x0, name-length, module name (mod2)
0x0, 4, b'm',b'o',b'd',b'2'
]);
}
#[test]
fn test_encode_coreinstances_section() {
let mut instances = CoreDumpInstancesSection::new();
instances.instance(0, vec![42], vec![17]);
let mut encoded = vec![];
instances.encode(&mut encoded);
#[rustfmt::skip]
assert_eq!(encoded, vec![
// section length
21,
// name length
13,
// section name (coreinstances)
b'c',b'o',b'r',b'e',b'i',b'n',b's',b't',b'a',b'n',b'c',b'e',b's',
// instance count
1,
// 0x0, module_idx
0x0, 0,
// memories count, memories
1, 42,
// globals count, globals
1, 17
]);
}
#[test]
fn test_encode_corestack_section() {
let mut thread = CoreDumpStackSection::new("main");
thread.frame(
0,
42,
51,
vec![CoreDumpValue::I32(1)],
vec![CoreDumpValue::I32(2)],
);
let mut encoded = vec![];
thread.encode(&mut encoded);
#[rustfmt::skip]
assert_eq!(
encoded,
vec![
// section length
27,
// length of name.
9,
// section name (corestack)
b'c',b'o',b'r',b'e',b's',b't',b'a',b'c',b'k',
// 0x0, thread name length
0, 4,
// thread name (main)
b'm',b'a',b'i',b'n',
// frame count
1,
// 0x0, instanceidx, funcidx, codeoffset
0, 0, 42, 51,
// local count
1,
// local value type
0x7F,
// local value
1,
// stack count
1,
// stack value type
0x7F,
// stack value
2
]
);
}
}

225
vendor/wasm-encoder/src/core/elements.rs vendored Normal file
View File

@@ -0,0 +1,225 @@
use crate::{ConstExpr, Encode, RefType, Section, SectionId, encode_section};
use alloc::borrow::Cow;
use alloc::vec::Vec;
/// An encoder for the element section.
///
/// Element sections are only supported for modules.
///
/// # Example
///
/// ```
/// use std::borrow::Cow;
/// use wasm_encoder::{
/// Elements, ElementSection, Module, TableSection, TableType,
/// RefType, ConstExpr
/// };
///
/// let mut tables = TableSection::new();
/// tables.table(TableType {
/// element_type: RefType::FUNCREF,
/// minimum: 128,
/// maximum: None,
/// table64: false,
/// shared: false,
/// });
///
/// let mut elements = ElementSection::new();
/// let table_index = 0;
/// let offset = ConstExpr::i32_const(42);
/// let functions = Elements::Functions(Cow::Borrowed(&[
/// // Function indices...
/// ]));
/// elements.active(Some(table_index), &offset, functions);
///
/// let mut module = Module::new();
/// module
/// .section(&tables)
/// .section(&elements);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Default, Debug)]
pub struct ElementSection {
bytes: Vec<u8>,
num_added: u32,
}
/// A sequence of elements in a segment in the element section.
#[derive(Clone, Debug)]
pub enum Elements<'a> {
/// A sequences of references to functions by their indices.
Functions(Cow<'a, [u32]>),
/// A sequence of reference expressions.
Expressions(RefType, Cow<'a, [ConstExpr]>),
}
/// An element segment's mode.
#[derive(Clone, Debug)]
pub enum ElementMode<'a> {
/// A passive element segment.
///
/// Passive segments are part of the bulk memory proposal.
Passive,
/// A declared element segment.
///
/// Declared segments are part of the bulk memory proposal.
Declared,
/// An active element segment.
Active {
/// The table index.
///
/// `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: &'a ConstExpr,
},
}
/// An element segment in the element section.
#[derive(Clone, Debug)]
pub struct ElementSegment<'a> {
/// The element segment's mode.
pub mode: ElementMode<'a>,
/// This segment's elements.
pub elements: Elements<'a>,
}
impl ElementSection {
/// Create a new element section encoder.
pub fn new() -> Self {
Self::default()
}
/// 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(..) => 0b100u32,
Elements::Functions(_) => 0b000u32,
};
let mut encode_type = false;
match &segment.mode {
ElementMode::Passive => {
(0x01 | expr_bit).encode(&mut self.bytes);
encode_type = true;
}
ElementMode::Active { table, offset } => {
match (table, &segment.elements) {
// If the `table` is not specified then the 0x00 encoding
// can be used with either function indices or expressions
// that have a `funcref` type.
(None, Elements::Functions(_) | Elements::Expressions(RefType::FUNCREF, _)) => {
(/* 0x00 | */expr_bit).encode(&mut self.bytes);
}
// ... otherwise fall through for all other expressions here
// with table 0 or an explicitly specified table to the 0x02
// encoding.
(None, Elements::Expressions(..)) | (Some(_), _) => {
(0x02 | expr_bit).encode(&mut self.bytes);
table.unwrap_or(0).encode(&mut self.bytes);
encode_type = true;
}
}
offset.encode(&mut self.bytes);
}
ElementMode::Declared => {
(0x03 | expr_bit).encode(&mut self.bytes);
encode_type = true;
}
}
match segment.elements {
Elements::Functions(fs) => {
if encode_type {
// elemkind == funcref
self.bytes.push(0x00);
}
fs.encode(&mut self.bytes);
}
Elements::Expressions(ty, e) => {
if encode_type {
ty.encode(&mut self.bytes);
}
e.len().encode(&mut self.bytes);
for expr in e.iter() {
expr.encode(&mut self.bytes);
}
}
}
self.num_added += 1;
self
}
/// Define an active element segment.
///
/// `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: &ConstExpr,
elements: Elements<'_>,
) -> &mut Self {
self.segment(ElementSegment {
mode: ElementMode::Active {
table: table_index,
offset,
},
elements,
})
}
/// Encode a passive element segment.
///
/// Passive segments are part of the bulk memory proposal.
pub fn passive<'a>(&mut self, elements: Elements<'a>) -> &mut Self {
self.segment(ElementSegment {
mode: ElementMode::Passive,
elements,
})
}
/// Encode a declared element segment.
///
/// Declared segments are part of the bulk memory proposal.
pub fn declared<'a>(&mut self, elements: Elements<'a>) -> &mut Self {
self.segment(ElementSegment {
mode: ElementMode::Declared,
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()
}
}

86
vendor/wasm-encoder/src/core/exports.rs vendored Normal file
View File

@@ -0,0 +1,86 @@
use super::{
CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_MEMORY_SORT, CORE_TABLE_SORT, CORE_TAG_SORT,
};
use crate::{Encode, Section, SectionId, encode_section};
use alloc::vec::Vec;
/// Represents the kind of an export from a WebAssembly module.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
#[repr(u8)]
pub enum ExportKind {
/// The export is a function.
Func = CORE_FUNCTION_SORT,
/// The export is a table.
Table = CORE_TABLE_SORT,
/// The export is a memory.
Memory = CORE_MEMORY_SORT,
/// The export is a global.
Global = CORE_GLOBAL_SORT,
/// The export is a tag.
Tag = CORE_TAG_SORT,
}
impl Encode for ExportKind {
fn encode(&self, sink: &mut Vec<u8>) {
sink.push(*self as u8);
}
}
/// 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

@@ -0,0 +1,64 @@
use crate::{Encode, Section, SectionId, encode_section};
use alloc::vec::Vec;
/// An encoder for the function section of WebAssembly modules.
///
/// # Example
///
/// ```
/// use wasm_encoder::{Module, FunctionSection, ValType};
///
/// let mut functions = FunctionSection::new();
/// let type_index = 0;
/// functions.function(type_index);
///
/// let mut module = Module::new();
/// module.section(&functions);
///
/// // Note: this will generate an invalid module because we didn't generate a
/// // code section containing the function body. See the documentation for
/// // `CodeSection` for details.
///
/// let bytes = module.finish();
/// ```
#[derive(Clone, Debug, Default)]
pub struct FunctionSection {
bytes: Vec<u8>,
num_added: u32,
}
impl FunctionSection {
/// Construct a new module 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 in a module's function section.
pub fn function(&mut self, type_index: u32) -> &mut Self {
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()
}
}

101
vendor/wasm-encoder/src/core/globals.rs vendored Normal file
View File

@@ -0,0 +1,101 @@
use crate::{ConstExpr, Encode, Section, SectionId, ValType, encode_section};
use alloc::vec::Vec;
/// An encoder for the global section.
///
/// Global sections are only supported for modules.
///
/// # Example
///
/// ```
/// use wasm_encoder::{ConstExpr, Module, GlobalSection, GlobalType, Instruction, ValType};
///
/// let mut globals = GlobalSection::new();
/// globals.global(
/// GlobalType {
/// val_type: ValType::I32,
/// mutable: false,
/// shared: false,
/// },
/// &ConstExpr::i32_const(42),
/// );
///
/// let mut module = Module::new();
/// module.section(&globals);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Default, Debug)]
pub struct GlobalSection {
bytes: Vec<u8>,
num_added: u32,
}
impl GlobalSection {
/// Create a new global section encoder.
pub fn new() -> Self {
Self::default()
}
/// 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: &ConstExpr) -> &mut Self {
global_type.encode(&mut self.bytes);
init_expr.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()
}
}
/// A global's type.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct GlobalType {
/// This global's value type.
pub val_type: ValType,
/// Whether this global is mutable or not.
pub mutable: bool,
/// Whether this global is shared or not.
pub shared: bool,
}
impl Encode for GlobalType {
fn encode(&self, sink: &mut Vec<u8>) {
self.val_type.encode(sink);
let mut flag = 0;
if self.mutable {
flag |= 0b01;
}
if self.shared {
flag |= 0b10;
}
sink.push(flag);
}
}

230
vendor/wasm-encoder/src/core/imports.rs vendored Normal file
View File

@@ -0,0 +1,230 @@
use crate::{
CORE_FUNCTION_EXACT_SORT, CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_MEMORY_SORT,
CORE_TABLE_SORT, CORE_TAG_SORT, Encode, GlobalType, MemoryType, Section, SectionId, TableType,
TagType, encode_section,
};
use alloc::borrow::Cow;
use alloc::vec::Vec;
/// 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),
/// A function exact type.
///
/// The value is an index into the types section.
FunctionExact(u32),
}
impl Encode for EntityType {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
Self::Function(f) => {
sink.push(CORE_FUNCTION_SORT);
f.encode(sink);
}
Self::FunctionExact(f) => {
sink.push(CORE_FUNCTION_EXACT_SORT);
f.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 import item to be used with [`Imports::Single`].
#[derive(Clone, Debug)]
pub struct Import<'a> {
/// The import's module name.
pub module: &'a str,
/// The import's item name.
pub name: &'a str,
/// The import's time.
pub ty: EntityType,
}
/// An import item to be used with [`Imports::Compact1`].
#[derive(Clone, Debug)]
pub struct ImportCompact<'a> {
/// The import's item name.
pub name: &'a str,
/// The import's type.
pub ty: EntityType,
}
/// A single entry in the import section of a WebAssembly module, possibly containing multiple imports.
#[derive(Clone, Debug)]
pub enum Imports<'a> {
/// A single import item.
Single(Import<'a>),
/// A group of imports with a common module name.
Compact1 {
/// The common module name.
module: &'a str,
/// The individual import items (name/type).
items: Cow<'a, [ImportCompact<'a>]>,
},
/// A group of imports with a common module name and type.
Compact2 {
/// The common module name.
module: &'a str,
/// The common import type.
ty: EntityType,
/// The individual import item names.
names: Cow<'a, [&'a str]>,
},
}
/// 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,
/// page_size_log2: None,
/// }
/// );
///
/// 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 imports in the import section.
pub fn imports<'a>(&mut self, imports: Imports<'a>) -> &mut Self {
match imports {
Imports::Single(import) => {
import.module.encode(&mut self.bytes);
import.name.encode(&mut self.bytes);
import.ty.encode(&mut self.bytes);
}
Imports::Compact1 { module, items } => {
module.encode(&mut self.bytes);
self.bytes.push(0x00); // empty name
self.bytes.push(0x7F);
items.len().encode(&mut self.bytes);
for item in items.iter() {
item.name.encode(&mut self.bytes);
item.ty.encode(&mut self.bytes);
}
}
Imports::Compact2 { module, ty, names } => {
module.encode(&mut self.bytes);
self.bytes.push(0x00); // empty name
self.bytes.push(0x7E);
ty.encode(&mut self.bytes);
names.len().encode(&mut self.bytes);
for item in names.iter() {
item.encode(&mut self.bytes);
}
}
}
self.num_added += 1;
self
}
/// Define an import in the import section.
pub fn import(&mut self, module: &str, name: &str, ty: impl Into<EntityType>) -> &mut Self {
self.imports(Imports::Single(Import {
module,
name,
ty: ty.into(),
}))
}
}
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()
}
}

File diff suppressed because it is too large Load Diff

264
vendor/wasm-encoder/src/core/linking.rs vendored Normal file
View File

@@ -0,0 +1,264 @@
use crate::{CustomSection, Encode, Section, SectionId, encode_section};
use alloc::borrow::Cow;
use alloc::vec;
use alloc::vec::Vec;
const VERSION: u32 = 2;
/// An encoder for the [linking custom
/// section](https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md#linking-metadata-section).
///
/// This section is a non-standard convention that is supported by the LLVM
/// toolchain. It, along with associated "reloc.*" custom sections, allows you
/// to treat a Wasm module as a low-level object file that can be linked with
/// other Wasm object files to produce a final, complete Wasm module.
///
/// The linking section must come before the reloc sections.
///
/// # Example
///
/// ```
/// use wasm_encoder::{LinkingSection, Module, SymbolTable};
///
/// // Create a new linking section.
/// let mut linking = LinkingSection::new();
///
/// // Define a symbol table.
/// let mut sym_tab = SymbolTable::new();
///
/// // Define a function symbol in the symbol table.
/// let flags = SymbolTable::WASM_SYM_BINDING_LOCAL | SymbolTable::WASM_SYM_EXPORTED;
/// let func_index = 42;
/// let sym_name = "my_exported_func";
/// sym_tab.function(flags, func_index, Some(sym_name));
///
/// // Add the symbol table to our linking section.
/// linking.symbol_table(&sym_tab);
///
/// // Add the linking section to a new Wasm module and get the encoded bytes.
/// let mut module = Module::new();
/// module.section(&linking);
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Debug)]
pub struct LinkingSection {
bytes: Vec<u8>,
}
impl LinkingSection {
/// Construct a new encoder for the linking custom section.
pub fn new() -> Self {
Self::default()
}
// TODO: `fn segment_info` for the `WASM_SEGMENT_INFO` linking subsection.
// TODO: `fn init_funcs` for the `WASM_INIT_FUNCS` linking subsection.
// TODO: `fn comdat_info` for the `WASM_COMDAT_INFO` linking subsection.
/// Add a symbol table subsection.
pub fn symbol_table(&mut self, symbol_table: &SymbolTable) -> &mut Self {
symbol_table.encode(&mut self.bytes);
self
}
}
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".into(),
data: Cow::Borrowed(&self.bytes),
}
.encode(sink);
}
}
impl Section for LinkingSection {
fn id(&self) -> u8 {
SectionId::Custom.into()
}
}
#[allow(unused)]
const WASM_SEGMENT_INFO: u8 = 5;
#[allow(unused)]
const WASM_INIT_FUNCS: u8 = 6;
#[allow(unused)]
const WASM_COMDAT_INFO: u8 = 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, Default)]
pub struct SymbolTable {
bytes: Vec<u8>,
num_added: u32,
}
const SYMTAB_FUNCTION: u32 = 0;
const SYMTAB_DATA: u32 = 1;
const SYMTAB_GLOBAL: u32 = 2;
#[allow(unused)]
const SYMTAB_SECTION: u32 = 3;
#[allow(unused)]
const SYMTAB_TAG: u32 = 4;
const SYMTAB_TABLE: u32 = 5;
impl SymbolTable {
/// Construct a new symbol table subsection encoder.
pub fn new() -> Self {
SymbolTable {
bytes: vec![],
num_added: 0,
}
}
/// Define a function symbol in this symbol table.
///
/// 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 {
SYMTAB_FUNCTION.encode(&mut self.bytes);
flags.encode(&mut self.bytes);
index.encode(&mut self.bytes);
if let Some(name) = name {
name.encode(&mut self.bytes);
}
self.num_added += 1;
self
}
/// Define a global symbol in this symbol table.
///
/// 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 {
SYMTAB_GLOBAL.encode(&mut self.bytes);
flags.encode(&mut self.bytes);
index.encode(&mut self.bytes);
if let Some(name) = name {
name.encode(&mut self.bytes);
}
self.num_added += 1;
self
}
// TODO: tags
/// Define a table symbol in this symbol table.
///
/// 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 {
SYMTAB_TABLE.encode(&mut self.bytes);
flags.encode(&mut self.bytes);
index.encode(&mut self.bytes);
if let Some(name) = name {
name.encode(&mut self.bytes);
}
self.num_added += 1;
self
}
/// Add a data symbol to this symbol table.
pub fn data(
&mut self,
flags: u32,
name: &str,
definition: Option<DataSymbolDefinition>,
) -> &mut Self {
SYMTAB_DATA.encode(&mut self.bytes);
flags.encode(&mut self.bytes);
name.encode(&mut self.bytes);
if let Some(def) = definition {
def.index.encode(&mut self.bytes);
def.offset.encode(&mut self.bytes);
def.size.encode(&mut self.bytes);
}
self.num_added += 1;
self
}
// TODO: sections
/// This is a weak symbol.
///
/// This flag is mutually exclusive with `WASM_SYM_BINDING_LOCAL`.
///
/// When linking multiple modules defining the same symbol, all weak
/// definitions are discarded if any strong definitions exist; then if
/// multiple weak definitions exist all but one (unspecified) are discarded;
/// and finally it is an error if more than one definition remains.
pub const WASM_SYM_BINDING_WEAK: u32 = 0x1;
/// This is a local symbol.
///
/// This flag is mutually exclusive with `WASM_SYM_BINDING_WEAK`.
///
/// Local symbols are not to be exported, or linked to other
/// modules/sections. The names of all non-local symbols must be unique, but
/// the names of local symbols are not considered for uniqueness. A local
/// function or global symbol cannot reference an import.
pub const WASM_SYM_BINDING_LOCAL: u32 = 0x02;
/// This is a hidden symbol.
///
/// Hidden symbols are not to be exported when performing the final link,
/// but may be linked to other modules.
pub const WASM_SYM_VISIBILITY_HIDDEN: u32 = 0x04;
/// This symbol is not defined.
///
/// For non-data symbols, this must match whether the symbol is an import or
/// is defined; for data symbols, determines whether a segment is specified.
pub const WASM_SYM_UNDEFINED: u32 = 0x10;
/// This symbol is intended to be exported from the wasm module to the host
/// environment.
///
/// This differs from the visibility flags in that it effects the static
/// linker.
pub const WASM_SYM_EXPORTED: u32 = 0x20;
/// This symbol uses an explicit symbol name, rather than reusing the name
/// from a wasm import.
///
/// This allows it to remap imports from foreign WebAssembly modules into
/// local symbols with different names.
pub const WASM_SYM_EXPLICIT_NAME: u32 = 0x40;
/// This symbol is intended to be included in the linker output, regardless
/// of whether it is used by the program.
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 {
/// The index of the data segment that this symbol is in.
pub index: u32,
/// The offset of this symbol within its segment.
pub offset: u32,
/// The byte size (which can be zero) of this data symbol.
///
/// Note that `offset + size` must be less than or equal to the segment's
/// size.
pub size: u32,
}

116
vendor/wasm-encoder/src/core/memories.rs vendored Normal file
View File

@@ -0,0 +1,116 @@
use crate::{Encode, Section, SectionId, encode_section};
use alloc::vec::Vec;
/// An encoder for the memory section.
///
/// Memory sections are only supported for modules.
///
/// # Example
///
/// ```
/// use wasm_encoder::{Module, MemorySection, MemoryType};
///
/// let mut memories = MemorySection::new();
/// memories.memory(MemoryType {
/// minimum: 1,
/// maximum: None,
/// memory64: false,
/// shared: false,
/// page_size_log2: None,
/// });
///
/// let mut module = Module::new();
/// module.section(&memories);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Default, Debug)]
pub struct MemorySection {
bytes: Vec<u8>,
num_added: u32,
}
impl MemorySection {
/// Create a new memory section encoder.
pub fn new() -> Self {
Self::default()
}
/// 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);
self.num_added += 1;
self
}
}
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()
}
}
/// A memory's type.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct MemoryType {
/// Minimum size, in pages, of this memory
pub minimum: u64,
/// Maximum size, in pages, of this memory
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,
/// The log base 2 of a custom page size for this memory.
///
/// The default page size for Wasm memories is 64KiB, i.e. 2<sup>16</sup> or
/// `65536`.
///
/// After the introduction of [the custom-page-sizes
/// proposal](https://github.com/WebAssembly/custom-page-sizes), Wasm can
/// customize the page size. It must be a power of two that is less than or
/// equal to 64KiB. Attempting to encode an invalid page size may panic.
pub page_size_log2: Option<u32>,
}
impl Encode for MemoryType {
fn encode(&self, sink: &mut Vec<u8>) {
let mut flags = 0;
if self.maximum.is_some() {
flags |= 0b0001;
}
if self.shared {
flags |= 0b0010;
}
if self.memory64 {
flags |= 0b0100;
}
if self.page_size_log2.is_some() {
flags |= 0b1000;
}
sink.push(flags);
self.minimum.encode(sink);
if let Some(max) = self.maximum {
max.encode(sink);
}
if let Some(p) = self.page_size_log2 {
p.encode(sink);
}
}
}

305
vendor/wasm-encoder/src/core/names.rs vendored Normal file
View File

@@ -0,0 +1,305 @@
use crate::{CustomSection, Encode, Section, SectionId, encoding_size};
use alloc::borrow::Cow;
use alloc::vec;
use alloc::vec::Vec;
/// 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,
// https://github.com/WebAssembly/gc/issues/193
Field = 10,
// https://github.com/WebAssembly/exception-handling/pull/213
Tag = 11,
}
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 this
/// 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 this
/// 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)
/// and before the field subsection (if present).
pub fn data(&mut self, names: &NameMap) {
self.subsection_header(Subsection::Data, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of all tags in this wasm module.
///
/// This section should come after the data name subsection (if present).
pub fn tag(&mut self, names: &NameMap) {
self.subsection_header(Subsection::Tag, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of fields within types in this
/// wasm module.
///
/// This section should come after the data name subsection (if present)
/// and before the tag subsection (if present).
pub fn fields(&mut self, names: &IndirectNameMap) {
self.subsection_header(Subsection::Field, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of all tags in this wasm module.
///
/// This section should come after the field name subsection (if present).
pub fn tags(&mut self, names: &NameMap) {
self.subsection_header(Subsection::Tag, names.size());
names.encode(&mut self.bytes);
}
/// Appends a raw subsection with the given id and data.
pub fn raw(&mut self, id: u8, data: &[u8]) {
self.bytes.push(id);
data.encode(&mut self.bytes);
}
fn subsection_header(&mut self, id: Subsection, len: usize) {
self.bytes.push(id as u8);
len.encode(&mut self.bytes);
}
/// View the encoded section as a CustomSection.
pub fn as_custom<'a>(&'a self) -> CustomSection<'a> {
CustomSection {
name: "name".into(),
data: Cow::Borrowed(&self.bytes),
}
}
}
impl Encode for NameSection {
fn encode(&self, sink: &mut Vec<u8>) {
self.as_custom().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;
}
pub(crate) fn size(&self) -> usize {
encoding_size(self.count) + self.bytes.len()
}
/// Returns whether no names have been added to this map.
pub fn is_empty(&self) -> bool {
self.count == 0
}
}
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

@@ -0,0 +1,181 @@
use crate::{CustomSection, Encode, Section, SectionId};
use alloc::borrow::Cow;
use alloc::vec::Vec;
/// An encoder for the [producers custom
/// section](https://github.com/WebAssembly/tool-conventions/blob/main/ProducersSection.md).
///
/// This section is a non-standard convention that is supported by many toolchains.
///
/// # Example
///
/// ```
/// use wasm_encoder::{ProducersSection, ProducersField, Module};
///
/// // Create a new producers section.
/// let mut field = ProducersField::new();
/// field.value("clang", "14.0.4");
/// field.value("rustc", "1.66.1 (90743e729 2023-01-10)");
/// let mut producers = ProducersSection::new();
/// producers.field("processed-by", &field);
///
/// // Add the producers section to a new Wasm module and get the encoded bytes.
/// let mut module = Module::new();
/// module.section(&producers);
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Debug)]
pub struct ProducersSection {
bytes: Vec<u8>,
num_fields: u32,
}
impl ProducersSection {
/// Construct an empty encoder for the producers custom section.
pub fn new() -> Self {
Self::default()
}
/// Add a field to the section. The spec recommends names for this section
/// are "language", "processed-by", and "sdk". Each field in section must
/// have a unique name.
pub fn field(&mut self, name: &str, values: &ProducersField) -> &mut Self {
name.encode(&mut self.bytes);
values.encode(&mut self.bytes);
self.num_fields += 1;
self
}
}
impl Default for ProducersSection {
fn default() -> Self {
Self {
bytes: Vec::new(),
num_fields: 0,
}
}
}
impl Encode for ProducersSection {
fn encode(&self, sink: &mut Vec<u8>) {
let mut data = Vec::new();
self.num_fields.encode(&mut data);
data.extend(&self.bytes);
CustomSection {
name: "producers".into(),
data: Cow::Borrowed(&data),
}
.encode(sink);
}
}
impl Section for ProducersSection {
fn id(&self) -> u8 {
SectionId::Custom.into()
}
}
/// The value of a field in the producers custom section
#[derive(Clone, Debug)]
pub struct ProducersField {
bytes: Vec<u8>,
num_values: u32,
}
impl ProducersField {
/// Construct an empty encoder for a producers field value
pub fn new() -> Self {
ProducersField::default()
}
/// Add a value to the field encoder. Each value in a field must have a
/// unique name. If there is no sensible value for `version`, use the
/// empty string.
pub fn value(&mut self, name: &str, version: &str) -> &mut Self {
name.encode(&mut self.bytes);
version.encode(&mut self.bytes);
self.num_values += 1;
self
}
}
impl Default for ProducersField {
fn default() -> Self {
Self {
bytes: Vec::new(),
num_values: 0,
}
}
}
impl Encode for ProducersField {
fn encode(&self, sink: &mut Vec<u8>) {
self.num_values.encode(sink);
sink.extend(&self.bytes);
}
}
#[cfg(test)]
mod test {
#[test]
fn roundtrip_example() {
use crate::{Module, ProducersField, ProducersSection};
use wasmparser::{KnownCustom, Parser, Payload};
// Create a new producers section.
let mut field = ProducersField::new();
field.value("clang", "14.0.4");
field.value("rustc", "1.66.1");
let mut producers = ProducersSection::new();
producers.field("processed-by", &field);
// Add the producers section to a new Wasm module and get the encoded bytes.
let mut module = Module::new();
module.section(&producers);
let wasm_bytes = module.finish();
let mut parser = Parser::new(0).parse_all(&wasm_bytes);
let payload = parser
.next()
.expect("parser is not empty")
.expect("element is a payload");
match payload {
Payload::Version { .. } => {}
_ => panic!(""),
}
let payload = parser
.next()
.expect("parser is not empty")
.expect("element is a payload");
match payload {
Payload::CustomSection(c) => {
assert_eq!(c.name(), "producers");
let mut section = match c.as_known() {
KnownCustom::Producers(s) => s.into_iter(),
_ => panic!("unknown custom section"),
};
let field = section
.next()
.expect("section has an element")
.expect("element is a producers field");
assert_eq!(field.name, "processed-by");
let mut values = field.values.into_iter();
let value = values
.next()
.expect("values has an element")
.expect("element is a producers field value");
assert_eq!(value.name, "clang");
assert_eq!(value.version, "14.0.4");
let value = values
.next()
.expect("values has another element")
.expect("element is a producers field value");
assert_eq!(value.name, "rustc");
assert_eq!(value.version, "1.66.1");
}
_ => panic!("unexpected payload"),
}
}
}

40
vendor/wasm-encoder/src/core/start.rs vendored Normal file
View File

@@ -0,0 +1,40 @@
use crate::{Encode, Section, SectionId, encoding_size};
use alloc::vec::Vec;
/// An encoder for the start section of WebAssembly modules.
///
/// # Example
///
/// Note: this doesn't actually define the function at index 0, its type, or its
/// code body, so the resulting Wasm module will be invalid. See `TypeSection`,
/// `FunctionSection`, and `CodeSection` for details on how to generate those
/// things.
///
/// ```
/// use wasm_encoder::{Module, StartSection};
///
/// let start = StartSection { function_index: 0 };
///
/// let mut module = Module::new();
/// module.section(&start);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Copy, Debug)]
pub struct StartSection {
/// The index of the start function.
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()
}
}

130
vendor/wasm-encoder/src/core/tables.rs vendored Normal file
View File

@@ -0,0 +1,130 @@
use crate::{ConstExpr, Encode, RefType, Section, SectionId, ValType, encode_section};
use alloc::vec::Vec;
/// An encoder for the table section.
///
/// Table sections are only supported for modules.
///
/// # Example
///
/// ```
/// use wasm_encoder::{Module, TableSection, TableType, RefType};
///
/// let mut tables = TableSection::new();
/// tables.table(TableType {
/// element_type: RefType::FUNCREF,
/// minimum: 128,
/// maximum: None,
/// table64: false,
/// shared: false,
/// });
///
/// let mut module = Module::new();
/// module.section(&tables);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Default, Debug)]
pub struct TableSection {
bytes: Vec<u8>,
num_added: u32,
}
impl TableSection {
/// Construct a new table section encoder.
pub fn new() -> Self {
Self::default()
}
/// 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);
self.num_added += 1;
self
}
/// Define a table with an explicit initialization expression.
///
/// Note that this is part of the function-references proposal.
pub fn table_with_init(&mut self, table_type: TableType, init: &ConstExpr) -> &mut Self {
self.bytes.push(0x40);
self.bytes.push(0x00);
table_type.encode(&mut self.bytes);
init.encode(&mut self.bytes);
self.num_added += 1;
self
}
}
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()
}
}
/// A table's type.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct TableType {
/// The table's element type.
pub element_type: RefType,
/// Whether or not this is a 64-bit table.
pub table64: bool,
/// Minimum size, in elements, of this table
pub minimum: u64,
/// Maximum size, in elements, of this table
pub maximum: Option<u64>,
/// Whether this table is shared or not.
///
/// This is included the shared-everything-threads proposal.
pub shared: bool,
}
impl TableType {
/// Returns the type used to index this table.
pub fn index_type(&self) -> ValType {
if self.table64 {
ValType::I64
} else {
ValType::I32
}
}
}
impl Encode for TableType {
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.table64 {
flags |= 0b100;
}
self.element_type.encode(sink);
sink.push(flags);
self.minimum.encode(sink);
if let Some(max) = self.maximum {
max.encode(sink);
}
}
}

86
vendor/wasm-encoder/src/core/tags.rs vendored Normal file
View File

@@ -0,0 +1,86 @@
use crate::{Encode, Section, SectionId, encode_section};
use alloc::vec::Vec;
/// An encoder for the tag section.
///
/// # Example
///
/// ```
/// use wasm_encoder::{Module, TagSection, TagType, TagKind};
///
/// let mut tags = TagSection::new();
/// tags.tag(TagType {
/// kind: TagKind::Exception,
/// func_type_idx: 0,
/// });
///
/// let mut module = Module::new();
/// module.section(&tags);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Default, Debug)]
pub struct TagSection {
bytes: Vec<u8>,
num_added: u32,
}
impl TagSection {
/// Create a new tag section encoder.
pub fn new() -> Self {
Self::default()
}
/// 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);
self.num_added += 1;
self
}
}
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()
}
}
/// Represents a tag kind.
#[repr(u8)]
#[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, PartialEq, Eq)]
pub struct TagType {
/// The kind of tag
pub kind: TagKind,
/// The function type this tag uses
pub func_type_idx: u32,
}
impl Encode for TagType {
fn encode(&self, sink: &mut Vec<u8>) {
sink.push(self.kind as u8);
self.func_type_idx.encode(sink);
}
}

753
vendor/wasm-encoder/src/core/types.rs vendored Normal file
View File

@@ -0,0 +1,753 @@
use crate::{Encode, Section, SectionId, encode_section};
use alloc::boxed::Box;
use alloc::vec::Vec;
/// Represents a subtype of possible other types in a WebAssembly module.
#[derive(Debug, Clone)]
pub struct SubType {
/// Is the subtype final.
pub is_final: bool,
/// The list of supertype indexes. As of GC MVP, there can be at most one
/// supertype.
pub supertype_idx: Option<u32>,
/// The composite type of the subtype.
pub composite_type: CompositeType,
}
/// Represents a composite type in a WebAssembly module.
#[derive(Debug, Clone)]
pub struct CompositeType {
/// The type defined inside the composite type.
pub inner: CompositeInnerType,
/// Whether the type is shared. This is part of the
/// shared-everything-threads proposal.
pub shared: bool,
/// Optional descriptor attribute.
pub descriptor: Option<u32>,
/// Optional describes attribute.
pub describes: Option<u32>,
}
/// A [`CompositeType`] can contain one of these types.
#[derive(Debug, Clone)]
pub enum CompositeInnerType {
/// The type is for a function.
Func(FuncType),
/// The type is for an array.
Array(ArrayType),
/// The type is for a struct.
Struct(StructType),
/// The type is for a continuation.
Cont(ContType),
}
/// Represents a type of a function in a WebAssembly module.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct FuncType {
/// The combined parameters and result types.
params_results: Box<[ValType]>,
/// The number of parameter types.
len_params: usize,
}
/// Represents a type of an array in a WebAssembly module.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct ArrayType(pub FieldType);
/// Represents a type of a struct in a WebAssembly module.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct StructType {
/// Struct fields.
pub fields: Box<[FieldType]>,
}
/// Field type in composite types (structs, arrays).
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct FieldType {
/// Storage type of the field.
pub element_type: StorageType,
/// Is the field mutable.
pub mutable: bool,
}
/// Storage type for composite type fields.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub enum StorageType {
/// The `i8` type.
I8,
/// The `i16` type.
I16,
/// A value type.
Val(ValType),
}
impl StorageType {
/// Is this storage type defaultable?
pub fn is_defaultable(&self) -> bool {
self.unpack().is_defaultable()
}
/// Unpack this storage type into a value type.
pub fn unpack(&self) -> ValType {
match self {
StorageType::I8 | StorageType::I16 => ValType::I32,
StorageType::Val(v) => *v,
}
}
}
/// Represents a type of a continuation in a WebAssembly module.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct ContType(pub u32);
/// The type of a core WebAssembly value.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub enum ValType {
/// The `i32` type.
I32,
/// The `i64` type.
I64,
/// The `f32` type.
F32,
/// The `f64` type.
F64,
/// The `v128` type.
///
/// Part of the SIMD proposal.
V128,
/// A reference type.
///
/// The `funcref` and `externref` type fall into this category and the full
/// generalization here is due to the implementation of the
/// function-references proposal.
Ref(RefType),
}
impl ValType {
/// Is this a numeric value type?
pub fn is_numeric(&self) -> bool {
match self {
ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 => true,
ValType::V128 | ValType::Ref(_) => false,
}
}
/// Is this a vector type?
pub fn is_vector(&self) -> bool {
match self {
ValType::V128 => true,
ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::Ref(_) => false,
}
}
/// Is this a reference type?
pub fn is_reference(&self) -> bool {
match self {
ValType::Ref(_) => true,
ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => false,
}
}
}
impl FuncType {
/// Creates a new [`FuncType`] from the given `params` and `results`.
pub fn new<P, R>(params: P, results: R) -> Self
where
P: IntoIterator<Item = ValType>,
R: IntoIterator<Item = ValType>,
{
let mut buffer = params.into_iter().collect::<Vec<_>>();
let len_params = buffer.len();
buffer.extend(results);
Self::from_parts(buffer.into(), len_params)
}
#[inline]
pub(crate) fn from_parts(params_results: Box<[ValType]>, len_params: usize) -> Self {
Self {
params_results,
len_params,
}
}
/// Returns a shared slice to the parameter types of the [`FuncType`].
#[inline]
pub fn params(&self) -> &[ValType] {
&self.params_results[..self.len_params]
}
/// Returns a shared slice to the result types of the [`FuncType`].
#[inline]
pub fn results(&self) -> &[ValType] {
&self.params_results[self.len_params..]
}
}
impl ValType {
/// Alias for the `funcref` type in WebAssembly
pub const FUNCREF: ValType = ValType::Ref(RefType::FUNCREF);
/// Alias for the `externref` type in WebAssembly
pub const EXTERNREF: ValType = ValType::Ref(RefType::EXTERNREF);
/// Alias for the `exnref` type in WebAssembly
pub const EXNREF: ValType = ValType::Ref(RefType::EXNREF);
/// Is this value defaultable?
pub fn is_defaultable(&self) -> bool {
match self {
ValType::Ref(r) => r.nullable,
ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => true,
}
}
}
impl Encode for StorageType {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
StorageType::I8 => sink.push(0x78),
StorageType::I16 => sink.push(0x77),
StorageType::Val(vt) => vt.encode(sink),
}
}
}
impl Encode for ValType {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
ValType::I32 => sink.push(0x7F),
ValType::I64 => sink.push(0x7E),
ValType::F32 => sink.push(0x7D),
ValType::F64 => sink.push(0x7C),
ValType::V128 => sink.push(0x7B),
ValType::Ref(rt) => rt.encode(sink),
}
}
}
/// A reference type.
///
/// This is largely part of the function references proposal for WebAssembly but
/// additionally is used by the `funcref` and `externref` types. The full
/// generality of this type is only exercised with function-references.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
#[allow(missing_docs)]
pub struct RefType {
pub nullable: bool,
pub heap_type: HeapType,
}
impl RefType {
/// Alias for the `anyref` type in WebAssembly.
pub const ANYREF: RefType = RefType {
nullable: true,
heap_type: HeapType::Abstract {
shared: false,
ty: AbstractHeapType::Any,
},
};
/// Alias for the `anyref` type in WebAssembly.
pub const EQREF: RefType = RefType {
nullable: true,
heap_type: HeapType::Abstract {
shared: false,
ty: AbstractHeapType::Eq,
},
};
/// Alias for the `funcref` type in WebAssembly.
pub const FUNCREF: RefType = RefType {
nullable: true,
heap_type: HeapType::Abstract {
shared: false,
ty: AbstractHeapType::Func,
},
};
/// Alias for the `externref` type in WebAssembly.
pub const EXTERNREF: RefType = RefType {
nullable: true,
heap_type: HeapType::Abstract {
shared: false,
ty: AbstractHeapType::Extern,
},
};
/// Alias for the `i31ref` type in WebAssembly.
pub const I31REF: RefType = RefType {
nullable: true,
heap_type: HeapType::Abstract {
shared: false,
ty: AbstractHeapType::I31,
},
};
/// Alias for the `arrayref` type in WebAssembly.
pub const ARRAYREF: RefType = RefType {
nullable: true,
heap_type: HeapType::Abstract {
shared: false,
ty: AbstractHeapType::Array,
},
};
/// Alias for the `exnref` type in WebAssembly.
pub const EXNREF: RefType = RefType {
nullable: true,
heap_type: HeapType::Abstract {
shared: false,
ty: AbstractHeapType::Exn,
},
};
/// Create a new abstract reference type.
pub fn new_abstract(ty: AbstractHeapType, nullable: bool, shared: bool) -> Self {
Self {
nullable,
heap_type: HeapType::Abstract { shared, ty },
}
}
/// Set the nullability of this reference type.
pub fn nullable(mut self, nullable: bool) -> Self {
self.nullable = nullable;
self
}
}
impl Encode for RefType {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
// Binary abbreviations (i.e., short form), for when the ref is
// nullable.
RefType {
nullable: true,
heap_type: heap @ HeapType::Abstract { .. },
} => {
heap.encode(sink);
}
// Generic 'ref null <heaptype>' encoding (i.e., long form).
RefType {
nullable: true,
heap_type,
} => {
sink.push(0x63);
heap_type.encode(sink);
}
// Generic 'ref <heaptype>' encoding.
RefType {
nullable: false,
heap_type,
} => {
sink.push(0x64);
heap_type.encode(sink);
}
}
}
}
impl From<RefType> for ValType {
fn from(ty: RefType) -> ValType {
ValType::Ref(ty)
}
}
/// Part of the function references proposal.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub enum HeapType {
/// An abstract heap type; e.g., `anyref`.
Abstract {
/// Whether the type is shared.
shared: bool,
/// The actual heap type.
ty: AbstractHeapType,
},
/// A concrete Wasm-defined type at the given index.
Concrete(u32),
/// An exact type.
Exact(u32),
}
impl HeapType {
/// Alias for the unshared `any` heap type.
pub const ANY: Self = Self::Abstract {
shared: false,
ty: AbstractHeapType::Any,
};
/// Alias for the unshared `func` heap type.
pub const FUNC: Self = Self::Abstract {
shared: false,
ty: AbstractHeapType::Func,
};
/// Alias for the unshared `extern` heap type.
pub const EXTERN: Self = Self::Abstract {
shared: false,
ty: AbstractHeapType::Extern,
};
/// Alias for the unshared `i31` heap type.
pub const I31: Self = Self::Abstract {
shared: false,
ty: AbstractHeapType::I31,
};
}
impl Encode for HeapType {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
HeapType::Abstract { shared, ty } => {
if *shared {
sink.push(0x65);
}
ty.encode(sink);
}
// Note that this is encoded as a signed type rather than unsigned
// as it's decoded as an s33
HeapType::Concrete(i) => i64::from(*i).encode(sink),
// Exact type is u32
HeapType::Exact(i) => {
sink.push(0x62);
u32::from(*i).encode(sink)
}
}
}
}
/// An abstract heap type.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub enum AbstractHeapType {
/// Untyped (any) function.
Func,
/// The abstract external heap type.
Extern,
/// The abstract `any` heap type.
///
/// The common supertype (a.k.a. top) of all internal types.
Any,
/// The abstract `none` heap type.
///
/// The common subtype (a.k.a. bottom) of all internal types.
None,
/// The abstract `noextern` heap type.
///
/// The common subtype (a.k.a. bottom) of all external types.
NoExtern,
/// The abstract `nofunc` heap type.
///
/// The common subtype (a.k.a. bottom) of all function types.
NoFunc,
/// The abstract `eq` heap type.
///
/// The common supertype of all referenceable types on which comparison
/// (ref.eq) is allowed.
Eq,
/// The abstract `struct` heap type.
///
/// The common supertype of all struct types.
Struct,
/// The abstract `array` heap type.
///
/// The common supertype of all array types.
Array,
/// The unboxed `i31` heap type.
I31,
/// The abstract `exception` heap type.
Exn,
/// The abstract `noexn` heap type.
NoExn,
/// The abstract `cont` heap type.
Cont,
/// The abstract `nocont` heap type.
NoCont,
}
impl Encode for AbstractHeapType {
fn encode(&self, sink: &mut Vec<u8>) {
use AbstractHeapType::*;
match self {
Func => sink.push(0x70),
Extern => sink.push(0x6F),
Any => sink.push(0x6E),
None => sink.push(0x71),
NoExtern => sink.push(0x72),
NoFunc => sink.push(0x73),
Eq => sink.push(0x6D),
Struct => sink.push(0x6B),
Array => sink.push(0x6A),
I31 => sink.push(0x6C),
Exn => sink.push(0x69),
NoExn => sink.push(0x74),
Cont => sink.push(0x68),
NoCont => sink.push(0x75),
}
}
}
/// An encoder for the type section of WebAssembly modules.
///
/// # Example
///
/// ```rust
/// use wasm_encoder::{Module, TypeSection, ValType};
///
/// let mut types = TypeSection::new();
///
/// types.ty().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
}
/// Encode a function type in this type section.
#[must_use = "the encoder must be used to encode the type"]
pub fn ty(&mut self) -> CoreTypeEncoder<'_> {
self.num_added += 1;
CoreTypeEncoder {
bytes: &mut self.bytes,
push_prefix_if_component_core_type: false,
}
}
}
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()
}
}
/// A single-use encoder for encoding a type; this forces all encoding for a
/// type to be done in a single shot.
#[derive(Debug)]
pub struct CoreTypeEncoder<'a> {
pub(crate) bytes: &'a mut Vec<u8>,
// For the time being, this flag handles an ambiguous encoding in the
// component model: the `0x50` opcode represents both a core module type as
// well as a GC non-final `sub` type. To avoid this, the component model
// specification requires us to prefix a non-final `sub` type with `0x00`
// when it is used as a top-level core type of a component. Eventually
// (prior to the component model's v1.0 release), a module type will get a
// new opcode and this special logic can go away.
pub(crate) push_prefix_if_component_core_type: bool,
}
impl<'a> CoreTypeEncoder<'a> {
/// Define a function type in this type section.
pub fn function<P, R>(mut self, params: P, results: R)
where
P: IntoIterator<Item = ValType>,
P::IntoIter: ExactSizeIterator,
R: IntoIterator<Item = ValType>,
R::IntoIter: ExactSizeIterator,
{
self.encode_function(params, results);
}
/// Define a function type in this type section.
pub fn func_type(mut self, ty: &FuncType) {
self.encode_function(ty.params().iter().cloned(), ty.results().iter().cloned());
}
fn encode_function<P, R>(&mut 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.bytes.push(0x60);
params.len().encode(self.bytes);
params.for_each(|p| p.encode(self.bytes));
results.len().encode(self.bytes);
results.for_each(|p| p.encode(self.bytes));
}
/// Define an array type in this type section.
pub fn array(mut self, ty: &StorageType, mutable: bool) {
self.encode_array(ty, mutable);
}
fn encode_array(&mut self, ty: &StorageType, mutable: bool) {
self.bytes.push(0x5e);
self.encode_field(ty, mutable);
}
fn encode_field(&mut self, ty: &StorageType, mutable: bool) {
ty.encode(self.bytes);
self.bytes.push(mutable as u8);
}
/// Define a struct type in this type section.
pub fn struct_<F>(mut self, fields: F)
where
F: IntoIterator<Item = FieldType>,
F::IntoIter: ExactSizeIterator,
{
self.encode_struct(fields);
}
fn encode_struct<F>(&mut self, fields: F)
where
F: IntoIterator<Item = FieldType>,
F::IntoIter: ExactSizeIterator,
{
let fields = fields.into_iter();
self.bytes.push(0x5f);
fields.len().encode(self.bytes);
for f in fields {
self.encode_field(&f.element_type, f.mutable);
}
}
/// Define a continuation type in this subsection
pub fn cont(mut self, ty: &ContType) {
self.encode_cont(ty)
}
fn encode_cont(&mut self, ty: &ContType) {
self.bytes.push(0x5d);
i64::from(ty.0).encode(self.bytes);
}
/// Define an explicit subtype in this type section.
pub fn subtype(mut self, ty: &SubType) {
self.encode_subtype(ty)
}
/// Define an explicit subtype in this type section.
fn encode_subtype(&mut self, ty: &SubType) {
// We only need to emit a prefix byte before the actual composite type
// when either the `sub` type is not final or it has a declared super
// type (see notes on `push_prefix_if_component_core_type`).
if ty.supertype_idx.is_some() || !ty.is_final {
if ty.is_final {
self.bytes.push(0x4f);
} else {
if self.push_prefix_if_component_core_type {
self.bytes.push(0x00);
}
self.bytes.push(0x50);
}
ty.supertype_idx.encode(self.bytes);
}
if ty.composite_type.shared {
self.bytes.push(0x65);
}
if let Some(index) = ty.composite_type.describes {
self.bytes.push(0x4c);
index.encode(self.bytes);
}
if let Some(index) = ty.composite_type.descriptor {
self.bytes.push(0x4d);
index.encode(self.bytes);
}
match &ty.composite_type.inner {
CompositeInnerType::Func(ty) => {
self.encode_function(ty.params().iter().copied(), ty.results().iter().copied())
}
CompositeInnerType::Array(ArrayType(ty)) => {
self.encode_array(&ty.element_type, ty.mutable)
}
CompositeInnerType::Struct(ty) => self.encode_struct(ty.fields.iter().cloned()),
CompositeInnerType::Cont(ty) => self.encode_cont(ty),
}
}
/// Define an explicit recursion group in this type section.
pub fn rec<T>(mut self, types: T)
where
T: IntoIterator<Item = SubType>,
T::IntoIter: ExactSizeIterator,
{
// When emitting a `rec` group, we will never emit `sub`'s special
// `0x00` prefix; that is only necessary when `sub` is not wrapped by
// `rec` (see notes on `push_prefix_if_component_core_type`).
self.push_prefix_if_component_core_type = false;
let types = types.into_iter();
self.bytes.push(0x4e);
types.len().encode(self.bytes);
types.for_each(|t| {
self.encode_subtype(&t);
});
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Module;
use wasmparser::WasmFeatures;
#[test]
fn func_types_dont_require_wasm_gc() {
let mut types = TypeSection::new();
types.ty().subtype(&SubType {
is_final: true,
supertype_idx: None,
composite_type: CompositeType {
inner: CompositeInnerType::Func(FuncType::new([], [])),
shared: false,
descriptor: None,
describes: None,
},
});
let mut module = Module::new();
module.section(&types);
let wasm_bytes = module.finish();
let mut validator =
wasmparser::Validator::new_with_features(WasmFeatures::default() & !WasmFeatures::GC);
validator.validate_all(&wasm_bytes).expect(
"Encoding pre Wasm GC type should not accidentally use Wasm GC specific encoding",
);
}
}

224
vendor/wasm-encoder/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,224 @@
//! A WebAssembly encoder.
//!
//! The main builder is the [`Module`]. You can build a section with a
//! section-specific builder, like [`TypeSection`] or [`ImportSection`], and
//! then add it to the module with [`Module::section`]. When you are finished
//! building the module, call either [`Module::as_slice`] or [`Module::finish`]
//! to get the encoded bytes. The former gives a shared reference to the
//! underlying bytes as a slice, while the latter gives you ownership of them as
//! a vector.
//!
//! # Example
//!
//! If we wanted to build this module:
//!
//! ```wasm
//! (module
//! (type (func (param i32 i32) (result i32)))
//! (func (type 0)
//! local.get 0
//! local.get 1
//! i32.add)
//! (export "f" (func 0)))
//! ```
//!
//! then we would do this:
//!
//! ```
//! use wasm_encoder::{
//! CodeSection, ExportKind, ExportSection, Function, FunctionSection,
//! Module, TypeSection, ValType,
//! };
//!
//! let mut module = Module::new();
//!
//! // Encode the type section.
//! let mut types = TypeSection::new();
//! let params = vec![ValType::I32, ValType::I32];
//! let results = vec![ValType::I32];
//! types.ty().function(params, results);
//! module.section(&types);
//!
//! // Encode the function section.
//! let mut functions = FunctionSection::new();
//! let type_index = 0;
//! functions.function(type_index);
//! module.section(&functions);
//!
//! // Encode the export section.
//! let mut exports = ExportSection::new();
//! 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.instructions()
//! .local_get(0)
//! .local_get(1)
//! .i32_add()
//! .end();
//! codes.function(&f);
//! module.section(&codes);
//!
//! // Extract the encoded Wasm bytes for this module.
//! let wasm_bytes = module.finish();
//!
//! // We generated a valid Wasm module!
//! assert!(wasmparser::validate(&wasm_bytes).is_ok());
//! ```
#![cfg_attr(docsrs, feature(doc_cfg))]
#![no_std]
#![deny(missing_docs, missing_debug_implementations)]
extern crate alloc;
#[cfg(feature = "std")]
#[macro_use]
extern crate std;
#[cfg(feature = "component-model")]
mod component;
mod core;
mod raw;
#[cfg(feature = "wasmparser")]
pub mod reencode;
#[cfg(feature = "component-model")]
pub use self::component::*;
pub use self::core::*;
pub use self::raw::*;
use alloc::vec::Vec;
/// 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>);
}
impl<T: Encode + ?Sized> Encode for &'_ T {
fn encode(&self, sink: &mut Vec<u8>) {
T::encode(self, sink)
}
}
impl<T: Encode> Encode for [T] {
fn encode(&self, sink: &mut Vec<u8>) {
self.len().encode(sink);
for item in self {
item.encode(sink);
}
}
}
impl Encode for [u8] {
fn encode(&self, sink: &mut Vec<u8>) {
self.len().encode(sink);
sink.extend(self);
}
}
impl Encode for str {
fn encode(&self, sink: &mut Vec<u8>) {
self.len().encode(sink);
sink.extend_from_slice(self.as_bytes());
}
}
impl Encode for usize {
fn encode(&self, sink: &mut Vec<u8>) {
assert!(*self <= u32::max_value() as usize);
(*self as u32).encode(sink)
}
}
impl Encode for u32 {
fn encode(&self, sink: &mut Vec<u8>) {
let (value, pos) = leb128fmt::encode_u32(*self).unwrap();
sink.extend_from_slice(&value[..pos]);
}
}
impl Encode for i32 {
fn encode(&self, sink: &mut Vec<u8>) {
let (value, pos) = leb128fmt::encode_s32(*self).unwrap();
sink.extend_from_slice(&value[..pos]);
}
}
impl Encode for u64 {
fn encode(&self, sink: &mut Vec<u8>) {
let (value, pos) = leb128fmt::encode_u64(*self).unwrap();
sink.extend_from_slice(&value[..pos]);
}
}
impl Encode for i64 {
fn encode(&self, sink: &mut Vec<u8>) {
let (value, pos) = leb128fmt::encode_s64(*self).unwrap();
sink.extend_from_slice(&value[..pos]);
}
}
fn encode_vec<T, V>(elements: V, sink: &mut Vec<u8>)
where
T: Encode,
V: IntoIterator<Item = T>,
V::IntoIter: ExactSizeIterator,
{
let elements = elements.into_iter();
u32::try_from(elements.len()).unwrap().encode(sink);
for x in elements {
x.encode(sink);
}
}
impl<T> Encode for Option<T>
where
T: Encode,
{
fn encode(&self, sink: &mut Vec<u8>) {
match self {
Some(v) => {
sink.push(0x01);
v.encode(sink);
}
None => sink.push(0x00),
}
}
}
fn encoding_size(n: u32) -> usize {
let (_value, pos) = leb128fmt::encode_u32(n).unwrap();
pos
}
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 test_encoding_size() {
assert_eq!(encoding_size(624485), 3);
}
#[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', 0x0d, 0x00, 0x01, 0x00]);
}
}

32
vendor/wasm-encoder/src/raw.rs vendored Normal file
View File

@@ -0,0 +1,32 @@
use crate::{Encode, Section};
use alloc::vec::Vec;
/// 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
}
}
#[cfg(feature = "component-model")]
impl crate::ComponentSection for RawSection<'_> {
fn id(&self) -> u8 {
self.id
}
}

2134
vendor/wasm-encoder/src/reencode.rs vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff