diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/wasm-encoder/src/component | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
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/canonicals.rs | 133 | ||||
-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 | 125 | ||||
-rw-r--r-- | third_party/rust/wasm-encoder/src/component/imports.rs | 151 | ||||
-rw-r--r-- | third_party/rust/wasm-encoder/src/component/instances.rs | 199 | ||||
-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 | 147 | ||||
-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 | 736 |
10 files changed, 1761 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/canonicals.rs b/third_party/rust/wasm-encoder/src/component/canonicals.rs new file mode 100644 index 0000000000..e81819c44e --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/canonicals.rs @@ -0,0 +1,133 @@ +use crate::{encode_section, ComponentSection, ComponentSectionId, Encode}; + +/// Represents options for canonical function definitions. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum CanonicalOption { + /// The string types in the function signature are UTF-8 encoded. + UTF8, + /// The string types in the function signature are UTF-16 encoded. + UTF16, + /// The string types in the function signature are compact UTF-16 encoded. + CompactUTF16, + /// The memory to use if the lifting or lowering of a function requires memory access. + /// + /// The value is an index to a core memory. + Memory(u32), + /// The realloc function to use if the lifting or lowering of a function requires memory + /// allocation. + /// + /// The value is an index to a core function of type `(func (param i32 i32 i32 i32) (result i32))`. + Realloc(u32), + /// The post-return function to use if the lifting of a function requires + /// cleanup after the function returns. + PostReturn(u32), +} + +impl Encode for CanonicalOption { + fn encode(&self, sink: &mut Vec<u8>) { + match self { + Self::UTF8 => sink.push(0x00), + Self::UTF16 => sink.push(0x01), + Self::CompactUTF16 => sink.push(0x02), + Self::Memory(idx) => { + sink.push(0x03); + idx.encode(sink); + } + Self::Realloc(idx) => { + sink.push(0x04); + idx.encode(sink); + } + Self::PostReturn(idx) => { + sink.push(0x05); + idx.encode(sink); + } + } + } +} + +/// An encoder for the canonical function section of WebAssembly components. +/// +/// # Example +/// +/// ``` +/// use wasm_encoder::{Component, CanonicalFunctionSection, CanonicalOption}; +/// +/// let mut functions = CanonicalFunctionSection::new(); +/// functions.lift(0, 0, [CanonicalOption::UTF8]); +/// +/// let mut component = Component::new(); +/// component.section(&functions); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct CanonicalFunctionSection { + bytes: Vec<u8>, + num_added: u32, +} + +impl CanonicalFunctionSection { + /// Construct a new component function section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of functions in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Define a function that will lift a core WebAssembly function to the canonical ABI. + pub fn lift<O>(&mut self, core_func_index: u32, type_index: u32, options: O) -> &mut Self + where + O: IntoIterator<Item = CanonicalOption>, + O::IntoIter: ExactSizeIterator, + { + let options = options.into_iter(); + self.bytes.push(0x00); + self.bytes.push(0x00); + core_func_index.encode(&mut self.bytes); + options.len().encode(&mut self.bytes); + for option in options { + option.encode(&mut self.bytes); + } + type_index.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Define a function that will lower a canonical ABI function to a core WebAssembly function. + pub fn lower<O>(&mut self, func_index: u32, options: O) -> &mut Self + where + O: IntoIterator<Item = CanonicalOption>, + O::IntoIter: ExactSizeIterator, + { + let options = options.into_iter(); + self.bytes.push(0x01); + self.bytes.push(0x00); + func_index.encode(&mut self.bytes); + options.len().encode(&mut self.bytes); + for option in options { + option.encode(&mut self.bytes); + } + self.num_added += 1; + self + } +} + +impl Encode for CanonicalFunctionSection { + fn encode(&self, sink: &mut Vec<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl ComponentSection for CanonicalFunctionSection { + fn id(&self) -> u8 { + ComponentSectionId::CanonicalFunction.into() + } +} 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..9720d51b02 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/exports.rs @@ -0,0 +1,125 @@ +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, + url: &str, + kind: ComponentExportKind, + index: u32, + ty: Option<ComponentTypeRef>, + ) -> &mut Self { + name.encode(&mut self.bytes); + url.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..8d843407f3 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/imports.rs @@ -0,0 +1,151 @@ +use crate::{ + encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, ComponentValType, + Encode, +}; + +/// Represents the possible type bounds for type references. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum TypeBounds { + /// The type is bounded by equality. + Eq, +} + +impl Encode for TypeBounds { + fn encode(&self, sink: &mut Vec<u8>) { + match self { + Self::Eq => sink.push(0x00), + } + } +} + +/// Represents a reference to a type. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum ComponentTypeRef { + /// The reference is to a core module type. + /// + /// The index is expected to be core type index to a core module type. + Module(u32), + /// The reference is to a function type. + /// + /// The index is expected to be a type index to a function type. + Func(u32), + /// The reference is to a value type. + Value(ComponentValType), + /// The reference is to a bounded type. + /// + /// The index is expected to be a type index. + Type(TypeBounds, u32), + /// The reference is to an instance type. + /// + /// The index is expected to be a type index to an instance type. + Instance(u32), + /// The reference is to a component type. + /// + /// The index is expected to be a type index to a component type. + Component(u32), +} + +impl ComponentTypeRef { + /// Gets the export kind of the reference. + pub fn kind(&self) -> ComponentExportKind { + match self { + Self::Module(_) => ComponentExportKind::Module, + Self::Func(_) => ComponentExportKind::Func, + Self::Value(_) => ComponentExportKind::Value, + Self::Type(..) => ComponentExportKind::Type, + Self::Instance(_) => ComponentExportKind::Instance, + Self::Component(_) => ComponentExportKind::Component, + } + } +} + +impl Encode for ComponentTypeRef { + fn encode(&self, sink: &mut Vec<u8>) { + self.kind().encode(sink); + + match self { + Self::Module(idx) | Self::Func(idx) | Self::Instance(idx) | Self::Component(idx) => { + idx.encode(sink); + } + Self::Value(ty) => ty.encode(sink), + Self::Type(bounds, idx) => { + bounds.encode(sink); + idx.encode(sink); + } + } + } +} + +/// An encoder for the import section of WebAssembly components. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{Component, ComponentTypeSection, PrimitiveValType, ComponentImportSection, ComponentTypeRef}; +/// +/// let mut types = ComponentTypeSection::new(); +/// +/// // Define a function type of `[string, string] -> string`. +/// types +/// .function() +/// .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, url: &str, ty: ComponentTypeRef) -> &mut Self { + name.encode(&mut self.bytes); + url.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() + } +} 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..5f2c97dec3 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/instances.rs @@ -0,0 +1,199 @@ +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 { + 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..0e3b02dc2e --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/names.rs @@ -0,0 +1,147 @@ +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", + data: &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..930467d57a --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/types.rs @@ -0,0 +1,736 @@ +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 { + self.bytes.push(0x00); + module.encode(&mut self.bytes); + name.encode(&mut self.bytes); + ty.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Define a type in this module type. + /// + /// The returned encoder must be used before adding another definition. + #[must_use = "the encoder must be used to encode the type"] + pub fn ty(&mut self) -> CoreTypeEncoder { + self.bytes.push(0x01); + self.num_added += 1; + self.types_added += 1; + CoreTypeEncoder(&mut self.bytes) + } + + /// Defines an 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, +} + +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, + _ => {} + } + self + } + + /// Defines an import in this component type. + pub fn import(&mut self, name: &str, url: &str, ty: ComponentTypeRef) -> &mut Self { + self.bytes.push(0x03); + name.encode(&mut self.bytes); + url.encode(&mut self.bytes); + ty.encode(&mut self.bytes); + self.num_added += 1; + match ty { + ComponentTypeRef::Type(..) => self.types_added += 1, + _ => {} + } + self + } + + /// Defines an export in this component type. + pub fn export(&mut self, name: &str, url: &str, ty: ComponentTypeRef) -> &mut Self { + self.bytes.push(0x04); + name.encode(&mut self.bytes); + url.encode(&mut self.bytes); + ty.encode(&mut self.bytes); + self.num_added += 1; + match ty { + ComponentTypeRef::Type(..) => self.types_added += 1, + _ => {} + } + self + } + + /// Gets the number of core types that have been added to this component type. + pub fn core_type_count(&self) -> u32 { + self.core_types_added + } + + /// Gets the number of types that have been added or aliased in this component type. + pub fn type_count(&self) -> u32 { + self.types_added + } +} + +impl Encode for ComponentType { + fn encode(&self, sink: &mut Vec<u8>) { + sink.push(0x41); + self.num_added.encode(sink); + sink.extend(&self.bytes); + } +} + +/// Represents an instance type. +#[derive(Debug, Clone, Default)] +pub struct InstanceType(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, url: &str, ty: ComponentTypeRef) -> &mut Self { + self.0.export(name, url, 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 + } + + /// 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) + } +} + +/// 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, + }); + } +} + +/// 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 a union type. + pub fn union<I, T>(self, types: I) + where + I: IntoIterator<Item = T>, + I::IntoIter: ExactSizeIterator, + T: Into<ComponentValType>, + { + let types = types.into_iter(); + self.0.push(0x6C); + types.len().encode(self.0); + for ty in types { + ty.into().encode(self.0); + } + } + + /// Define an option type. + pub fn option(self, ty: impl Into<ComponentValType>) { + self.0.push(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); + } +} + +/// 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() + } +} + +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() + } +} |