Skip to main content

wac_types/
package.rs

1use crate::{
2    CoreExtern, CoreFuncType, DefinedType, Enum, Flags, FuncType, FuncTypeId, Interface,
3    InterfaceId, ItemKind, ModuleType, ModuleTypeId, Record, Resource, ResourceAlias, ResourceId,
4    Type, Types, UsedType, ValueType, Variant, World, WorldId,
5};
6use anyhow::{bail, Context, Result};
7use indexmap::IndexMap;
8use semver::Version;
9use std::borrow::Borrow;
10use std::fmt;
11use std::{collections::HashMap, path::Path, rc::Rc};
12use wasmparser::{
13    component_types::{self as wasm},
14    names::{ComponentName, ComponentNameKind},
15    Chunk, Encoding, Parser, Payload, ValidPayload, Validator, WasmFeatures,
16};
17
18/// Represents a package key that can be used in associative containers.
19#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
20pub struct PackageKey {
21    /// The name of the package,
22    name: String,
23    /// The version of the package.
24    version: Option<Version>,
25}
26
27impl PackageKey {
28    /// Constructs a new package key from the given package reference.
29    pub fn new(package: &Package) -> Self {
30        Self {
31            name: package.name.clone(),
32            version: package.version.clone(),
33        }
34    }
35
36    /// Gets the name of the package.
37    pub fn name(&self) -> &str {
38        &self.name
39    }
40
41    /// Gets the version of the package.
42    pub fn version(&self) -> Option<&Version> {
43        self.version.as_ref()
44    }
45}
46
47impl fmt::Display for PackageKey {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        write!(f, "{name}", name = self.name)?;
50        if let Some(version) = &self.version {
51            write!(f, "@{version}")?;
52        }
53
54        Ok(())
55    }
56}
57
58/// A borrowed package key.
59#[derive(Copy, Clone, Hash, PartialEq, Eq)]
60pub struct BorrowedPackageKey<'a> {
61    /// The package name.
62    pub name: &'a str,
63    /// The optional package version.
64    pub version: Option<&'a Version>,
65}
66
67impl<'a> BorrowedPackageKey<'a> {
68    /// Constructs a new borrowed package key from the given package reference.
69    pub fn new(package: &'a Package) -> Self {
70        Self {
71            name: &package.name,
72            version: package.version.as_ref(),
73        }
74    }
75
76    /// Constructs a new borrowed package key from the given name and version.
77    pub fn from_name_and_version(name: &'a str, version: Option<&'a Version>) -> Self {
78        Self { name, version }
79    }
80
81    /// Converts the borrowed package key into an owned package key.
82    pub fn into_owned(self) -> PackageKey {
83        PackageKey {
84            name: self.name.to_owned(),
85            version: self.version.cloned(),
86        }
87    }
88}
89
90impl fmt::Display for BorrowedPackageKey<'_> {
91    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92        write!(f, "{name}", name = self.name)?;
93        if let Some(version) = self.version {
94            write!(f, "@{version}")?;
95        }
96
97        Ok(())
98    }
99}
100
101/// A trait implemented by types that can be borrowed as a package key.
102pub trait BorrowedKey {
103    /// Borrows the key as a borrowed package key.
104    fn borrowed_key(&self) -> BorrowedPackageKey<'_>;
105}
106
107impl BorrowedKey for PackageKey {
108    fn borrowed_key(&self) -> BorrowedPackageKey<'_> {
109        BorrowedPackageKey {
110            name: &self.name,
111            version: self.version.as_ref(),
112        }
113    }
114}
115
116impl BorrowedKey for BorrowedPackageKey<'_> {
117    fn borrowed_key(&self) -> BorrowedPackageKey<'_> {
118        *self
119    }
120}
121
122impl<'a> Borrow<dyn BorrowedKey + 'a> for PackageKey {
123    fn borrow(&self) -> &(dyn BorrowedKey + 'a) {
124        self
125    }
126}
127
128impl Eq for dyn BorrowedKey + '_ {}
129
130impl PartialEq for dyn BorrowedKey + '_ {
131    fn eq(&self, other: &dyn BorrowedKey) -> bool {
132        self.borrowed_key().eq(&other.borrowed_key())
133    }
134}
135
136impl std::hash::Hash for dyn BorrowedKey + '_ {
137    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
138        self.borrowed_key().hash(state)
139    }
140}
141
142/// Represents a WebAssembly component model package.
143///
144/// A package is a binary-encoded WebAssembly component.
145#[derive(Clone)]
146#[cfg_attr(feature = "serde", derive(serde::Serialize))]
147#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
148pub struct Package {
149    /// The package name.
150    name: String,
151    /// The package version.
152    version: Option<Version>,
153    /// The bytes of the package.
154    ///
155    /// The bytes are a binary-encoded WebAssembly component.
156    #[cfg_attr(feature = "serde", serde(skip))]
157    bytes: Vec<u8>,
158    /// The type of the represented component.
159    ty: WorldId,
160    /// The type resulting from instantiating the component.
161    instance_type: InterfaceId,
162    /// Defined interfaces and worlds (from a WIT package).
163    definitions: IndexMap<String, ItemKind>,
164}
165
166impl Package {
167    /// Gets the package key for the package.
168    pub fn key(&self) -> BorrowedPackageKey<'_> {
169        BorrowedPackageKey::new(self)
170    }
171
172    /// Creates a new package from the given file path.
173    ///
174    /// The package will populate its types into the provided type collection.
175    pub fn from_file(
176        name: &str,
177        version: Option<&Version>,
178        path: impl AsRef<Path>,
179        types: &mut Types,
180    ) -> Result<Self> {
181        let path = path.as_ref();
182        let bytes = std::fs::read(path)
183            .with_context(|| format!("failed to read `{path}`", path = path.display()))?;
184        Self::from_bytes(name, version, bytes, types)
185    }
186
187    /// Creates a new package from the given bytes.
188    ///
189    /// The package will populate its types into the provided type collection.
190    pub fn from_bytes(
191        name: &str,
192        version: Option<&Version>,
193        bytes: impl Into<Vec<u8>>,
194        types: &mut Types,
195    ) -> Result<Self> {
196        let bytes = bytes.into();
197        if !Parser::is_component(&bytes) {
198            bail!("package `{name}` is not a binary-encoded WebAssembly component");
199        }
200
201        let mut parser = Parser::new(0);
202        let mut parsers = Vec::new();
203        let mut validator = Validator::new_with_features(WasmFeatures::all());
204        let mut imports = Vec::new();
205        let mut exports = Vec::new();
206
207        let mut cur = bytes.as_ref();
208        loop {
209            match parser.parse(cur, true)? {
210                Chunk::Parsed { payload, consumed } => {
211                    cur = &cur[consumed..];
212
213                    match validator.payload(&payload)? {
214                        ValidPayload::Ok => {
215                            // Don't parse any sub-components or sub-modules
216                            if !parsers.is_empty() {
217                                continue;
218                            }
219
220                            match payload {
221                                Payload::Version { encoding, .. } => {
222                                    assert_eq!(encoding, Encoding::Component);
223                                }
224                                Payload::ComponentImportSection(s) => {
225                                    imports.reserve(s.count() as usize);
226                                    for import in s {
227                                        imports.push(import?.name.0);
228                                    }
229                                }
230                                Payload::ComponentExportSection(s) => {
231                                    exports.reserve(s.count() as usize);
232                                    for export in s {
233                                        exports.push(export?.name.0);
234                                    }
235                                }
236                                _ => {}
237                            }
238                        }
239                        ValidPayload::Func(_, _) => {}
240                        ValidPayload::Parser(next) => {
241                            parsers.push(parser);
242                            parser = next;
243                        }
244                        ValidPayload::End(wasm_types) => match parsers.pop() {
245                            Some(parent) => parser = parent,
246                            None => {
247                                let mut converter = TypeConverter::new(types, wasm_types);
248
249                                let imports = imports
250                                    .into_iter()
251                                    .map(|i| Ok((i.to_string(), converter.import(i)?)))
252                                    .collect::<Result<_>>()?;
253
254                                let exports: IndexMap<String, ItemKind> = exports
255                                    .into_iter()
256                                    .map(|i| Ok((i.to_string(), converter.export(i)?)))
257                                    .collect::<Result<_>>()?;
258
259                                let ty = types.add_world(World {
260                                    id: None,
261                                    uses: Default::default(),
262                                    imports,
263                                    exports: exports.clone(),
264                                });
265
266                                let instance_type = types.add_interface(Interface {
267                                    id: None,
268                                    uses: Default::default(),
269                                    exports,
270                                });
271
272                                let definitions = Self::find_definitions(types, ty);
273
274                                return Ok(Self {
275                                    name: name.to_owned(),
276                                    version: version.map(ToOwned::to_owned),
277                                    bytes,
278                                    ty,
279                                    instance_type,
280                                    definitions,
281                                });
282                            }
283                        },
284                    }
285                }
286                Chunk::NeedMoreData(_) => panic!("all data should be present"),
287            }
288        }
289    }
290
291    /// Gets the name of the package.
292    pub fn name(&self) -> &str {
293        &self.name
294    }
295
296    /// Gets the version of the package.
297    pub fn version(&self) -> Option<&Version> {
298        self.version.as_ref()
299    }
300
301    /// Gets the bytes of the package.
302    ///
303    /// The bytes are a binary-encoded WebAssembly component.
304    pub fn bytes(&self) -> &[u8] {
305        &self.bytes
306    }
307
308    /// Gets the id of the world (i.e. component type) of the package.
309    pub fn ty(&self) -> WorldId {
310        self.ty
311    }
312
313    /// Gets the id of the interface (i.e. instance type) that would
314    /// result from instantiating the package.
315    pub fn instance_type(&self) -> InterfaceId {
316        self.instance_type
317    }
318
319    /// Gets the interfaces and worlds defined in this package.
320    pub fn definitions(&self) -> &IndexMap<String, ItemKind> {
321        &self.definitions
322    }
323
324    fn find_definitions(types: &Types, world: WorldId) -> IndexMap<String, ItemKind> {
325        // Look for any component type exports that export a component type or instance type
326        let exports = &types[world].exports;
327        let mut defs = IndexMap::new();
328        for (name, kind) in exports {
329            if let ItemKind::Type(Type::World(id)) = kind {
330                let world = &types[*id];
331                if world.exports.len() != 1 {
332                    continue;
333                }
334
335                // Check if the export name is an interface name
336                let (export_name, kind) = world.exports.get_index(0).unwrap();
337                match ComponentName::new(export_name, 0).unwrap().kind() {
338                    ComponentNameKind::Interface(_) => {}
339                    _ => continue,
340                }
341
342                match kind {
343                    ItemKind::Instance(id) => {
344                        defs.insert(name.clone(), ItemKind::Type(Type::Interface(*id)));
345                    }
346                    ItemKind::Component(id) => {
347                        defs.insert(name.clone(), ItemKind::Type(Type::World(*id)));
348                    }
349                    _ => continue,
350                }
351            }
352        }
353
354        defs
355    }
356}
357
358impl fmt::Debug for Package {
359    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360        f.debug_struct("Package")
361            .field("name", &self.name)
362            .field("version", &self.version)
363            .field("bytes", &"...")
364            .field("ty", &self.ty)
365            .field("instance_type", &self.instance_type)
366            .field("definitions", &self.definitions)
367            .finish()
368    }
369}
370
371#[derive(Debug, Clone, Copy, PartialEq, Eq)]
372enum Owner {
373    /// The owner is an interface.
374    Interface(InterfaceId),
375    /// The owner is a world.
376    World(WorldId),
377}
378
379#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
380enum Entity {
381    /// The entity is a type.
382    Type(Type),
383    /// The entity is a resource.
384    Resource(ResourceId),
385}
386
387/// Responsible for converting between wasmparser and wac-parser type
388/// representations.
389struct TypeConverter<'a> {
390    types: &'a mut Types,
391    wasm_types: Rc<wasmparser::types::Types>,
392    cache: HashMap<wasm::AnyTypeId, Entity>,
393    resource_map: HashMap<wasm::ResourceId, ResourceId>,
394    owners: HashMap<wasm::ComponentAnyTypeId, (Owner, String)>,
395}
396
397impl<'a> TypeConverter<'a> {
398    fn new(types: &'a mut Types, wasm_types: wasmparser::types::Types) -> Self {
399        Self {
400            types,
401            wasm_types: Rc::new(wasm_types),
402            cache: Default::default(),
403            resource_map: Default::default(),
404            owners: Default::default(),
405        }
406    }
407
408    fn import(&mut self, name: &str) -> Result<ItemKind> {
409        let import = self
410            .wasm_types
411            .component_entity_type_of_import(name)
412            .unwrap();
413        self.entity(name, import)
414    }
415
416    fn export(&mut self, name: &str) -> Result<ItemKind> {
417        let export = self
418            .wasm_types
419            .component_entity_type_of_export(name)
420            .unwrap();
421        self.entity(name, export)
422    }
423
424    fn component_func_type(&mut self, id: wasm::ComponentFuncTypeId) -> Result<FuncTypeId> {
425        let key = wasm::AnyTypeId::Component(wasm::ComponentAnyTypeId::Func(id));
426        if let Some(ty) = self.cache.get(&key) {
427            match ty {
428                Entity::Type(Type::Func(id)) => return Ok(*id),
429                _ => panic!("invalid cached type"),
430            }
431        }
432
433        let wasm_types = self.wasm_types.clone();
434        let func_ty = &wasm_types[id];
435        let params = func_ty
436            .params
437            .iter()
438            .map(|(name, ty)| Ok((name.to_string(), self.component_val_type(*ty)?)))
439            .collect::<Result<_>>()?;
440
441        let result = match func_ty.result {
442            Some(ty) => Some(self.component_val_type(ty)?),
443            None => None,
444        };
445
446        let id = self.types.add_func_type(FuncType {
447            params,
448            result,
449            is_async: func_ty.async_,
450        });
451        self.cache.insert(key, Entity::Type(Type::Func(id)));
452        Ok(id)
453    }
454
455    fn module_type(&mut self, id: wasm::ComponentCoreModuleTypeId) -> Result<ModuleTypeId> {
456        let key = wasm::AnyTypeId::Core(wasm::ComponentCoreTypeId::Module(id));
457        if let Some(ty) = self.cache.get(&key) {
458            match ty {
459                Entity::Type(Type::Module(id)) => return Ok(*id),
460                _ => panic!("invalid cached type"),
461            }
462        }
463
464        let module_ty = &self.wasm_types[id];
465
466        let imports = module_ty
467            .imports
468            .iter()
469            .map(|((module, name), ty)| {
470                Ok(((module.clone(), name.clone()), self.entity_type(*ty)?))
471            })
472            .collect::<Result<_>>()?;
473
474        let exports = module_ty
475            .exports
476            .iter()
477            .map(|(name, ty)| Ok((name.clone(), self.entity_type(*ty)?)))
478            .collect::<Result<_>>()?;
479
480        let module_id = self.types.add_module_type(ModuleType { imports, exports });
481        self.cache
482            .insert(key, Entity::Type(Type::Module(module_id)));
483        Ok(module_id)
484    }
485
486    fn ty(&mut self, name: &str, id: wasm::ComponentAnyTypeId) -> Result<Type> {
487        match id {
488            wasm::ComponentAnyTypeId::Defined(id) => {
489                Ok(Type::Value(self.component_defined_type(id)?))
490            }
491            wasm::ComponentAnyTypeId::Func(id) => Ok(Type::Func(self.component_func_type(id)?)),
492            wasm::ComponentAnyTypeId::Component(id) => {
493                Ok(Type::World(self.component_type(None, id)?))
494            }
495            wasm::ComponentAnyTypeId::Instance(id) => {
496                Ok(Type::Interface(self.component_instance_type(None, id)?))
497            }
498            wasm::ComponentAnyTypeId::Resource(id) => Ok(Type::Resource(self.resource(name, id))),
499        }
500    }
501
502    fn component_val_type(&mut self, ty: wasm::ComponentValType) -> Result<ValueType> {
503        match ty {
504            wasm::ComponentValType::Primitive(ty) => Ok(ValueType::Primitive(ty.into())),
505            wasm::ComponentValType::Type(id) => Ok(self.component_defined_type(id)?),
506        }
507    }
508
509    fn component_instance_type(
510        &mut self,
511        name: Option<&str>,
512        id: wasm::ComponentInstanceTypeId,
513    ) -> Result<InterfaceId> {
514        let key = wasm::AnyTypeId::Component(wasm::ComponentAnyTypeId::Instance(id));
515        if let Some(ty) = self.cache.get(&key) {
516            match ty {
517                Entity::Type(Type::Interface(id)) => {
518                    return Ok(*id);
519                }
520                _ => panic!("invalid cached type"),
521            }
522        }
523
524        let wasm_types = self.wasm_types.clone();
525        let instance_ty = &wasm_types[id];
526        let id = self.types.add_interface(Interface {
527            id: name.and_then(|n| n.contains(':').then(|| n.to_owned())),
528            uses: Default::default(),
529            exports: IndexMap::with_capacity(instance_ty.exports.len()),
530        });
531
532        for (name, ty) in &instance_ty.exports {
533            let export = self.entity(name, *ty)?;
534
535            if let wasm::ComponentEntityType::Type {
536                referenced,
537                created,
538            } = ty
539            {
540                self.use_or_own(Owner::Interface(id), name, *referenced, *created);
541
542                // Prevent self-referential ownership of any aliased resources in this interface
543                if let ItemKind::Type(Type::Resource(res)) = export {
544                    if let Some(ResourceAlias { owner, .. }) = &mut self.types[res].alias {
545                        if let Some(owner_id) = owner {
546                            if *owner_id == id {
547                                *owner = None;
548                            }
549                        }
550                    }
551                }
552            }
553
554            let prev = self.types[id].exports.insert(name.clone(), export);
555            assert!(prev.is_none());
556        }
557
558        self.cache.insert(key, Entity::Type(Type::Interface(id)));
559        Ok(id)
560    }
561
562    fn entity(&mut self, name: &str, ty: wasm::ComponentEntityType) -> Result<ItemKind> {
563        match ty {
564            wasm::ComponentEntityType::Module(id) => Ok(ItemKind::Module(self.module_type(id)?)),
565            wasm::ComponentEntityType::Value(ty) => {
566                Ok(ItemKind::Value(self.component_val_type(ty)?))
567            }
568            wasm::ComponentEntityType::Type { created, .. } => {
569                Ok(ItemKind::Type(self.ty(name, created)?))
570            }
571            wasm::ComponentEntityType::Func(id) => {
572                Ok(ItemKind::Func(self.component_func_type(id)?))
573            }
574            wasm::ComponentEntityType::Instance(id) => Ok(ItemKind::Instance(
575                self.component_instance_type(Some(name), id)?,
576            )),
577            wasm::ComponentEntityType::Component(id) => {
578                Ok(ItemKind::Component(self.component_type(Some(name), id)?))
579            }
580        }
581    }
582
583    fn use_or_own(
584        &mut self,
585        owner: Owner,
586        name: &str,
587        referenced: wasm::ComponentAnyTypeId,
588        created: wasm::ComponentAnyTypeId,
589    ) {
590        if let Some((other, orig)) = self.find_owner(referenced) {
591            match *other {
592                Owner::Interface(interface) if owner != *other => {
593                    let used = UsedType {
594                        interface,
595                        name: if name != orig {
596                            Some(orig.to_string())
597                        } else {
598                            None
599                        },
600                    };
601
602                    // Owner is a different interface, so add a using reference
603                    let uses = match owner {
604                        Owner::Interface(id) => &mut self.types[id].uses,
605                        Owner::World(id) => &mut self.types[id].uses,
606                    };
607
608                    uses.insert(name.to_string(), used);
609                }
610                _ => {}
611            }
612            return;
613        }
614
615        // Take ownership of the entity
616        let prev = self.owners.insert(created, (owner, name.to_string()));
617        assert!(prev.is_none());
618    }
619
620    fn component_type(&mut self, name: Option<&str>, id: wasm::ComponentTypeId) -> Result<WorldId> {
621        let key = wasm::AnyTypeId::Component(wasm::ComponentAnyTypeId::Component(id));
622        if let Some(ty) = self.cache.get(&key) {
623            match ty {
624                Entity::Type(Type::World(id)) => return Ok(*id),
625                _ => panic!("invalid cached type"),
626            }
627        }
628
629        let wasm_types = self.wasm_types.clone();
630        let component_ty = &wasm_types[id];
631        let id = self.types.add_world(World {
632            id: name.and_then(|n| n.contains(':').then(|| n.to_owned())),
633            uses: Default::default(),
634            imports: IndexMap::with_capacity(component_ty.imports.len()),
635            exports: IndexMap::with_capacity(component_ty.exports.len()),
636        });
637
638        for (name, ty) in &component_ty.imports {
639            let import = self.entity(name, *ty)?;
640
641            if let wasm::ComponentEntityType::Type {
642                referenced,
643                created,
644            } = ty
645            {
646                self.use_or_own(Owner::World(id), name, *referenced, *created);
647            }
648
649            let prev = self.types[id].imports.insert(name.clone(), import);
650            assert!(prev.is_none());
651        }
652
653        for (name, ty) in &component_ty.exports {
654            let ty = self.entity(name, *ty)?;
655            let prev = self.types[id].exports.insert(name.clone(), ty);
656            assert!(prev.is_none());
657        }
658
659        self.cache.insert(key, Entity::Type(Type::World(id)));
660        Ok(id)
661    }
662
663    fn component_defined_type(&mut self, id: wasm::ComponentDefinedTypeId) -> Result<ValueType> {
664        let key = wasm::AnyTypeId::Component(wasm::ComponentAnyTypeId::Defined(id));
665        if let Some(ty) = self.cache.get(&key) {
666            match ty {
667                Entity::Type(Type::Value(ty)) => return Ok(*ty),
668                _ => panic!("invalid cached type"),
669            }
670        }
671
672        let wasm_types = self.wasm_types.clone();
673        let ty = match &wasm_types[id] {
674            wasm::ComponentDefinedType::Primitive(ty) => ValueType::Defined(
675                self.types
676                    .add_defined_type(DefinedType::Alias(ValueType::Primitive((*ty).into()))),
677            ),
678            wasm::ComponentDefinedType::Record(ty) => {
679                let fields = ty
680                    .fields
681                    .iter()
682                    .map(|(name, ty)| Ok((name.as_str().to_owned(), self.component_val_type(*ty)?)))
683                    .collect::<Result<_>>()?;
684
685                ValueType::Defined(
686                    self.types
687                        .add_defined_type(DefinedType::Record(Record { fields })),
688                )
689            }
690            wasm::ComponentDefinedType::Variant(ty) => {
691                let cases = ty
692                    .cases
693                    .iter()
694                    .map(|(name, case)| {
695                        Ok((
696                            name.as_str().to_owned(),
697                            case.ty.map(|ty| self.component_val_type(ty)).transpose()?,
698                        ))
699                    })
700                    .collect::<Result<_>>()?;
701
702                ValueType::Defined(
703                    self.types
704                        .add_defined_type(DefinedType::Variant(Variant { cases })),
705                )
706            }
707            wasm::ComponentDefinedType::List(ty) => {
708                let ty = self.component_val_type(*ty)?;
709                ValueType::Defined(self.types.add_defined_type(DefinedType::List(ty)))
710            }
711            wasm::ComponentDefinedType::Tuple(ty) => {
712                let types = ty
713                    .types
714                    .iter()
715                    .map(|ty| self.component_val_type(*ty))
716                    .collect::<Result<_>>()?;
717                ValueType::Defined(self.types.add_defined_type(DefinedType::Tuple(types)))
718            }
719            wasm::ComponentDefinedType::Flags(flags) => {
720                let flags = flags.iter().map(|flag| flag.as_str().to_owned()).collect();
721                ValueType::Defined(
722                    self.types
723                        .add_defined_type(DefinedType::Flags(Flags(flags))),
724                )
725            }
726            wasm::ComponentDefinedType::Enum(cases) => {
727                let cases = cases.iter().map(|case| case.as_str().to_owned()).collect();
728                ValueType::Defined(self.types.add_defined_type(DefinedType::Enum(Enum(cases))))
729            }
730            wasm::ComponentDefinedType::Option(ty) => {
731                let ty = self.component_val_type(*ty)?;
732                ValueType::Defined(self.types.add_defined_type(DefinedType::Option(ty)))
733            }
734            wasm::ComponentDefinedType::Result { ok, err } => {
735                let ok = ok.map(|ty| self.component_val_type(ty)).transpose()?;
736                let err = err.map(|ty| self.component_val_type(ty)).transpose()?;
737                ValueType::Defined(self.types.add_defined_type(DefinedType::Result { ok, err }))
738            }
739            wasm::ComponentDefinedType::Borrow(id) => ValueType::Borrow(
740                match self.cache.get(&wasm::AnyTypeId::Component(
741                    wasm::ComponentAnyTypeId::Resource(*id),
742                )) {
743                    Some(Entity::Resource(id)) => *id,
744                    _ => panic!("expected a resource"),
745                },
746            ),
747            wasm::ComponentDefinedType::Own(id) => ValueType::Own(
748                match self.cache.get(&wasm::AnyTypeId::Component(
749                    wasm::ComponentAnyTypeId::Resource(*id),
750                )) {
751                    Some(Entity::Resource(id)) => *id,
752                    _ => panic!("expected a resource"),
753                },
754            ),
755            wasm::ComponentDefinedType::Stream(ty) => {
756                let stream = ty.map(|ty| self.component_val_type(ty)).transpose()?;
757                ValueType::Defined(self.types.add_defined_type(DefinedType::Stream(stream)))
758            }
759            wasm::ComponentDefinedType::Future(ty) => {
760                let option = ty.map(|ty| self.component_val_type(ty)).transpose()?;
761                ValueType::Defined(self.types.add_defined_type(DefinedType::Future(option)))
762            }
763            wasm::ComponentDefinedType::FixedLengthList(ty, size) => {
764                let ty = self.component_val_type(*ty)?;
765                ValueType::Defined(
766                    self.types
767                        .add_defined_type(DefinedType::FixedSizeList(ty, *size)),
768                )
769            }
770            wasmparser::component_types::ComponentDefinedType::Map(_, _) => {
771                bail!("ComponentDefinedType::Map is not yet supported");
772            }
773        };
774
775        self.cache.insert(key, Entity::Type(Type::Value(ty)));
776        Ok(ty)
777    }
778
779    fn resource(&mut self, name: &str, id: wasm::AliasableResourceId) -> ResourceId {
780        let key = wasm::AnyTypeId::Component(wasm::ComponentAnyTypeId::Resource(id));
781        if let Some(ty) = self.cache.get(&key) {
782            match ty {
783                Entity::Resource(id) => return *id,
784                _ => panic!("invalid cached type"),
785            }
786        }
787
788        // Check if this is an alias of another resource
789        if let Some(resource_id) = self.resource_map.get(&id.resource()) {
790            let alias_id = self.types.add_resource(Resource {
791                name: name.to_owned(),
792                alias: Some(ResourceAlias {
793                    owner: match self.find_owner(wasm::ComponentAnyTypeId::Resource(id)) {
794                        Some((Owner::Interface(id), _)) => Some(*id),
795                        _ => None,
796                    },
797                    source: *resource_id,
798                }),
799            });
800            self.cache.insert(key, Entity::Resource(alias_id));
801            return alias_id;
802        }
803
804        // Otherwise, this is a new resource
805        let resource_id = self.types.add_resource(Resource {
806            name: name.to_owned(),
807            alias: None,
808        });
809
810        self.resource_map.insert(id.resource(), resource_id);
811        self.cache.insert(key, Entity::Resource(resource_id));
812        resource_id
813    }
814
815    fn entity_type(&self, ty: wasmparser::types::EntityType) -> Result<CoreExtern> {
816        Ok(match ty {
817            wasmparser::types::EntityType::Func(ty) => CoreExtern::Func(self.func_type(ty)?),
818            wasmparser::types::EntityType::Table(ty) => ty.try_into()?,
819            wasmparser::types::EntityType::Memory(ty) => ty.into(),
820            wasmparser::types::EntityType::Global(ty) => ty.try_into()?,
821            wasmparser::types::EntityType::Tag(ty) => CoreExtern::Tag(self.func_type(ty)?),
822            wasmparser::types::EntityType::FuncExact(_) => {
823                todo!("wasmparser::types::EntityType::FuncExact")
824            }
825        })
826    }
827
828    fn func_type(&self, ty: wasmparser::types::CoreTypeId) -> Result<CoreFuncType> {
829        let func_ty = self.wasm_types[ty].unwrap_func();
830        Ok(CoreFuncType {
831            params: func_ty
832                .params()
833                .iter()
834                .copied()
835                .map(TryInto::try_into)
836                .collect::<Result<_>>()?,
837            results: func_ty
838                .results()
839                .iter()
840                .copied()
841                .map(TryInto::try_into)
842                .collect::<Result<_>>()?,
843        })
844    }
845
846    fn find_owner(&self, mut id: wasm::ComponentAnyTypeId) -> Option<&(Owner, String)> {
847        let mut prev = None;
848        while prev.is_none() {
849            prev = self.owners.get(&id);
850            id = match self.wasm_types.peel_alias(id) {
851                Some(next) => next,
852                None => break,
853            };
854        }
855        prev
856    }
857}