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

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()
}
}