use crate::*; use anyhow::{anyhow, bail}; use indexmap::IndexSet; use std::mem; use std::{collections::HashMap, io::Read}; use wasmparser::Chunk; use wasmparser::{ component_types::{ ComponentAnyTypeId, ComponentDefinedType, ComponentEntityType, ComponentFuncType, ComponentInstanceType, ComponentType, ComponentValType, }, names::{ComponentName, ComponentNameKind}, types, types::Types, ComponentExternalKind, Parser, Payload, PrimitiveValType, ValidPayload, Validator, }; /// Represents information about a decoded WebAssembly component. struct ComponentInfo { /// Wasmparser-defined type information learned after a component is fully /// validated. types: types::Types, /// List of all imports and exports from this component. externs: Vec<(String, Extern)>, /// Decoded package metadata package_metadata: Option, } struct DecodingExport { name: String, kind: ComponentExternalKind, index: u32, } enum Extern { Import(String), Export(DecodingExport), } #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum WitEncodingVersion { V1, V2, } impl ComponentInfo { /// Creates a new component info by parsing the given WebAssembly component bytes. fn from_reader(mut reader: impl Read) -> Result { let mut validator = Validator::new(); let mut externs = Vec::new(); let mut depth = 1; let mut types = None; let mut _package_metadata = None; let mut cur = Parser::new(0); let mut eof = false; let mut stack = Vec::new(); let mut buffer = Vec::new(); loop { let chunk = cur.parse(&buffer, eof)?; let (payload, consumed) = match chunk { Chunk::NeedMoreData(hint) => { assert!(!eof); // otherwise an error would be returned // Use the hint to preallocate more space, then read // some more data into our buffer. // // Note that the buffer management here is not ideal, // but it's compact enough to fit in an example! let len = buffer.len(); buffer.extend((0..hint).map(|_| 0u8)); let n = reader.read(&mut buffer[len..])?; buffer.truncate(len + n); eof = n == 0; continue; } Chunk::Parsed { consumed, payload } => (payload, consumed), }; match validator.payload(&payload)? { ValidPayload::Ok => {} ValidPayload::Parser(_) => depth += 1, ValidPayload::End(t) => { depth -= 1; if depth == 0 { types = Some(t); } } ValidPayload::Func(..) => {} } match payload { Payload::ComponentImportSection(s) if depth == 1 => { for import in s { let import = import?; externs.push(( import.name.0.to_string(), Extern::Import(import.name.0.to_string()), )); } } Payload::ComponentExportSection(s) if depth == 1 => { for export in s { let export = export?; externs.push(( export.name.0.to_string(), Extern::Export(DecodingExport { name: export.name.0.to_string(), kind: export.kind, index: export.index, }), )); } } #[cfg(feature = "serde")] Payload::CustomSection(s) if s.name() == PackageMetadata::SECTION_NAME => { if _package_metadata.is_some() { bail!("multiple {:?} sections", PackageMetadata::SECTION_NAME); } _package_metadata = Some(PackageMetadata::decode(s.data())?); } Payload::ModuleSection { parser, .. } | Payload::ComponentSection { parser, .. } => { stack.push(cur.clone()); cur = parser.clone(); } Payload::End(_) => { if let Some(parent_parser) = stack.pop() { cur = parent_parser.clone(); } else { break; } } _ => {} } // once we're done processing the payload we can forget the // original. buffer.drain(..consumed); } Ok(Self { types: types.unwrap(), externs, package_metadata: _package_metadata, }) } fn is_wit_package(&self) -> Option { // all wit package exports must be component types, and there must be at // least one if self.externs.is_empty() { return None; } if !self.externs.iter().all(|(_, item)| { let export = match item { Extern::Export(e) => e, _ => return false, }; match export.kind { ComponentExternalKind::Type => matches!( self.types.as_ref().component_any_type_at(export.index), ComponentAnyTypeId::Component(_) ), _ => false, } }) { return None; } // The distinction between v1 and v2 encoding formats is the structure of the export // strings for each component. The v1 format uses ":/wit" as the name // for the top-level exports, while the v2 format uses the unqualified name of the encoded // entity. match ComponentName::new(&self.externs[0].0, 0).ok()?.kind() { ComponentNameKind::Interface(name) if name.interface().as_str() == "wit" => { Some(WitEncodingVersion::V1) } ComponentNameKind::Label(_) => Some(WitEncodingVersion::V2), _ => None, } } fn decode_wit_v1_package(&self) -> Result<(Resolve, PackageId)> { let mut decoder = WitPackageDecoder::new(&self.types); let mut pkg = None; for (name, item) in self.externs.iter() { let export = match item { Extern::Export(e) => e, _ => unreachable!(), }; let id = self.types.as_ref().component_type_at(export.index); let ty = &self.types[id]; if pkg.is_some() { bail!("more than one top-level exported component type found"); } let name = ComponentName::new(name, 0).unwrap(); pkg = Some( decoder .decode_v1_package(&name, ty) .with_context(|| format!("failed to decode document `{name}`"))?, ); } let pkg = pkg.ok_or_else(|| anyhow!("no exported component type found"))?; let (mut resolve, package) = decoder.finish(pkg); if let Some(package_metadata) = &self.package_metadata { package_metadata.inject(&mut resolve, package)?; } Ok((resolve, package)) } fn decode_wit_v2_package(&self) -> Result<(Resolve, PackageId)> { let mut decoder = WitPackageDecoder::new(&self.types); let mut pkg_name = None; let mut interfaces = IndexMap::new(); let mut worlds = IndexMap::new(); let mut fields = PackageFields { interfaces: &mut interfaces, worlds: &mut worlds, }; for (_, item) in self.externs.iter() { let export = match item { Extern::Export(e) => e, _ => unreachable!(), }; let index = export.index; let id = self.types.as_ref().component_type_at(index); let component = &self.types[id]; // The single export of this component will determine if it's a world or an interface: // worlds export a component, while interfaces export an instance. if component.exports.len() != 1 { bail!( "Expected a single export, but found {} instead", component.exports.len() ); } let name = component.exports.keys().nth(0).unwrap(); let name = match component.exports[name] { ComponentEntityType::Component(ty) => { let package_name = decoder.decode_world(name.as_str(), &self.types[ty], &mut fields)?; package_name } ComponentEntityType::Instance(ty) => { let package_name = decoder.decode_interface( name.as_str(), &component.imports, &self.types[ty], &mut fields, )?; package_name } _ => unreachable!(), }; if let Some(pkg_name) = pkg_name.as_ref() { // TODO: when we have fully switched to the v2 format, we should switch to parsing // multiple wit documents instead of bailing. if pkg_name != &name { bail!("item defined with mismatched package name") } } else { pkg_name.replace(name); } } let pkg = if let Some(name) = pkg_name { Package { name, docs: Docs::default(), interfaces, worlds, } } else { bail!("no exported component type found"); }; let (mut resolve, package) = decoder.finish(pkg); if let Some(package_metadata) = &self.package_metadata { package_metadata.inject(&mut resolve, package)?; } Ok((resolve, package)) } fn decode_component(&self) -> Result<(Resolve, WorldId)> { assert!(self.is_wit_package().is_none()); let mut decoder = WitPackageDecoder::new(&self.types); // Note that this name is arbitrarily chosen. We may one day perhaps // want to encode this in the component binary format itself, but for // now it shouldn't be an issue to have a defaulted name here. let world_name = "root"; let world = decoder.resolve.worlds.alloc(World { name: world_name.to_string(), docs: Default::default(), imports: Default::default(), exports: Default::default(), package: None, includes: Default::default(), include_names: Default::default(), stability: Default::default(), }); let mut package = Package { // Similar to `world_name` above this is arbitrarily chosen as it's // not otherwise encoded in a binary component. This theoretically // shouldn't cause issues, however. name: PackageName { namespace: "root".to_string(), version: None, name: "component".to_string(), }, docs: Default::default(), worlds: [(world_name.to_string(), world)].into_iter().collect(), interfaces: Default::default(), }; let mut fields = PackageFields { worlds: &mut package.worlds, interfaces: &mut package.interfaces, }; for (_name, item) in self.externs.iter() { match item { Extern::Import(import) => { decoder.decode_component_import(import, world, &mut fields)? } Extern::Export(export) => { decoder.decode_component_export(export, world, &mut fields)? } } } let (resolve, _) = decoder.finish(package); Ok((resolve, world)) } } /// Result of the [`decode`] function. pub enum DecodedWasm { /// The input to [`decode`] was one or more binary-encoded WIT package(s). /// /// The full resolve graph is here plus the identifier of the packages that /// were encoded. Note that other packages may be within the resolve if any /// of the main packages refer to other, foreign packages. WitPackage(Resolve, PackageId), /// The input to [`decode`] was a component and its interface is specified /// by the world here. Component(Resolve, WorldId), } impl DecodedWasm { /// Returns the [`Resolve`] for WIT types contained. pub fn resolve(&self) -> &Resolve { match self { DecodedWasm::WitPackage(resolve, _) => resolve, DecodedWasm::Component(resolve, _) => resolve, } } /// Returns the main packages of what was decoded. pub fn package(&self) -> PackageId { match self { DecodedWasm::WitPackage(_, id) => *id, DecodedWasm::Component(resolve, world) => resolve.worlds[*world].package.unwrap(), } } } /// Decode for incremental reading pub fn decode_reader(reader: impl Read) -> Result { let info = ComponentInfo::from_reader(reader)?; if let Some(version) = info.is_wit_package() { match version { WitEncodingVersion::V1 => { log::debug!("decoding a v1 WIT package encoded as wasm"); let (resolve, pkg) = info.decode_wit_v1_package()?; Ok(DecodedWasm::WitPackage(resolve, pkg)) } WitEncodingVersion::V2 => { log::debug!("decoding a v2 WIT package encoded as wasm"); let (resolve, pkg) = info.decode_wit_v2_package()?; Ok(DecodedWasm::WitPackage(resolve, pkg)) } } } else { log::debug!("inferring the WIT of a concrete component"); let (resolve, world) = info.decode_component()?; Ok(DecodedWasm::Component(resolve, world)) } } /// Decodes an in-memory WebAssembly binary into a WIT [`Resolve`] and /// associated metadata. /// /// The WebAssembly binary provided here can either be a /// WIT-package-encoded-as-binary or an actual component itself. A [`Resolve`] /// is always created and the return value indicates which was detected. pub fn decode(bytes: &[u8]) -> Result { decode_reader(bytes) } /// Decodes the single component type `world` specified as a WIT world. /// /// The `world` should be an exported component type. The `world` must have been /// previously created via `encode_world` meaning that it is a component that /// itself imports nothing and exports a single component, and the single /// component export represents the world. The name of the export is also the /// name of the package/world/etc. pub fn decode_world(wasm: &[u8]) -> Result<(Resolve, WorldId)> { let mut validator = Validator::new(); let mut exports = Vec::new(); let mut depth = 1; let mut types = None; for payload in Parser::new(0).parse_all(wasm) { let payload = payload?; match validator.payload(&payload)? { ValidPayload::Ok => {} ValidPayload::Parser(_) => depth += 1, ValidPayload::End(t) => { depth -= 1; if depth == 0 { types = Some(t); } } ValidPayload::Func(..) => {} } match payload { Payload::ComponentExportSection(s) if depth == 1 => { for export in s { exports.push(export?); } } _ => {} } } if exports.len() != 1 { bail!("expected one export in component"); } if exports[0].kind != ComponentExternalKind::Type { bail!("expected an export of a type"); } if exports[0].ty.is_some() { bail!("expected an un-ascribed exported type"); } let types = types.as_ref().unwrap(); let world = match types.as_ref().component_any_type_at(exports[0].index) { ComponentAnyTypeId::Component(c) => c, _ => bail!("expected an exported component type"), }; let mut decoder = WitPackageDecoder::new(types); let mut interfaces = IndexMap::new(); let mut worlds = IndexMap::new(); let ty = &types[world]; assert_eq!(ty.imports.len(), 0); assert_eq!(ty.exports.len(), 1); let name = ty.exports.keys().nth(0).unwrap(); let ty = match ty.exports[0] { ComponentEntityType::Component(ty) => ty, _ => unreachable!(), }; let name = decoder.decode_world( name, &types[ty], &mut PackageFields { interfaces: &mut interfaces, worlds: &mut worlds, }, )?; let (resolve, pkg) = decoder.finish(Package { name, interfaces, worlds, docs: Default::default(), }); // The package decoded here should only have a single world so extract that // here to return. let world = *resolve.packages[pkg].worlds.iter().next().unwrap().1; Ok((resolve, world)) } struct PackageFields<'a> { interfaces: &'a mut IndexMap, worlds: &'a mut IndexMap, } struct WitPackageDecoder<'a> { resolve: Resolve, types: &'a Types, foreign_packages: IndexMap, iface_to_package_index: HashMap, named_interfaces: HashMap, /// A map which tracks named resources to what their corresponding `TypeId` /// is. This first layer of key in this map is the owner scope of a /// resource, more-or-less the `world` or `interface` that it's defined /// within. The second layer of this map is keyed by name of the resource /// and points to the actual ID of the resource. /// /// This map is populated in `register_type_export`. resources: HashMap>, /// A map from a type id to what it's been translated to. type_map: HashMap, } impl WitPackageDecoder<'_> { fn new<'a>(types: &'a Types) -> WitPackageDecoder<'a> { WitPackageDecoder { resolve: Resolve::default(), types, type_map: HashMap::new(), foreign_packages: Default::default(), iface_to_package_index: Default::default(), named_interfaces: Default::default(), resources: Default::default(), } } fn decode_v1_package(&mut self, name: &ComponentName, ty: &ComponentType) -> Result { // Process all imports for this package first, where imports are // importing from remote packages. for (name, ty) in ty.imports.iter() { let ty = match ty { ComponentEntityType::Instance(idx) => &self.types[*idx], _ => bail!("import `{name}` is not an instance"), }; self.register_import(name, ty) .with_context(|| format!("failed to process import `{name}`"))?; } let mut package = Package { // The name encoded for packages must be of the form `foo:bar/wit` // where "wit" is just a placeholder for now. The package name in // this case would be `foo:bar`. name: match name.kind() { ComponentNameKind::Interface(name) if name.interface().as_str() == "wit" => { name.to_package_name() } _ => bail!("package name is not a valid id: {name}"), }, docs: Default::default(), interfaces: Default::default(), worlds: Default::default(), }; let mut fields = PackageFields { interfaces: &mut package.interfaces, worlds: &mut package.worlds, }; for (name, ty) in ty.exports.iter() { match ty { ComponentEntityType::Instance(idx) => { let ty = &self.types[*idx]; self.register_interface(name.as_str(), ty, &mut fields) .with_context(|| format!("failed to process export `{name}`"))?; } ComponentEntityType::Component(idx) => { let ty = &self.types[*idx]; self.register_world(name.as_str(), ty, &mut fields) .with_context(|| format!("failed to process export `{name}`"))?; } _ => bail!("component export `{name}` is not an instance or component"), } } Ok(package) } fn decode_interface<'a>( &mut self, name: &str, imports: &wasmparser::collections::IndexMap, ty: &ComponentInstanceType, fields: &mut PackageFields<'a>, ) -> Result { let component_name = self .parse_component_name(name) .context("expected world name to have an ID form")?; let package = match component_name.kind() { ComponentNameKind::Interface(name) => name.to_package_name(), _ => bail!("expected world name to be fully qualified"), }; for (name, ty) in imports.iter() { let ty = match ty { ComponentEntityType::Instance(idx) => &self.types[*idx], _ => bail!("import `{name}` is not an instance"), }; self.register_import(name, ty) .with_context(|| format!("failed to process import `{name}`"))?; } let _ = self.register_interface(name, ty, fields)?; Ok(package) } fn decode_world<'a>( &mut self, name: &str, ty: &ComponentType, fields: &mut PackageFields<'a>, ) -> Result { let kebab_name = self .parse_component_name(name) .context("expected world name to have an ID form")?; let package = match kebab_name.kind() { ComponentNameKind::Interface(name) => name.to_package_name(), _ => bail!("expected world name to be fully qualified"), }; let _ = self.register_world(name, ty, fields)?; Ok(package) } fn decode_component_import<'a>( &mut self, name: &str, world: WorldId, package: &mut PackageFields<'a>, ) -> Result<()> { log::debug!("decoding component import `{name}`"); let ty = self .types .as_ref() .component_entity_type_of_import(name) .unwrap(); let owner = TypeOwner::World(world); let (name, item) = match ty { ComponentEntityType::Instance(i) => { let ty = &self.types[i]; let (name, id) = if name.contains('/') { let id = self.register_import(name, ty)?; (WorldKey::Interface(id), id) } else { self.register_interface(name, ty, package) .with_context(|| format!("failed to decode WIT from import `{name}`"))? }; ( name, WorldItem::Interface { id, stability: Default::default(), }, ) } ComponentEntityType::Func(i) => { let ty = &self.types[i]; let func = self .convert_function(name, ty, owner) .with_context(|| format!("failed to decode function from import `{name}`"))?; (WorldKey::Name(name.to_string()), WorldItem::Function(func)) } ComponentEntityType::Type { referenced, created, } => { let id = self .register_type_export(name, owner, referenced, created) .with_context(|| format!("failed to decode type from export `{name}`"))?; (WorldKey::Name(name.to_string()), WorldItem::Type(id)) } // All other imports do not form part of the component's world _ => return Ok(()), }; self.resolve.worlds[world].imports.insert(name, item); Ok(()) } fn decode_component_export<'a>( &mut self, export: &DecodingExport, world: WorldId, package: &mut PackageFields<'a>, ) -> Result<()> { let name = &export.name; log::debug!("decoding component export `{name}`"); let types = self.types.as_ref(); let ty = types.component_entity_type_of_export(name).unwrap(); let (name, item) = match ty { ComponentEntityType::Func(i) => { let ty = &types[i]; let func = self .convert_function(name, ty, TypeOwner::World(world)) .with_context(|| format!("failed to decode function from export `{name}`"))?; (WorldKey::Name(name.to_string()), WorldItem::Function(func)) } ComponentEntityType::Instance(i) => { let ty = &types[i]; let (name, id) = if name.contains('/') { let id = self.register_import(name, ty)?; (WorldKey::Interface(id), id) } else { self.register_interface(name, ty, package) .with_context(|| format!("failed to decode WIT from export `{name}`"))? }; ( name, WorldItem::Interface { id, stability: Default::default(), }, ) } _ => { bail!("component export `{name}` was not a function or instance") } }; self.resolve.worlds[world].exports.insert(name, item); Ok(()) } /// Registers that the `name` provided is either imported interface from a /// foreign package or referencing a previously defined interface in this /// package. /// /// This function will internally ensure that `name` is well-structured and /// will fill in any information as necessary. For example with a foreign /// dependency the foreign package structure, types, etc, all need to be /// created. For a local dependency it's instead ensured that all the types /// line up with the previous definitions. fn register_import(&mut self, name: &str, ty: &ComponentInstanceType) -> Result { let (is_local, interface) = match self.named_interfaces.get(name) { Some(id) => (true, *id), None => (false, self.extract_dep_interface(name)?), }; let owner = TypeOwner::Interface(interface); for (name, ty) in ty.exports.iter() { log::debug!("decoding import instance export `{name}`"); match *ty { ComponentEntityType::Type { referenced, created, } => { match self.resolve.interfaces[interface] .types .get(name.as_str()) .copied() { // If this name is already defined as a type in the // specified interface then that's ok. For package-local // interfaces that's expected since the interface was // fully defined. For remote interfaces it means we're // using something that was already used elsewhere. In // both cases continue along. // // Notably for the remotely defined case this will also // walk over the structure of the type and register // internal wasmparser ids with wit-parser ids. This is // necessary to ensure that anonymous types like // `list` defined in original definitions are // unified with anonymous types when duplicated inside // of worlds. Overall this prevents, for example, extra // `list` types from popping up when decoding. This // is not strictly necessary but assists with // roundtripping assertions during fuzzing. Some(id) => { log::debug!("type already exist"); match referenced { ComponentAnyTypeId::Defined(ty) => { self.register_defined(id, &self.types[ty])?; } ComponentAnyTypeId::Resource(_) => {} _ => unreachable!(), } let prev = self.type_map.insert(created, id); assert!(prev.is_none()); } // If the name is not defined, however, then there's two // possibilities: // // * For package-local interfaces this is an error // because the package-local interface defined // everything already and this is referencing // something that isn't defined. // // * For remote interfaces they're never fully declared // so it's lazily filled in here. This means that the // view of remote interfaces ends up being the minimal // slice needed for this resolve, which is what's // intended. None => { if is_local { bail!("instance type export `{name}` not defined in interface"); } let id = self.register_type_export( name.as_str(), owner, referenced, created, )?; let prev = self.resolve.interfaces[interface] .types .insert(name.to_string(), id); assert!(prev.is_none()); } } } // This has similar logic to types above where we lazily fill in // functions for remote dependencies and otherwise assert // they're already defined for local dependencies. ComponentEntityType::Func(ty) => { let def = &self.types[ty]; if self.resolve.interfaces[interface] .functions .contains_key(name.as_str()) { // TODO: should ideally verify that function signatures // match. continue; } if is_local { bail!("instance function export `{name}` not defined in interface"); } let func = self.convert_function(name.as_str(), def, owner)?; let prev = self.resolve.interfaces[interface] .functions .insert(name.to_string(), func); assert!(prev.is_none()); } _ => bail!("instance type export `{name}` is not a type"), } } Ok(interface) } fn find_alias(&self, id: ComponentAnyTypeId) -> Option { // Consult `type_map` for `referenced` or anything in its // chain of aliases to determine what it maps to. This may // bottom out in `None` in the case that this type is // just now being defined, but this should otherwise follow // chains of aliases to determine what exactly this was a // `use` of if it exists. let mut prev = None; let mut cur = id; while prev.is_none() { prev = self.type_map.get(&cur).copied(); cur = match self.types.as_ref().peel_alias(cur) { Some(next) => next, None => break, }; } prev } /// This will parse the `name_string` as a component model ID string and /// ensure that there's an `InterfaceId` corresponding to its components. fn extract_dep_interface(&mut self, name_string: &str) -> Result { let name = ComponentName::new(name_string, 0).unwrap(); let name = match name.kind() { ComponentNameKind::Interface(name) => name, _ => bail!("package name is not a valid id: {name_string}"), }; let package_name = name.to_package_name(); // Lazily create a `Package` as necessary, along with the interface. let package = self .foreign_packages .entry(package_name.to_string()) .or_insert_with(|| Package { name: package_name.clone(), docs: Default::default(), interfaces: Default::default(), worlds: Default::default(), }); let interface = *package .interfaces .entry(name.interface().to_string()) .or_insert_with(|| { self.resolve.interfaces.alloc(Interface { name: Some(name.interface().to_string()), docs: Default::default(), types: IndexMap::default(), functions: IndexMap::new(), package: None, stability: Default::default(), }) }); // Record a mapping of which foreign package this interface belongs to self.iface_to_package_index.insert( interface, self.foreign_packages .get_full(&package_name.to_string()) .unwrap() .0, ); Ok(interface) } /// A general-purpose helper function to translate a component instance /// into a WIT interface. /// /// This is one of the main workhorses of this module. This handles /// interfaces both at the type level, for concrete components, and /// internally within worlds as well. /// /// The `name` provided is the contextual ID or name of the interface. This /// could be a kebab-name in the case of a world import or export or it can /// also be an ID. This is used to guide insertion into various maps. /// /// The `ty` provided is the actual component type being decoded. /// /// The `package` is where to insert the final interface if `name` is an ID /// meaning it's registered as a named standalone item within the package. fn register_interface<'a>( &mut self, name: &str, ty: &ComponentInstanceType, package: &mut PackageFields<'a>, ) -> Result<(WorldKey, InterfaceId)> { // If this interface's name is already known then that means this is an // interface that's both imported and exported. Use `register_import` // to draw connections between types and this interface's types. if self.named_interfaces.contains_key(name) { let id = self.register_import(name, ty)?; return Ok((WorldKey::Interface(id), id)); } // If this is a bare kebab-name for an interface then the interface's // listed name is `None` and the name goes out through the key. // Otherwise this name is extracted from `name` interpreted as an ID. let interface_name = self.extract_interface_name_from_component_name(name)?; let mut interface = Interface { name: interface_name.clone(), docs: Default::default(), types: IndexMap::default(), functions: IndexMap::new(), package: None, stability: Default::default(), }; let owner = TypeOwner::Interface(self.resolve.interfaces.next_id()); for (name, ty) in ty.exports.iter() { match *ty { ComponentEntityType::Type { referenced, created, } => { let ty = self .register_type_export(name.as_str(), owner, referenced, created) .with_context(|| format!("failed to register type export '{name}'"))?; let prev = interface.types.insert(name.to_string(), ty); assert!(prev.is_none()); } ComponentEntityType::Func(ty) => { let ty = &self.types[ty]; let func = self .convert_function(name.as_str(), ty, owner) .with_context(|| format!("failed to convert function '{name}'"))?; let prev = interface.functions.insert(name.to_string(), func); assert!(prev.is_none()); } _ => bail!("instance type export `{name}` is not a type or function"), }; } let id = self.resolve.interfaces.alloc(interface); let key = match interface_name { // If this interface is named then it's part of the package, so // insert it. Additionally register it in `named_interfaces` so // further use comes back to this original definition. Some(interface_name) => { let prev = package.interfaces.insert(interface_name, id); assert!(prev.is_none(), "duplicate interface added for {name:?}"); let prev = self.named_interfaces.insert(name.to_string(), id); assert!(prev.is_none()); WorldKey::Interface(id) } // If this interface isn't named then its key is always a // kebab-name. None => WorldKey::Name(name.to_string()), }; Ok((key, id)) } fn parse_component_name(&self, name: &str) -> Result { ComponentName::new(name, 0) .with_context(|| format!("cannot extract item name from: {name}")) } fn extract_interface_name_from_component_name(&self, name: &str) -> Result> { let component_name = self.parse_component_name(name)?; match component_name.kind() { ComponentNameKind::Interface(name) => Ok(Some(name.interface().to_string())), ComponentNameKind::Label(_name) => Ok(None), _ => bail!("cannot extract item name from: {name}"), } } fn register_type_export( &mut self, name: &str, owner: TypeOwner, referenced: ComponentAnyTypeId, created: ComponentAnyTypeId, ) -> Result { let kind = match self.find_alias(referenced) { // If this `TypeId` points to a type which has // previously been defined, meaning we're aliasing a // prior definition. Some(prev) => { log::debug!("type export for `{name}` is an alias"); TypeDefKind::Type(Type::Id(prev)) } // ... or this `TypeId`'s source definition has never // been seen before, so declare the full type. None => { log::debug!("type export for `{name}` is a new type"); match referenced { ComponentAnyTypeId::Defined(ty) => self .convert_defined(&self.types[ty]) .context("failed to convert unaliased type")?, ComponentAnyTypeId::Resource(_) => TypeDefKind::Resource, _ => unreachable!(), } } }; let ty = self.resolve.types.alloc(TypeDef { name: Some(name.to_string()), kind, docs: Default::default(), stability: Default::default(), owner, }); // If this is a resource then doubly-register it in `self.resources` so // the ID allocated here can be looked up via name later on during // `convert_function`. if let TypeDefKind::Resource = self.resolve.types[ty].kind { let prev = self .resources .entry(owner) .or_insert(HashMap::new()) .insert(name.to_string(), ty); assert!(prev.is_none()); } let prev = self.type_map.insert(created, ty); assert!(prev.is_none()); Ok(ty) } fn register_world<'a>( &mut self, name: &str, ty: &ComponentType, package: &mut PackageFields<'a>, ) -> Result { let name = self .extract_interface_name_from_component_name(name)? .context("expected world name to have an ID form")?; let mut world = World { name: name.clone(), docs: Default::default(), imports: Default::default(), exports: Default::default(), includes: Default::default(), include_names: Default::default(), package: None, stability: Default::default(), }; let owner = TypeOwner::World(self.resolve.worlds.next_id()); for (name, ty) in ty.imports.iter() { let (name, item) = match ty { ComponentEntityType::Instance(idx) => { let ty = &self.types[*idx]; let (name, id) = if name.contains('/') { // If a name is an interface import then it is either to // a package-local or foreign interface, and both // situations are handled in `register_import`. let id = self.register_import(name, ty)?; (WorldKey::Interface(id), id) } else { // A plain kebab-name indicates an inline interface that // wasn't declared explicitly elsewhere with a name, and // `register_interface` will create a new `Interface` // with no name. self.register_interface(name, ty, package)? }; ( name, WorldItem::Interface { id, stability: Default::default(), }, ) } ComponentEntityType::Type { created, referenced, } => { let ty = self.register_type_export(name.as_str(), owner, *referenced, *created)?; (WorldKey::Name(name.to_string()), WorldItem::Type(ty)) } ComponentEntityType::Func(idx) => { let ty = &self.types[*idx]; let func = self.convert_function(name.as_str(), ty, owner)?; (WorldKey::Name(name.to_string()), WorldItem::Function(func)) } _ => bail!("component import `{name}` is not an instance, func, or type"), }; world.imports.insert(name, item); } for (name, ty) in ty.exports.iter() { let (name, item) = match ty { ComponentEntityType::Instance(idx) => { let ty = &self.types[*idx]; let (name, id) = if name.contains('/') { // Note that despite this being an export this is // calling `register_import`. With a URL this interface // must have been previously defined so this will // trigger the logic of either filling in a remotely // defined interface or connecting items to local // definitions of our own interface. let id = self.register_import(name, ty)?; (WorldKey::Interface(id), id) } else { self.register_interface(name, ty, package)? }; ( name, WorldItem::Interface { id, stability: Default::default(), }, ) } ComponentEntityType::Func(idx) => { let ty = &self.types[*idx]; let func = self.convert_function(name.as_str(), ty, owner)?; (WorldKey::Name(name.to_string()), WorldItem::Function(func)) } _ => bail!("component export `{name}` is not an instance or function"), }; world.exports.insert(name, item); } let id = self.resolve.worlds.alloc(world); let prev = package.worlds.insert(name, id); assert!(prev.is_none()); Ok(id) } fn convert_function( &mut self, name: &str, ty: &ComponentFuncType, owner: TypeOwner, ) -> Result { let name = ComponentName::new(name, 0).unwrap(); let params = ty .params .iter() .map(|(name, ty)| Ok((name.to_string(), self.convert_valtype(ty)?))) .collect::>>() .context("failed to convert params")?; let results = if ty.results.len() == 1 && ty.results[0].0.is_none() { Results::Anon( self.convert_valtype(&ty.results[0].1) .context("failed to convert anonymous result type")?, ) } else { Results::Named( ty.results .iter() .map(|(name, ty)| { Ok(( name.as_ref().unwrap().to_string(), self.convert_valtype(ty)?, )) }) .collect::>>() .context("failed to convert named result types")?, ) }; Ok(Function { docs: Default::default(), stability: Default::default(), kind: match name.kind() { ComponentNameKind::Label(_) => FunctionKind::Freestanding, ComponentNameKind::Constructor(resource) => { FunctionKind::Constructor(self.resources[&owner][resource.as_str()]) } ComponentNameKind::Method(name) => { FunctionKind::Method(self.resources[&owner][name.resource().as_str()]) } ComponentNameKind::Static(name) => { FunctionKind::Static(self.resources[&owner][name.resource().as_str()]) } // Functions shouldn't have ID-based names at this time. ComponentNameKind::Interface(_) | ComponentNameKind::Url(_) | ComponentNameKind::Hash(_) | ComponentNameKind::Dependency(_) => unreachable!(), }, // Note that this name includes "name mangling" such as // `[method]foo.bar` which is intentional. The `FunctionKind` // discriminant calculated above indicates how to interpret this // name. name: name.to_string(), params, results, }) } fn convert_valtype(&mut self, ty: &ComponentValType) -> Result { let id = match ty { ComponentValType::Primitive(ty) => return Ok(self.convert_primitive(*ty)), ComponentValType::Type(id) => *id, }; // Don't create duplicate types for anything previously created. if let Some(ret) = self.type_map.get(&id.into()) { return Ok(Type::Id(*ret)); } // Otherwise create a new `TypeDef` without a name since this is an // anonymous valtype. Note that this is invalid for some types so return // errors on those types, but eventually the `bail!` here is // more-or-less unreachable due to expected validation to be added to // the component model binary format itself. let def = &self.types[id]; let kind = self.convert_defined(def)?; match &kind { TypeDefKind::Type(_) | TypeDefKind::List(_) | TypeDefKind::Tuple(_) | TypeDefKind::Option(_) | TypeDefKind::Result(_) | TypeDefKind::Handle(_) => {} TypeDefKind::Resource | TypeDefKind::Record(_) | TypeDefKind::Enum(_) | TypeDefKind::Variant(_) | TypeDefKind::Flags(_) | TypeDefKind::Future(_) | TypeDefKind::Stream(_) => { bail!("unexpected unnamed type of kind '{}'", kind.as_str()); } TypeDefKind::Unknown => unreachable!(), } let ty = self.resolve.types.alloc(TypeDef { name: None, docs: Default::default(), stability: Default::default(), owner: TypeOwner::None, kind, }); let prev = self.type_map.insert(id.into(), ty); assert!(prev.is_none()); Ok(Type::Id(ty)) } /// Converts a wasmparser `ComponentDefinedType`, the definition of a type /// in the component model, to a WIT `TypeDefKind` to get inserted into the /// types arena by the caller. fn convert_defined(&mut self, ty: &ComponentDefinedType) -> Result { match ty { ComponentDefinedType::Primitive(t) => Ok(TypeDefKind::Type(self.convert_primitive(*t))), ComponentDefinedType::List(t) => { let t = self.convert_valtype(t)?; Ok(TypeDefKind::List(t)) } ComponentDefinedType::Tuple(t) => { let types = t .types .iter() .map(|t| self.convert_valtype(t)) .collect::>()?; Ok(TypeDefKind::Tuple(Tuple { types })) } ComponentDefinedType::Option(t) => { let t = self.convert_valtype(t)?; Ok(TypeDefKind::Option(t)) } ComponentDefinedType::Result { ok, err } => { let ok = match ok { Some(t) => Some(self.convert_valtype(t)?), None => None, }; let err = match err { Some(t) => Some(self.convert_valtype(t)?), None => None, }; Ok(TypeDefKind::Result(Result_ { ok, err })) } ComponentDefinedType::Record(r) => { let fields = r .fields .iter() .map(|(name, ty)| { Ok(Field { name: name.to_string(), ty: self.convert_valtype(ty).with_context(|| { format!("failed to convert record field '{name}'") })?, docs: Default::default(), }) }) .collect::>()?; Ok(TypeDefKind::Record(Record { fields })) } ComponentDefinedType::Variant(v) => { let cases = v .cases .iter() .map(|(name, case)| { if case.refines.is_some() { bail!("unimplemented support for `refines`"); } Ok(Case { name: name.to_string(), ty: match &case.ty { Some(ty) => Some(self.convert_valtype(ty)?), None => None, }, docs: Default::default(), }) }) .collect::>()?; Ok(TypeDefKind::Variant(Variant { cases })) } ComponentDefinedType::Flags(f) => { let flags = f .iter() .map(|name| Flag { name: name.to_string(), docs: Default::default(), }) .collect(); Ok(TypeDefKind::Flags(Flags { flags })) } ComponentDefinedType::Enum(e) => { let cases = e .iter() .cloned() .map(|name| EnumCase { name: name.into(), docs: Default::default(), }) .collect(); Ok(TypeDefKind::Enum(Enum { cases })) } ComponentDefinedType::Own(id) => { let id = self.type_map[&(*id).into()]; Ok(TypeDefKind::Handle(Handle::Own(id))) } ComponentDefinedType::Borrow(id) => { let id = self.type_map[&(*id).into()]; Ok(TypeDefKind::Handle(Handle::Borrow(id))) } } } fn convert_primitive(&self, ty: PrimitiveValType) -> Type { match ty { PrimitiveValType::U8 => Type::U8, PrimitiveValType::S8 => Type::S8, PrimitiveValType::U16 => Type::U16, PrimitiveValType::S16 => Type::S16, PrimitiveValType::U32 => Type::U32, PrimitiveValType::S32 => Type::S32, PrimitiveValType::U64 => Type::U64, PrimitiveValType::S64 => Type::S64, PrimitiveValType::Bool => Type::Bool, PrimitiveValType::Char => Type::Char, PrimitiveValType::String => Type::String, PrimitiveValType::F32 => Type::F32, PrimitiveValType::F64 => Type::F64, } } fn register_defined(&mut self, id: TypeId, def: &ComponentDefinedType) -> Result<()> { Registrar { types: &self.types, type_map: &mut self.type_map, resolve: &self.resolve, } .defined(id, def) } /// Completes the decoding of this resolve by finalizing all packages into /// their topological ordering within the returned `Resolve`. /// /// Takes the root package as an argument to insert. fn finish(mut self, package: Package) -> (Resolve, PackageId) { // Build a topological ordering is then calculated by visiting all the // transitive dependencies of packages. let mut order = IndexSet::new(); for i in 0..self.foreign_packages.len() { self.visit_package(i, &mut order); } // Using the topological ordering create a temporary map from // index-in-`foreign_packages` to index-in-`order` let mut idx_to_pos = vec![0; self.foreign_packages.len()]; for (pos, idx) in order.iter().enumerate() { idx_to_pos[*idx] = pos; } // .. and then using `idx_to_pos` sort the `foreign_packages` array based // on the position it's at in the topological ordering let mut deps = mem::take(&mut self.foreign_packages) .into_iter() .enumerate() .collect::>(); deps.sort_by_key(|(idx, _)| idx_to_pos[*idx]); // .. and finally insert the packages, in their final topological // ordering, into the returned array. for (_idx, (_url, pkg)) in deps { self.insert_package(pkg); } let id = self.insert_package(package); assert!(self.resolve.worlds.iter().all(|(_, w)| w.package.is_some())); assert!(self .resolve .interfaces .iter() .all(|(_, i)| i.package.is_some())); (self.resolve, id) } fn insert_package(&mut self, package: Package) -> PackageId { let Package { name, interfaces, worlds, docs, } = package; // Most of the time the `package` being inserted is not already present // in `self.resolve`, but in the case of the top-level `decode_world` // function this isn't the case. This shouldn't in general be a problem // so union-up the packages here while asserting that nothing gets // replaced by accident which would indicate a bug. let pkg = self .resolve .package_names .get(&name) .copied() .unwrap_or_else(|| { let id = self.resolve.packages.alloc(Package { name: name.clone(), interfaces: Default::default(), worlds: Default::default(), docs, }); let prev = self.resolve.package_names.insert(name, id); assert!(prev.is_none()); id }); for (name, id) in interfaces { let prev = self.resolve.packages[pkg].interfaces.insert(name, id); assert!(prev.is_none()); self.resolve.interfaces[id].package = Some(pkg); } for (name, id) in worlds { let prev = self.resolve.packages[pkg].worlds.insert(name, id); assert!(prev.is_none()); let world = &mut self.resolve.worlds[id]; world.package = Some(pkg); for (name, item) in world.imports.iter().chain(world.exports.iter()) { if let WorldKey::Name(_) = name { if let WorldItem::Interface { id, .. } = item { self.resolve.interfaces[*id].package = Some(pkg); } } } } pkg } fn visit_package(&self, idx: usize, order: &mut IndexSet) { if order.contains(&idx) { return; } let (_name, pkg) = self.foreign_packages.get_index(idx).unwrap(); let interfaces = pkg.interfaces.values().copied().chain( pkg.worlds .values() .flat_map(|w| { let world = &self.resolve.worlds[*w]; world.imports.values().chain(world.exports.values()) }) .filter_map(|item| match item { WorldItem::Interface { id, .. } => Some(*id), WorldItem::Function(_) | WorldItem::Type(_) => None, }), ); for iface in interfaces { for dep in self.resolve.interface_direct_deps(iface) { let dep_idx = self.iface_to_package_index[&dep]; if dep_idx != idx { self.visit_package(dep_idx, order); } } } assert!(order.insert(idx)); } } /// Helper type to register the structure of a wasm-defined type against a /// wit-defined type. struct Registrar<'a> { types: &'a Types, type_map: &'a mut HashMap, resolve: &'a Resolve, } impl Registrar<'_> { /// Verifies that the wasm structure of `def` matches the wit structure of /// `id` and recursively registers types. fn defined(&mut self, id: TypeId, def: &ComponentDefinedType) -> Result<()> { match def { ComponentDefinedType::Primitive(_) => Ok(()), ComponentDefinedType::List(t) => { let ty = match &self.resolve.types[id].kind { TypeDefKind::List(r) => r, // Note that all cases below have this match and the general // idea is that once a type is named or otherwise identified // here there's no need to recurse. The purpose of this // registrar is to build connections for anonymous types // that don't otherwise have a name to ensure that they're // decoded to reuse the same constructs consistently. For // that reason once something is named we can bail out. TypeDefKind::Type(Type::Id(_)) => return Ok(()), _ => bail!("expected a list"), }; self.valtype(t, ty) } ComponentDefinedType::Tuple(t) => { let ty = match &self.resolve.types[id].kind { TypeDefKind::Tuple(r) => r, TypeDefKind::Type(Type::Id(_)) => return Ok(()), _ => bail!("expected a tuple"), }; if ty.types.len() != t.types.len() { bail!("mismatched number of tuple fields"); } for (a, b) in t.types.iter().zip(ty.types.iter()) { self.valtype(a, b)?; } Ok(()) } ComponentDefinedType::Option(t) => { let ty = match &self.resolve.types[id].kind { TypeDefKind::Option(r) => r, TypeDefKind::Type(Type::Id(_)) => return Ok(()), _ => bail!("expected an option"), }; self.valtype(t, ty) } ComponentDefinedType::Result { ok, err } => { let ty = match &self.resolve.types[id].kind { TypeDefKind::Result(r) => r, TypeDefKind::Type(Type::Id(_)) => return Ok(()), _ => bail!("expected a result"), }; match (ok, &ty.ok) { (Some(a), Some(b)) => self.valtype(a, b)?, (None, None) => {} _ => bail!("disagreement on result structure"), } match (err, &ty.err) { (Some(a), Some(b)) => self.valtype(a, b)?, (None, None) => {} _ => bail!("disagreement on result structure"), } Ok(()) } ComponentDefinedType::Record(def) => { let ty = match &self.resolve.types[id].kind { TypeDefKind::Record(r) => r, TypeDefKind::Type(Type::Id(_)) => return Ok(()), _ => bail!("expected a record"), }; if def.fields.len() != ty.fields.len() { bail!("mismatched number of record fields"); } for ((name, ty), field) in def.fields.iter().zip(&ty.fields) { if name.as_str() != field.name { bail!("mismatched field order"); } self.valtype(ty, &field.ty)?; } Ok(()) } ComponentDefinedType::Variant(def) => { let ty = match &self.resolve.types[id].kind { TypeDefKind::Variant(r) => r, TypeDefKind::Type(Type::Id(_)) => return Ok(()), _ => bail!("expected a variant"), }; if def.cases.len() != ty.cases.len() { bail!("mismatched number of variant cases"); } for ((name, ty), case) in def.cases.iter().zip(&ty.cases) { if name.as_str() != case.name { bail!("mismatched case order"); } match (&ty.ty, &case.ty) { (Some(a), Some(b)) => self.valtype(a, b)?, (None, None) => {} _ => bail!("disagreement on case type"), } } Ok(()) } // These have no recursive structure so they can bail out. ComponentDefinedType::Flags(_) | ComponentDefinedType::Enum(_) | ComponentDefinedType::Own(_) | ComponentDefinedType::Borrow(_) => Ok(()), } } fn valtype(&mut self, wasm: &ComponentValType, wit: &Type) -> Result<()> { let wasm = match wasm { ComponentValType::Type(wasm) => *wasm, ComponentValType::Primitive(_wasm) => { assert!(!matches!(wit, Type::Id(_))); return Ok(()); } }; let wit = match wit { Type::Id(id) => *id, _ => bail!("expected id-based type"), }; let prev = match self.type_map.insert(wasm.into(), wit) { Some(prev) => prev, None => { let wasm = &self.types[wasm]; return self.defined(wit, wasm); } }; // If `wit` matches `prev` then we've just rediscovered what we already // knew which is that the `wasm` id maps to the `wit` id. // // If, however, `wit` is not equal to `prev` then that's more // interesting. Consider a component such as: // // ```wasm // (component // (import (interface "a:b/name") (instance // (type $l (list string)) // (type $foo (variant (case "l" $l))) // (export "foo" (type (eq $foo))) // )) // (component $c // (type $l (list string)) // (type $bar (variant (case "n" u16) (case "l" $l))) // (export "bar" (type $bar)) // (type $foo (variant (case "l" $l))) // (export "foo" (type $foo)) // ) // (instance $i (instantiate $c)) // (export (interface "a:b/name") (instance $i)) // ) // ``` // // This roughly corresponds to: // // ```wit // package a:b // // interface name { // variant bar { // n(u16), // l(list), // } // // variant foo { // l(list), // } // } // // world module { // import name // export name // } // ``` // // In this situation first we'll see the `import` which records type // information for the `foo` type in `interface name`. Later on the full // picture of `interface name` becomes apparent with the export of a // component which has full type information. When walking over this // first `bar` is seen and its recursive structure. // // The problem arises when walking over the `foo` type. In this // situation the code path we're currently on will be hit because // there's a preexisting definition of `foo` from the import and it's // now going to be unified with what we've seen in the export. When // visiting the `list` case of the `foo` variant this ends up // being different than the `list` used by the `bar` variant. The // reason for this is that when visiting `bar` the wasm-defined `(list // string)` hasn't been seen before so a new type is allocated. Later // though this same wasm type is unified with the first `(list string)` // type in the `import`. // // All-in-all this ends up meaning that it's possible for `prev` to not // match `wit`. In this situation it means the decoded WIT interface // will have duplicate definitions of `list`. This is, // theoretically, not that big of a problem because the same underlying // definition is still there and the meaning of the type is the same. // This can, however, perhaps be a problem for consumers where it's // assumed that all `list` are equal and there's only one. For // example a bindings generator for C may assume that `list` // will only appear once and generate a single name for it, but with two // different types in play here it may generate two types of the same // name (or something like that). // // For now though this is left for a future refactoring. Fixing this // issue would require tracking anonymous types during type translation // so the decoding process for the `bar` export would reuse the // `list` type created from decoding the `foo` import. That's // somewhat nontrivial at this time, so it's left for a future // refactoring. let _ = prev; Ok(()) } } pub(crate) trait InterfaceNameExt { fn to_package_name(&self) -> PackageName; } impl InterfaceNameExt for wasmparser::names::InterfaceName<'_> { fn to_package_name(&self) -> PackageName { PackageName { namespace: self.namespace().to_string(), name: self.package().to_string(), version: self.version(), } } }