diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /third_party/rust/wasm-encoder/src/component | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/wasm-encoder/src/component')
-rw-r--r-- | third_party/rust/wasm-encoder/src/component/aliases.rs | 160 | ||||
-rw-r--r-- | third_party/rust/wasm-encoder/src/component/builder.rs | 455 | ||||
-rw-r--r-- | third_party/rust/wasm-encoder/src/component/canonicals.rs | 159 | ||||
-rw-r--r-- | third_party/rust/wasm-encoder/src/component/components.rs | 29 | ||||
-rw-r--r-- | third_party/rust/wasm-encoder/src/component/exports.rs | 124 | ||||
-rw-r--r-- | third_party/rust/wasm-encoder/src/component/imports.rs | 175 | ||||
-rw-r--r-- | third_party/rust/wasm-encoder/src/component/instances.rs | 200 | ||||
-rw-r--r-- | third_party/rust/wasm-encoder/src/component/modules.rs | 29 | ||||
-rw-r--r-- | third_party/rust/wasm-encoder/src/component/names.rs | 149 | ||||
-rw-r--r-- | third_party/rust/wasm-encoder/src/component/start.rs | 52 | ||||
-rw-r--r-- | third_party/rust/wasm-encoder/src/component/types.rs | 792 |
11 files changed, 2324 insertions, 0 deletions
diff --git a/third_party/rust/wasm-encoder/src/component/aliases.rs b/third_party/rust/wasm-encoder/src/component/aliases.rs new file mode 100644 index 0000000000..1e317fb0e2 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/aliases.rs @@ -0,0 +1,160 @@ +use super::{COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, CORE_TYPE_SORT, TYPE_SORT}; +use crate::{ + encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind, +}; + +/// Represents the kinds of outer 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); + } + } + } +} diff --git a/third_party/rust/wasm-encoder/src/component/builder.rs b/third_party/rust/wasm-encoder/src/component/builder.rs new file mode 100644 index 0000000000..27c39ac8a0 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/builder.rs @@ -0,0 +1,455 @@ +use crate::component::*; +use crate::{ExportKind, Module, RawSection, ValType}; +use std::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: u32, + core_funcs: u32, + core_types: u32, + core_memories: u32, + core_tables: u32, + core_instances: u32, + core_tags: u32, + core_globals: u32, + + // Component index spaces + funcs: u32, + instances: u32, + types: u32, + components: u32, + values: u32, +} + +impl ComponentBuilder { + /// Returns the current number of core modules. + pub fn core_module_count(&self) -> u32 { + self.core_modules + } + + /// Returns the current number of core funcs. + pub fn core_func_count(&self) -> u32 { + self.core_funcs + } + + /// Returns the current number of core types. + pub fn core_type_count(&self) -> u32 { + self.core_types + } + + /// Returns the current number of core memories. + pub fn core_memory_count(&self) -> u32 { + self.core_memories + } + + /// Returns the current number of core tables. + pub fn core_table_count(&self) -> u32 { + self.core_tables + } + + /// Returns the current number of core instances. + pub fn core_instance_count(&self) -> u32 { + self.core_instances + } + + /// Returns the current number of core tags. + pub fn core_tag_count(&self) -> u32 { + self.core_tags + } + + /// Returns the current number of core globals. + pub fn core_global_count(&self) -> u32 { + self.core_globals + } + + /// Returns the current number of component funcs. + pub fn func_count(&self) -> u32 { + self.funcs + } + + /// Returns the current number of component instances. + pub fn instance_count(&self) -> u32 { + self.instances + } + + /// Returns the current number of component values. + pub fn value_count(&self) -> u32 { + self.values + } + + /// Returns the current number of components. + pub fn component_count(&self) -> u32 { + self.components + } + + /// Returns the current number of component types. + pub fn type_count(&self) -> u32 { + self.types + } + + /// 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, module: &Module) -> u32 { + self.flush(); + self.component.section(&ModuleSection(module)); + inc(&mut self.core_modules) + } + + /// Encodes a core wasm `module` into this component, returning its index. + pub fn core_module_raw(&mut self, module: &[u8]) -> u32 { + self.flush(); + self.component.section(&RawSection { + id: ComponentSectionId::CoreModule.into(), + data: module, + }); + inc(&mut self.core_modules) + } + + /// Instantiates a core wasm module at `module_index` with the `args` + /// provided. + /// + /// Returns the index of the core wasm instance crated. + pub fn core_instantiate<'a, A>(&mut self, module_index: u32, args: A) -> u32 + where + A: IntoIterator<Item = (&'a str, ModuleArg)>, + A::IntoIter: ExactSizeIterator, + { + self.instances().instantiate(module_index, args); + inc(&mut self.core_instances) + } + + /// Creates a new core wasm instance from the `exports` provided. + /// + /// Returns the index of the core wasm instance crated. + pub fn core_instantiate_exports<'a, E>(&mut self, exports: E) -> u32 + where + E: IntoIterator<Item = (&'a str, ExportKind, u32)>, + E::IntoIter: ExactSizeIterator, + { + self.instances().export_items(exports); + inc(&mut self.core_instances) + } + + /// 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 crated. + pub fn core_alias_export(&mut self, instance: u32, name: &str, kind: ExportKind) -> u32 { + self.alias(Alias::CoreInstanceExport { + instance, + kind, + name, + }) + } + + /// Adds a new alias to this component + pub fn alias(&mut self, alias: Alias<'_>) -> u32 { + self.aliases().alias(alias); + match alias { + Alias::InstanceExport { kind, .. } => self.inc_kind(kind), + Alias::CoreInstanceExport { kind, .. } => self.inc_core_kind(kind), + Alias::Outer { + kind: ComponentOuterAliasKind::Type, + .. + } => inc(&mut self.types), + Alias::Outer { + kind: ComponentOuterAliasKind::CoreModule, + .. + } => inc(&mut self.core_modules), + Alias::Outer { + kind: ComponentOuterAliasKind::Component, + .. + } => inc(&mut self.components), + Alias::Outer { + kind: ComponentOuterAliasKind::CoreType, + .. + } => inc(&mut self.core_types), + } + } + + /// 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(Alias::InstanceExport { + instance, + kind, + name, + }) + } + + fn inc_kind(&mut self, kind: ComponentExportKind) -> u32 { + match kind { + ComponentExportKind::Func => inc(&mut self.funcs), + ComponentExportKind::Module => inc(&mut self.core_modules), + ComponentExportKind::Type => inc(&mut self.types), + ComponentExportKind::Component => inc(&mut self.components), + ComponentExportKind::Instance => inc(&mut self.instances), + ComponentExportKind::Value => inc(&mut self.values), + } + } + + fn inc_core_kind(&mut self, kind: ExportKind) -> u32 { + match kind { + ExportKind::Func => inc(&mut self.core_funcs), + ExportKind::Table => inc(&mut self.core_tables), + ExportKind::Memory => inc(&mut self.core_memories), + ExportKind::Global => inc(&mut self.core_globals), + ExportKind::Tag => inc(&mut self.core_tags), + } + } + + /// 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, func_index: u32, options: O) -> u32 + where + O: IntoIterator<Item = CanonicalOption>, + O::IntoIter: ExactSizeIterator, + { + self.canonical_functions().lower(func_index, options); + inc(&mut self.core_funcs) + } + + /// 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, 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); + inc(&mut self.funcs) + } + + /// 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(_) => inc(&mut self.instances), + ComponentTypeRef::Func(_) => inc(&mut self.funcs), + ComponentTypeRef::Type(..) => inc(&mut self.types), + ComponentTypeRef::Component(_) => inc(&mut self.components), + ComponentTypeRef::Module(_) => inc(&mut self.core_modules), + ComponentTypeRef::Value(_) => inc(&mut self.values), + }; + 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(kind) + } + + /// Creates a new encoder for the next core type in this component. + pub fn core_type(&mut self) -> (u32, CoreTypeEncoder<'_>) { + (inc(&mut self.core_types), self.core_types().ty()) + } + + /// Creates a new encoder for the next type in this component. + pub fn ty(&mut self) -> (u32, ComponentTypeEncoder<'_>) { + (inc(&mut self.types), self.types().ty()) + } + + /// Creates a new instance type within this component. + pub fn type_instance(&mut self, ty: &InstanceType) -> u32 { + self.types().instance(ty); + inc(&mut self.types) + } + + /// Creates a new component type within this component. + pub fn type_component(&mut self, ty: &ComponentType) -> u32 { + self.types().component(ty); + inc(&mut self.types) + } + + /// Creates a new defined component type within this component. + pub fn type_defined(&mut self) -> (u32, ComponentDefinedTypeEncoder<'_>) { + (inc(&mut self.types), self.types().defined_type()) + } + + /// Creates a new component function type within this component. + pub fn type_function(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>) { + (inc(&mut self.types), self.types().function()) + } + + /// Declares a + pub fn type_resource(&mut self, rep: ValType, dtor: Option<u32>) -> u32 { + self.types().resource(rep, dtor); + inc(&mut self.types) + } + + /// Defines a new subcomponent of this component. + pub fn component(&mut self, mut builder: ComponentBuilder) -> u32 { + builder.flush(); + self.flush(); + self.component + .section(&NestedComponentSection(&builder.component)); + inc(&mut self.components) + } + + /// Defines a new subcomponent of this component. + pub fn component_raw(&mut self, data: &[u8]) -> u32 { + let raw_section = RawSection { + id: ComponentSectionId::Component.into(), + data, + }; + self.flush(); + self.component.section(&raw_section); + inc(&mut self.components) + } + + /// Instantiates the `component_index` specified with the `args` specified. + pub fn instantiate<A, S>(&mut self, 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); + inc(&mut self.instances) + } + + /// Declares a new `resource.drop` intrinsic. + pub fn resource_drop(&mut self, ty: u32) -> u32 { + self.canonical_functions().resource_drop(ty); + inc(&mut self.core_funcs) + } + + /// Declares a new `resource.new` intrinsic. + pub fn resource_new(&mut self, ty: u32) -> u32 { + self.canonical_functions().resource_new(ty); + inc(&mut self.core_funcs) + } + + /// Declares a new `resource.rep` intrinsic. + pub fn resource_rep(&mut self, ty: u32) -> u32 { + self.canonical_functions().resource_rep(ty); + inc(&mut self.core_funcs) + } + + /// 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(§ion); + } + )* + } + } + + } + ) +} + +section_accessors! { + component_instances => ComponentInstanceSection + instances => InstanceSection + canonical_functions => CanonicalFunctionSection + aliases => ComponentAliasSection + exports => ComponentExportSection + imports => ComponentImportSection + types => ComponentTypeSection + core_types => CoreTypeSection +} + +fn inc(idx: &mut u32) -> u32 { + let ret = *idx; + *idx += 1; + ret +} diff --git a/third_party/rust/wasm-encoder/src/component/canonicals.rs b/third_party/rust/wasm-encoder/src/component/canonicals.rs new file mode 100644 index 0000000000..340d9ca621 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/canonicals.rs @@ -0,0 +1,159 @@ +use crate::{encode_section, ComponentSection, ComponentSectionId, Encode}; + +/// Represents options for canonical function definitions. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum CanonicalOption { + /// The string types in the function signature are UTF-8 encoded. + UTF8, + /// The string types in the function signature are UTF-16 encoded. + UTF16, + /// The string types in the function signature are compact UTF-16 encoded. + CompactUTF16, + /// The memory to use if the lifting or lowering of a function requires memory access. + /// + /// The value is an index to a core memory. + Memory(u32), + /// The realloc function to use if the lifting or lowering of a function requires memory + /// allocation. + /// + /// The value is an index to a core function of type `(func (param i32 i32 i32 i32) (result i32))`. + Realloc(u32), + /// The post-return function to use if the lifting of a function requires + /// cleanup after the function returns. + PostReturn(u32), +} + +impl Encode for CanonicalOption { + fn encode(&self, sink: &mut Vec<u8>) { + match self { + Self::UTF8 => sink.push(0x00), + Self::UTF16 => sink.push(0x01), + Self::CompactUTF16 => sink.push(0x02), + Self::Memory(idx) => { + sink.push(0x03); + idx.encode(sink); + } + Self::Realloc(idx) => { + sink.push(0x04); + idx.encode(sink); + } + Self::PostReturn(idx) => { + sink.push(0x05); + idx.encode(sink); + } + } + } +} + +/// An encoder for the canonical function section of WebAssembly components. +/// +/// # Example +/// +/// ``` +/// use wasm_encoder::{Component, CanonicalFunctionSection, CanonicalOption}; +/// +/// let mut functions = CanonicalFunctionSection::new(); +/// functions.lift(0, 0, [CanonicalOption::UTF8]); +/// +/// let mut component = Component::new(); +/// component.section(&functions); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct CanonicalFunctionSection { + bytes: Vec<u8>, + num_added: u32, +} + +impl CanonicalFunctionSection { + /// Construct a new component function section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of functions in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Define a function that will lift a core WebAssembly function to the canonical ABI. + pub fn lift<O>(&mut self, core_func_index: u32, type_index: u32, options: O) -> &mut Self + where + O: IntoIterator<Item = CanonicalOption>, + O::IntoIter: ExactSizeIterator, + { + let options = options.into_iter(); + self.bytes.push(0x00); + self.bytes.push(0x00); + core_func_index.encode(&mut self.bytes); + options.len().encode(&mut self.bytes); + for option in options { + option.encode(&mut self.bytes); + } + type_index.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Define a function that will lower a canonical ABI function to a core WebAssembly function. + pub fn lower<O>(&mut self, func_index: u32, options: O) -> &mut Self + where + O: IntoIterator<Item = CanonicalOption>, + O::IntoIter: ExactSizeIterator, + { + let options = options.into_iter(); + self.bytes.push(0x01); + self.bytes.push(0x00); + func_index.encode(&mut self.bytes); + options.len().encode(&mut self.bytes); + for option in options { + option.encode(&mut self.bytes); + } + self.num_added += 1; + self + } + + /// 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 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 + } +} + +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() + } +} diff --git a/third_party/rust/wasm-encoder/src/component/components.rs b/third_party/rust/wasm-encoder/src/component/components.rs new file mode 100644 index 0000000000..c08645e3b9 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/components.rs @@ -0,0 +1,29 @@ +use crate::{Component, ComponentSection, ComponentSectionId, Encode}; + +/// An encoder for the component section of WebAssembly components. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{Component, NestedComponentSection}; +/// +/// let mut nested = Component::new(); +/// let mut component = Component::new(); +/// component.section(&NestedComponentSection(&nested)); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug)] +pub struct NestedComponentSection<'a>(pub &'a Component); + +impl Encode for NestedComponentSection<'_> { + fn encode(&self, sink: &mut Vec<u8>) { + self.0.bytes.encode(sink); + } +} + +impl ComponentSection for NestedComponentSection<'_> { + fn id(&self) -> u8 { + ComponentSectionId::Component.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/component/exports.rs b/third_party/rust/wasm-encoder/src/component/exports.rs new file mode 100644 index 0000000000..e4fcfee055 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/exports.rs @@ -0,0 +1,124 @@ +use super::{ + COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, FUNCTION_SORT, INSTANCE_SORT, TYPE_SORT, + VALUE_SORT, +}; +use crate::{encode_section, ComponentSection, ComponentSectionId, ComponentTypeRef, Encode}; + +/// Represents the kind of an export from a WebAssembly component. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ComponentExportKind { + /// The export is a core module. + Module, + /// The export is a function. + Func, + /// The export is a value. + Value, + /// The export is a type. + Type, + /// The export is an instance. + Instance, + /// The export is a component. + Component, +} + +impl Encode for ComponentExportKind { + fn encode(&self, sink: &mut Vec<u8>) { + match self { + Self::Module => { + sink.push(CORE_SORT); + sink.push(CORE_MODULE_SORT); + } + Self::Func => { + sink.push(FUNCTION_SORT); + } + Self::Value => { + sink.push(VALUE_SORT); + } + Self::Type => { + sink.push(TYPE_SORT); + } + Self::Instance => { + sink.push(INSTANCE_SORT); + } + Self::Component => { + sink.push(COMPONENT_SORT); + } + } + } +} + +/// An encoder for the export section of WebAssembly component. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{Component, ComponentExportSection, ComponentExportKind}; +/// +/// // This exports a function named "foo" +/// let mut exports = ComponentExportSection::new(); +/// exports.export("foo", ComponentExportKind::Func, 0, 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::component::imports::push_extern_name_byte(&mut self.bytes, name); + name.encode(&mut self.bytes); + 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() + } +} diff --git a/third_party/rust/wasm-encoder/src/component/imports.rs b/third_party/rust/wasm-encoder/src/component/imports.rs new file mode 100644 index 0000000000..6337a0625d --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/imports.rs @@ -0,0 +1,175 @@ +use crate::{ + encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, ComponentValType, + Encode, +}; + +/// Represents the possible type bounds for type references. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum TypeBounds { + /// The type is bounded by equality 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(PrimitiveValType::String); +/// +/// // This imports a function named `f` with the type defined above +/// let mut imports = ComponentImportSection::new(); +/// imports.import("f", ComponentTypeRef::Func(0)); +/// +/// let mut component = Component::new(); +/// component.section(&types); +/// component.section(&imports); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct ComponentImportSection { + bytes: Vec<u8>, + num_added: u32, +} + +impl ComponentImportSection { + /// Create a new component import section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of imports in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Define an import in the component import section. + pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { + push_extern_name_byte(&mut self.bytes, name); + name.encode(&mut self.bytes); + ty.encode(&mut self.bytes); + self.num_added += 1; + self + } +} + +impl Encode for ComponentImportSection { + fn encode(&self, sink: &mut Vec<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl ComponentSection for ComponentImportSection { + fn id(&self) -> u8 { + ComponentSectionId::Import.into() + } +} + +/// 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. +/// +/// This function is a compatibility shim for the time being while this change +/// is being rolled out. That PR is technically a spec-breaking change relative +/// to prior but we want old tooling to continue to work with new modules. To +/// handle that names that look like IDs, `a:b/c`, get an 0x01 prefix instead of +/// the spec-defined 0x00 prefix. That makes components produced by current +/// versions of this crate compatible with older parsers. +/// +/// Note that wasmparser has a similar case where it parses either 0x01 or 0x00. +/// That means that the selection of a byte here doesn't actually matter for +/// wasmparser's own validation. Eventually this will go away and an 0x00 byte +/// will always be emitted to align with the spec. +pub(crate) fn push_extern_name_byte(bytes: &mut Vec<u8>, name: &str) { + if name.contains(':') { + bytes.push(0x01); + } else { + bytes.push(0x00); + } +} diff --git a/third_party/rust/wasm-encoder/src/component/instances.rs b/third_party/rust/wasm-encoder/src/component/instances.rs new file mode 100644 index 0000000000..e0877d1661 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/instances.rs @@ -0,0 +1,200 @@ +use super::CORE_INSTANCE_SORT; +use crate::{ + encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind, +}; + +/// Represents an argument to a module instantiation. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ModuleArg { + /// The argument is an instance. + Instance(u32), +} + +impl Encode for ModuleArg { + fn encode(&self, sink: &mut Vec<u8>) { + let (sort, idx) = match self { + Self::Instance(idx) => (CORE_INSTANCE_SORT, *idx), + }; + sink.push(sort); + idx.encode(sink); + } +} + +/// An encoder for the core instance section of WebAssembly components. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{Component, InstanceSection, ExportKind, ModuleArg}; +/// +/// let mut instances = InstanceSection::new(); +/// instances.export_items([("foo", ExportKind::Func, 0)]); +/// instances.instantiate(1, [("foo", ModuleArg::Instance(0))]); +/// +/// let mut component = Component::new(); +/// component.section(&instances); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct InstanceSection { + bytes: Vec<u8>, + num_added: u32, +} + +impl InstanceSection { + /// Create a new core instance section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of instances in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Define an instance by instantiating a core module. + pub fn instantiate<A, 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::push_extern_name_byte(&mut self.bytes, name); + name.encode(&mut self.bytes); + kind.encode(&mut self.bytes); + index.encode(&mut self.bytes); + } + self.num_added += 1; + self + } +} + +impl Encode for ComponentInstanceSection { + fn encode(&self, sink: &mut Vec<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl ComponentSection for ComponentInstanceSection { + fn id(&self) -> u8 { + ComponentSectionId::Instance.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/component/modules.rs b/third_party/rust/wasm-encoder/src/component/modules.rs new file mode 100644 index 0000000000..437cd353af --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/modules.rs @@ -0,0 +1,29 @@ +use crate::{ComponentSection, ComponentSectionId, Encode, Module}; + +/// An encoder for the module section of WebAssembly components. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{Module, Component, ModuleSection}; +/// +/// let mut module = Module::new(); +/// let mut component = Component::new(); +/// component.section(&ModuleSection(&module)); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug)] +pub struct ModuleSection<'a>(pub &'a Module); + +impl Encode for ModuleSection<'_> { + fn encode(&self, sink: &mut Vec<u8>) { + self.0.bytes.encode(sink); + } +} + +impl ComponentSection for ModuleSection<'_> { + fn id(&self) -> u8 { + ComponentSectionId::CoreModule.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/component/names.rs b/third_party/rust/wasm-encoder/src/component/names.rs new file mode 100644 index 0000000000..99db10bda0 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/names.rs @@ -0,0 +1,149 @@ +use std::borrow::Cow; + +use super::*; +use crate::{encoding_size, CustomSection, Encode, ExportKind, NameMap, SectionId}; + +/// 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 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) + } + + 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() + } +} diff --git a/third_party/rust/wasm-encoder/src/component/start.rs b/third_party/rust/wasm-encoder/src/component/start.rs new file mode 100644 index 0000000000..d4b60e1dfc --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/start.rs @@ -0,0 +1,52 @@ +use crate::{ComponentSection, ComponentSectionId, Encode}; + +/// An encoder for the start section of WebAssembly components. +/// +/// # Example +/// +/// ``` +/// use wasm_encoder::{Component, ComponentStartSection}; +/// +/// let start = ComponentStartSection { function_index: 0, args: [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() + } +} diff --git a/third_party/rust/wasm-encoder/src/component/types.rs b/third_party/rust/wasm-encoder/src/component/types.rs new file mode 100644 index 0000000000..537e8c5a00 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/types.rs @@ -0,0 +1,792 @@ +use super::CORE_TYPE_SORT; +use crate::{ + encode_section, Alias, ComponentExportKind, ComponentOuterAliasKind, ComponentSection, + ComponentSectionId, ComponentTypeRef, Encode, EntityType, ValType, +}; + +/// Represents the type of a core module. +#[derive(Debug, Clone, Default)] +pub struct ModuleType { + bytes: Vec<u8>, + num_added: u32, + types_added: u32, +} + +impl ModuleType { + /// Creates a new core module type. + pub fn new() -> Self { + Self::default() + } + + /// Defines an import in this module type. + pub fn import(&mut self, module: &str, name: &str, ty: EntityType) -> &mut Self { + crate::component::imports::push_extern_name_byte(&mut self.bytes, name); + module.encode(&mut self.bytes); + name.encode(&mut self.bytes); + ty.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Define a type in this module type. + /// + /// The returned encoder must be used before adding another definition. + #[must_use = "the encoder must be used to encode the type"] + pub fn ty(&mut self) -> CoreTypeEncoder { + self.bytes.push(0x01); + self.num_added += 1; + self.types_added += 1; + CoreTypeEncoder(&mut self.bytes) + } + + /// Defines an 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 CoreTypeEncoder<'a>(pub(crate) &'a mut Vec<u8>); + +impl<'a> CoreTypeEncoder<'a> { + /// Define a function type. + pub fn function<P, R>(self, params: P, results: R) + where + P: IntoIterator<Item = ValType>, + P::IntoIter: ExactSizeIterator, + R: IntoIterator<Item = ValType>, + R::IntoIter: ExactSizeIterator, + { + let params = params.into_iter(); + let results = results.into_iter(); + + self.0.push(0x60); + params.len().encode(self.0); + params.for_each(|p| p.encode(self.0)); + results.len().encode(self.0); + results.for_each(|p| p.encode(self.0)); + } + + /// Define a module type. + pub fn module(self, ty: &ModuleType) { + ty.encode(self.0); + } +} + +/// An encoder for the core type section of WebAssembly components. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{Component, CoreTypeSection, ModuleType}; +/// +/// let mut types = CoreTypeSection::new(); +/// +/// types.module(&ModuleType::new()); +/// +/// let mut component = Component::new(); +/// component.section(&types); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct CoreTypeSection { + bytes: Vec<u8>, + num_added: u32, +} + +impl CoreTypeSection { + /// Create a new core type section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of types in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Encode a type into this section. + /// + /// The returned encoder must be finished before adding another type. + #[must_use = "the encoder must be used to encode the type"] + pub fn ty(&mut self) -> CoreTypeEncoder<'_> { + self.num_added += 1; + CoreTypeEncoder(&mut self.bytes) + } + + /// Define a function type in this type section. + pub fn function<P, R>(&mut self, params: P, results: R) -> &mut Self + where + P: IntoIterator<Item = ValType>, + P::IntoIter: ExactSizeIterator, + R: IntoIterator<Item = ValType>, + R::IntoIter: ExactSizeIterator, + { + self.ty().function(params, results); + self + } + + /// Define a module type in this type section. + /// + /// Currently this is only used for core type sections in components. + pub fn module(&mut self, ty: &ModuleType) -> &mut Self { + self.ty().module(ty); + self + } +} + +impl Encode for CoreTypeSection { + fn encode(&self, sink: &mut Vec<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl ComponentSection for CoreTypeSection { + fn id(&self) -> u8 { + ComponentSectionId::CoreType.into() + } +} + +/// Represents a component type. +#[derive(Debug, Clone, Default)] +pub struct ComponentType { + bytes: Vec<u8>, + num_added: u32, + core_types_added: u32, + types_added: u32, + 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) -> CoreTypeEncoder { + self.bytes.push(0x00); + self.num_added += 1; + self.core_types_added += 1; + CoreTypeEncoder(&mut self.bytes) + } + + /// Define a type in this component type. + /// + /// The returned encoder must be used before adding another definition. + #[must_use = "the encoder must be used to encode the type"] + pub fn ty(&mut self) -> ComponentTypeEncoder { + self.bytes.push(0x01); + self.num_added += 1; + self.types_added += 1; + ComponentTypeEncoder(&mut self.bytes) + } + + /// Defines an 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::component::imports::push_extern_name_byte(&mut self.bytes, name); + name.encode(&mut self.bytes); + 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::component::imports::push_extern_name_byte(&mut self.bytes, name); + name.encode(&mut self.bytes); + 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) -> CoreTypeEncoder { + 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>(&'a mut Vec<u8>); + +impl<'a> ComponentFuncTypeEncoder<'a> { + fn new(sink: &'a mut Vec<u8>) -> Self { + sink.push(0x40); + Self(sink) + } + + /// Defines named parameters. + /// + /// Parameters must be defined before defining results. + 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>, + { + let params = params.into_iter(); + params.len().encode(self.0); + for (name, ty) in params { + name.encode(self.0); + ty.into().encode(self.0); + } + self + } + + /// Defines a single unnamed result. + /// + /// This method cannot be used with `results`. + pub fn result(&mut self, ty: impl Into<ComponentValType>) -> &mut Self { + self.0.push(0x00); + ty.into().encode(self.0); + self + } + + /// Defines named results. + /// + /// This method cannot be used with `result`. + pub fn results<'b, R, T>(&mut self, results: R) -> &mut Self + where + R: IntoIterator<Item = (&'b str, T)>, + R::IntoIter: ExactSizeIterator, + T: Into<ComponentValType>, + { + self.0.push(0x01); + let results = results.into_iter(); + results.len().encode(self.0); + for (name, ty) in results { + name.encode(self.0); + ty.into().encode(self.0); + } + self + } +} + +/// 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. + Float32, + /// The type is a 64-bit floating point number. + Float64, + /// The type is a Unicode character. + Char, + /// The type is a string. + String, +} + +impl Encode for PrimitiveValType { + fn encode(&self, sink: &mut Vec<u8>) { + sink.push(match self { + Self::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::Float32 => 0x76, + Self::Float64 => 0x75, + Self::Char => 0x74, + Self::String => 0x73, + }); + } +} + +#[cfg(feature = "wasmparser")] +impl From<wasmparser::PrimitiveValType> for PrimitiveValType { + fn from(ty: wasmparser::PrimitiveValType) -> Self { + match ty { + wasmparser::PrimitiveValType::Bool => PrimitiveValType::Bool, + wasmparser::PrimitiveValType::S8 => PrimitiveValType::S8, + wasmparser::PrimitiveValType::U8 => PrimitiveValType::U8, + wasmparser::PrimitiveValType::S16 => PrimitiveValType::S16, + wasmparser::PrimitiveValType::U16 => PrimitiveValType::U16, + wasmparser::PrimitiveValType::S32 => PrimitiveValType::S32, + wasmparser::PrimitiveValType::U32 => PrimitiveValType::U32, + wasmparser::PrimitiveValType::S64 => PrimitiveValType::S64, + wasmparser::PrimitiveValType::U64 => PrimitiveValType::U64, + wasmparser::PrimitiveValType::Float32 => PrimitiveValType::Float32, + wasmparser::PrimitiveValType::Float64 => PrimitiveValType::Float64, + wasmparser::PrimitiveValType::Char => PrimitiveValType::Char, + wasmparser::PrimitiveValType::String => PrimitiveValType::String, + } + } +} + +/// 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 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); + } +} + +/// 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(PrimitiveValType::String); +/// +/// let mut component = Component::new(); +/// component.section(&types); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct ComponentTypeSection { + bytes: Vec<u8>, + num_added: u32, +} + +impl ComponentTypeSection { + /// Create a new component type section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of types in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Encode a type into this section. + /// + /// The returned encoder must be finished before adding another type. + #[must_use = "the encoder must be used to encode the type"] + pub fn ty(&mut self) -> ComponentTypeEncoder<'_> { + self.num_added += 1; + ComponentTypeEncoder(&mut self.bytes) + } + + /// Define a component type in this type section. + pub fn component(&mut self, ty: &ComponentType) -> &mut Self { + self.ty().component(ty); + self + } + + /// Define an instance type in this type section. + pub fn instance(&mut self, ty: &InstanceType) -> &mut Self { + self.ty().instance(ty); + self + } + + /// Define a function type in this type section. + pub fn function(&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() + } +} |