use crate::encoding::types::{TypeEncodingMaps, ValtypeEncoder}; use anyhow::Result; use indexmap::IndexSet; use std::collections::HashMap; use std::mem; use wasm_encoder::*; use wit_parser::*; /// Encodes the given `package` within `resolve` to a binary WebAssembly /// representation. /// /// This function is the root of the implementation of serializing a WIT package /// into a WebAssembly representation. The wasm representation serves two /// purposes: /// /// * One is to be a binary encoding of a WIT document which is ideally more /// stable than the WIT textual format itself. /// * Another is to provide a clear mapping of all WIT features into the /// component model through use of its binary representation. /// /// The `resolve` provided is a set of packages and types and such and the /// `package` argument is an ID within the world provided. The documents within /// `package` will all be encoded into the binary returned. /// /// The binary returned can be [`decode`d](crate::decode) to recover the WIT /// package provided. pub fn encode(resolve: &Resolve, package: PackageId) -> Result> { let mut component = encode_component(resolve, package)?; component.raw_custom_section(&crate::base_producers().raw_custom_section()); Ok(component.finish()) } /// Encodes the given `package` within `resolve` to a binary WebAssembly /// representation. /// /// This function is the root of the implementation of serializing a WIT package /// into a WebAssembly representation. The wasm representation serves two /// purposes: /// /// * One is to be a binary encoding of a WIT document which is ideally more /// stable than the WIT textual format itself. /// * Another is to provide a clear mapping of all WIT features into the /// component model through use of its binary representation. /// /// The `resolve` provided is a set of packages and types and such and the /// `package` argument is an ID within the world provided. The documents within /// `package` will all be encoded into the binary returned. /// /// The binary returned can be [`decode`d](crate::decode) to recover the WIT /// package provided. pub fn encode_component(resolve: &Resolve, package: PackageId) -> Result { let mut encoder = Encoder { component: ComponentBuilder::default(), resolve, package, }; encoder.run()?; let package_metadata = PackageMetadata::extract(resolve, package); encoder.component.custom_section(&CustomSection { name: PackageMetadata::SECTION_NAME.into(), data: package_metadata.encode()?.into(), }); Ok(encoder.component) } /// Encodes a `world` as a component type. pub fn encode_world(resolve: &Resolve, world_id: WorldId) -> Result { let mut component = InterfaceEncoder::new(resolve); let world = &resolve.worlds[world_id]; log::trace!("encoding world {}", world.name); // Encode the imports for (name, import) in world.imports.iter() { let name = resolve.name_world_key(name); log::trace!("encoding import {name}"); let ty = match import { WorldItem::Interface { id, .. } => { component.interface = Some(*id); let idx = component.encode_instance(*id)?; ComponentTypeRef::Instance(idx) } WorldItem::Function(f) => { component.interface = None; let idx = component.encode_func_type(resolve, f)?; ComponentTypeRef::Func(idx) } WorldItem::Type(t) => { component.interface = None; component.import_types = true; component.encode_valtype(resolve, &Type::Id(*t))?; component.import_types = false; continue; } }; component.outer.import(&name, ty); } // Encode the exports for (name, export) in world.exports.iter() { let name = resolve.name_world_key(name); log::trace!("encoding export {name}"); let ty = match export { WorldItem::Interface { id, .. } => { component.interface = Some(*id); let idx = component.encode_instance(*id)?; ComponentTypeRef::Instance(idx) } WorldItem::Function(f) => { component.interface = None; let idx = component.encode_func_type(resolve, f)?; ComponentTypeRef::Func(idx) } WorldItem::Type(_) => unreachable!(), }; component.outer.export(&name, ty); } Ok(component.outer) } struct Encoder<'a> { component: ComponentBuilder, resolve: &'a Resolve, package: PackageId, } impl Encoder<'_> { fn run(&mut self) -> Result<()> { // Encode all interfaces as component types and then export them. for (name, &id) in self.resolve.packages[self.package].interfaces.iter() { let component_ty = self.encode_interface(id)?; let ty = self.component.type_component(Some(name), &component_ty); self.component .export(name.as_ref(), ComponentExportKind::Type, ty, None); } // For each `world` encode it directly as a component and then create a // wrapper component that exports that component. for (name, &world) in self.resolve.packages[self.package].worlds.iter() { let component_ty = encode_world(self.resolve, world)?; let world = &self.resolve.worlds[world]; let mut wrapper = ComponentType::new(); wrapper.ty().component(&component_ty); let pkg = &self.resolve.packages[world.package.unwrap()]; wrapper.export(&pkg.name.interface_id(name), ComponentTypeRef::Component(0)); let ty = self.component.type_component(Some(name), &wrapper); self.component .export(name.as_ref(), ComponentExportKind::Type, ty, None); } Ok(()) } fn encode_interface(&mut self, id: InterfaceId) -> Result { // Build a set of interfaces reachable from this document, including the // interfaces in the document itself. This is used to import instances // into the component type we're encoding. Note that entire interfaces // are imported with all their types as opposed to just the needed types // in an interface for this document. That's done to assist with the // decoding process where everyone's view of a foreign document agrees // notably on the order that types are defined in to assist with // roundtripping. let mut interfaces = IndexSet::new(); self.add_live_interfaces(&mut interfaces, id); // Seed the set of used names with all exported interfaces to ensure // that imported interfaces choose different names as the import names // aren't used during decoding. let mut used_names = IndexSet::new(); for id in interfaces.iter() { let iface = &self.resolve.interfaces[*id]; if iface.package == Some(self.package) { let first = used_names.insert(iface.name.as_ref().unwrap().clone()); assert!(first); } } let mut encoder = InterfaceEncoder::new(self.resolve); for interface in interfaces { encoder.interface = Some(interface); let iface = &self.resolve.interfaces[interface]; let name = self.resolve.id_of(interface).unwrap(); if interface == id { let idx = encoder.encode_instance(interface)?; log::trace!("exporting self as {idx}"); encoder.outer.export(&name, ComponentTypeRef::Instance(idx)); } else { encoder.push_instance(); for (_, id) in iface.types.iter() { encoder.encode_valtype(self.resolve, &Type::Id(*id))?; } let instance = encoder.pop_instance(); let idx = encoder.outer.type_count(); encoder.outer.ty().instance(&instance); encoder.import_map.insert(interface, encoder.instances); encoder.instances += 1; encoder.outer.import(&name, ComponentTypeRef::Instance(idx)); } } encoder.interface = None; Ok(encoder.outer) } /// Recursively add all live interfaces reachable from `id` into the /// `interfaces` set, and then add `id` to the set. fn add_live_interfaces(&self, interfaces: &mut IndexSet, id: InterfaceId) { if interfaces.contains(&id) { return; } for id in self.resolve.interface_direct_deps(id) { self.add_live_interfaces(interfaces, id); } assert!(interfaces.insert(id)); } } struct InterfaceEncoder<'a> { resolve: &'a Resolve, outer: ComponentType, ty: Option, type_encoding_maps: TypeEncodingMaps<'a>, saved_maps: Option>, import_map: HashMap, outer_type_map: HashMap, instances: u32, import_types: bool, interface: Option, } impl InterfaceEncoder<'_> { fn new(resolve: &Resolve) -> InterfaceEncoder<'_> { InterfaceEncoder { resolve, outer: ComponentType::new(), ty: None, type_encoding_maps: Default::default(), import_map: Default::default(), outer_type_map: Default::default(), instances: 0, saved_maps: None, import_types: false, interface: None, } } fn encode_instance(&mut self, interface: InterfaceId) -> Result { self.push_instance(); let iface = &self.resolve.interfaces[interface]; let mut type_order = IndexSet::new(); for (_, id) in iface.types.iter() { self.encode_valtype(self.resolve, &Type::Id(*id))?; type_order.insert(*id); } // Sort functions based on whether or not they're associated with // resources. // // This is done here to ensure that when a WIT package is printed as WIT // then decoded, or if it's printed as Wasm then decoded, the final // result is the same. When printing via WIT resource methods are // attached to the resource types themselves meaning that they'll appear // intermingled with the rest of the types, namely first before all // other functions. The purpose of this sort is to perform a stable sort // over all functions by shuffling the resource-related functions first, // in order of when their associated resource was encoded, and putting // freestanding functions last. // // Note that this is not actually required for correctness, it's // basically here to make fuzzing happy. let mut funcs = iface.functions.iter().collect::>(); funcs.sort_by_key(|(_name, func)| match func.kind.resource() { Some(id) => type_order.get_index_of(&id).unwrap(), None => type_order.len(), }); for (name, func) in funcs { let ty = self.encode_func_type(self.resolve, func)?; self.ty .as_mut() .unwrap() .export(name, ComponentTypeRef::Func(ty)); } let instance = self.pop_instance(); let idx = self.outer.type_count(); self.outer.ty().instance(&instance); self.import_map.insert(interface, self.instances); self.instances += 1; Ok(idx) } fn push_instance(&mut self) { assert!(self.ty.is_none()); assert!(self.saved_maps.is_none()); self.saved_maps = Some(mem::take(&mut self.type_encoding_maps)); self.ty = Some(InstanceType::default()); } fn pop_instance(&mut self) -> InstanceType { let maps = self.saved_maps.take().unwrap(); self.type_encoding_maps = maps; mem::take(&mut self.ty).unwrap() } } impl<'a> ValtypeEncoder<'a> for InterfaceEncoder<'a> { fn defined_type(&mut self) -> (u32, ComponentDefinedTypeEncoder<'_>) { match &mut self.ty { Some(ty) => (ty.type_count(), ty.ty().defined_type()), None => (self.outer.type_count(), self.outer.ty().defined_type()), } } fn define_function_type(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>) { match &mut self.ty { Some(ty) => (ty.type_count(), ty.ty().function()), None => (self.outer.type_count(), self.outer.ty().function()), } } fn export_type(&mut self, index: u32, name: &'a str) -> Option { match &mut self.ty { Some(ty) => { assert!(!self.import_types); let ret = ty.type_count(); ty.export(name, ComponentTypeRef::Type(TypeBounds::Eq(index))); Some(ret) } None => { let ret = self.outer.type_count(); if self.import_types { self.outer .import(name, ComponentTypeRef::Type(TypeBounds::Eq(index))); } else { self.outer .export(name, ComponentTypeRef::Type(TypeBounds::Eq(index))); } Some(ret) } } } fn export_resource(&mut self, name: &'a str) -> u32 { let type_ref = ComponentTypeRef::Type(TypeBounds::SubResource); match &mut self.ty { Some(ty) => { assert!(!self.import_types); ty.export(name, type_ref); ty.type_count() - 1 } None => { if self.import_types { self.outer.import(name, type_ref); } else { self.outer.export(name, type_ref); } self.outer.type_count() - 1 } } } fn type_encoding_maps(&mut self) -> &mut TypeEncodingMaps<'a> { &mut self.type_encoding_maps } fn interface(&self) -> Option { self.interface } fn import_type(&mut self, owner: InterfaceId, id: TypeId) -> u32 { let ty = &self.resolve.types[id]; let instance = self.import_map[&owner]; let outer_idx = *self.outer_type_map.entry(id).or_insert_with(|| { let ret = self.outer.type_count(); self.outer.alias(Alias::InstanceExport { instance, name: ty.name.as_ref().unwrap(), kind: ComponentExportKind::Type, }); ret }); match &mut self.ty { Some(ty) => { let ret = ty.type_count(); ty.alias(Alias::Outer { count: 1, index: outer_idx, kind: ComponentOuterAliasKind::Type, }); ret } None => outer_idx, } } }