Skip to main content

wit_parser/
lib.rs

1#![no_std]
2
3extern crate alloc;
4
5#[cfg(feature = "std")]
6extern crate std;
7
8use crate::abi::AbiVariant;
9use alloc::format;
10use alloc::string::{String, ToString};
11use alloc::vec::Vec;
12use id_arena::{Arena, Id};
13use semver::Version;
14
15#[cfg(feature = "std")]
16pub type IndexMap<K, V> = indexmap::IndexMap<K, V, std::hash::RandomState>;
17#[cfg(feature = "std")]
18pub type IndexSet<T> = indexmap::IndexSet<T, std::hash::RandomState>;
19#[cfg(not(feature = "std"))]
20pub type IndexMap<K, V> = indexmap::IndexMap<K, V, hashbrown::DefaultHashBuilder>;
21#[cfg(not(feature = "std"))]
22pub type IndexSet<T> = indexmap::IndexSet<T, hashbrown::DefaultHashBuilder>;
23
24#[cfg(feature = "std")]
25pub(crate) use std::collections::{HashMap, HashSet};
26
27#[cfg(not(feature = "std"))]
28pub(crate) use hashbrown::{HashMap, HashSet};
29
30use alloc::borrow::Cow;
31use core::fmt;
32use core::hash::{Hash, Hasher};
33#[cfg(feature = "std")]
34use std::path::Path;
35
36#[cfg(feature = "decoding")]
37pub mod decoding;
38#[cfg(feature = "decoding")]
39mod metadata;
40#[cfg(feature = "decoding")]
41pub use metadata::PackageMetadata;
42
43pub mod abi;
44mod ast;
45pub use ast::error::*;
46pub use ast::lex::Span;
47pub use ast::{ItemName, SourceMap, SpanLocation};
48pub use ast::{ParsedUsePath, parse_use_path};
49mod sizealign;
50pub use sizealign::*;
51mod resolve;
52pub use resolve::error::*;
53pub use resolve::*;
54mod live;
55pub use live::{LiveTypes, TypeIdVisitor};
56
57#[cfg(feature = "serde")]
58use serde_derive::Serialize;
59#[cfg(feature = "serde")]
60mod serde_;
61#[cfg(feature = "serde")]
62use serde_::*;
63
64/// Checks if the given string is a legal identifier in wit.
65pub fn validate_id(s: &str) -> anyhow::Result<()> {
66    ast::validate_id(0, s)?;
67    Ok(())
68}
69
70/// Renders an [`anyhow::Error`] chain produced by this crate, substituting
71/// snippet-bearing output for any [`ResolveError`] or [`ParseError`] layers.
72///
73/// For each layer in the chain, this calls [`ResolveError::render`] or
74/// [`ParseError::render`] to format typed errors with file/line/column and
75/// a source snippet. Other layers are formatted via their [`fmt::Display`]
76/// impl. Layers are joined with `": "`, matching `format!("{err:#}")`.
77///
78/// `source_map` must be the [`SourceMap`] in which every typed error's spans
79/// are valid; combining typed errors from different source maps in one chain
80/// is unsupported. For errors from [`Resolve`] methods, prefer
81/// [`Resolve::render_error`].
82#[cfg(feature = "std")]
83pub fn render_anyhow_error(err: &anyhow::Error, source_map: &SourceMap) -> String {
84    err.chain()
85        .map(|layer| {
86            if let Some(re) = layer.downcast_ref::<ResolveError>() {
87                re.render(source_map)
88            } else if let Some(pe) = layer.downcast_ref::<ParseError>() {
89                pe.render(source_map)
90            } else {
91                layer.to_string()
92            }
93        })
94        .collect::<Vec<_>>()
95        .join(": ")
96}
97
98pub type WorldId = Id<World>;
99pub type InterfaceId = Id<Interface>;
100pub type TypeId = Id<TypeDef>;
101
102/// Representation of a parsed WIT package which has not resolved external
103/// dependencies yet.
104///
105/// This representation has performed internal resolution of the WIT package
106/// itself, ensuring that all references internally are valid and the WIT was
107/// syntactically valid and such.
108///
109/// The fields of this structure represent a flat list of arrays unioned from
110/// all documents within the WIT package. This means, for example, that all
111/// types from all documents are located in `self.types`. The fields of each
112/// item can help splitting back out into packages/interfaces/etc as necessary.
113///
114/// Note that an `UnresolvedPackage` cannot be queried in general about
115/// information such as size or alignment as that would require resolution of
116/// foreign dependencies. Translations such as to-binary additionally are not
117/// supported on an `UnresolvedPackage` due to the lack of knowledge about the
118/// foreign types. This is intended to be an intermediate state which can be
119/// inspected by embedders, if necessary, before quickly transforming to a
120/// [`Resolve`] to fully work with a WIT package.
121///
122/// After an [`UnresolvedPackage`] is parsed it can be fully resolved with
123/// [`Resolve::push`]. During this operation a dependency map is specified which
124/// will connect the `foreign_deps` field of this structure to packages
125/// previously inserted within the [`Resolve`]. Embedders are responsible for
126/// performing this resolution themselves.
127#[derive(Clone, Debug, PartialEq, Eq)]
128pub struct UnresolvedPackage {
129    /// The namespace, name, and version information for this package.
130    pub name: PackageName,
131
132    /// All worlds from all documents within this package.
133    ///
134    /// Each world lists the document that it is from.
135    pub worlds: Arena<World>,
136
137    /// All interfaces from all documents within this package.
138    ///
139    /// Each interface lists the document that it is from. Interfaces are listed
140    /// in topological order as well so iteration through this arena will only
141    /// reference prior elements already visited when working with recursive
142    /// references.
143    pub interfaces: Arena<Interface>,
144
145    /// All types from all documents within this package.
146    ///
147    /// Each type lists the interface or world that defined it, or nothing if
148    /// it's an anonymous type. Types are listed in this arena in topological
149    /// order to ensure that iteration through this arena will only reference
150    /// other types transitively that are already iterated over.
151    pub types: Arena<TypeDef>,
152
153    /// All foreign dependencies that this package depends on.
154    ///
155    /// These foreign dependencies must be resolved to convert this unresolved
156    /// package into a `Resolve`. The map here is keyed by the name of the
157    /// foreign package that this depends on, and the sub-map is keyed by an
158    /// interface name followed by the identifier within `self.interfaces`. The
159    /// fields of `self.interfaces` describes the required types that are from
160    /// each foreign interface.
161    pub foreign_deps: IndexMap<PackageName, IndexMap<String, (AstItem, Vec<Stability>)>>,
162
163    /// Doc comments for this package.
164    pub docs: Docs,
165
166    #[cfg_attr(not(feature = "std"), allow(dead_code))]
167    package_name_span: Span,
168    unknown_type_spans: Vec<Span>,
169    foreign_dep_spans: Vec<Span>,
170    required_resource_types: Vec<(TypeId, Span)>,
171}
172
173impl UnresolvedPackage {
174    /// Adjusts all spans in this package by adding the given byte offset.
175    ///
176    /// This is used when merging source maps to update spans to point to the
177    /// correct location in the combined source map.
178    pub(crate) fn adjust_spans(&mut self, offset: u32) {
179        // Adjust parallel vec spans
180        self.package_name_span.adjust(offset);
181        for span in &mut self.unknown_type_spans {
182            span.adjust(offset);
183        }
184        for span in &mut self.foreign_dep_spans {
185            span.adjust(offset);
186        }
187        for (_, span) in &mut self.required_resource_types {
188            span.adjust(offset);
189        }
190
191        // Adjust spans on arena items
192        for (_, world) in self.worlds.iter_mut() {
193            world.adjust_spans(offset);
194        }
195        for (_, iface) in self.interfaces.iter_mut() {
196            iface.adjust_spans(offset);
197        }
198        for (_, ty) in self.types.iter_mut() {
199            ty.adjust_spans(offset);
200        }
201    }
202}
203
204/// Tracks a set of packages, all pulled from the same group of WIT source files.
205#[derive(Clone, Debug, PartialEq, Eq)]
206pub struct UnresolvedPackageGroup {
207    /// The "main" package in this package group which was found at the root of
208    /// the WIT files.
209    ///
210    /// Note that this is required to be present in all WIT files.
211    pub main: UnresolvedPackage,
212
213    /// Nested packages found while parsing `main`, if any.
214    pub nested: Vec<UnresolvedPackage>,
215
216    /// A set of processed source files from which these packages have been parsed.
217    pub source_map: SourceMap,
218}
219
220#[derive(Debug, Copy, Clone, PartialEq, Eq)]
221#[cfg_attr(feature = "serde", derive(Serialize))]
222#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
223pub enum AstItem {
224    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
225    Interface(InterfaceId),
226    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
227    World(WorldId),
228}
229
230/// A structure used to keep track of the name of a package, containing optional
231/// information such as a namespace and version information.
232///
233/// This is directly encoded as an "ID" in the binary component representation
234/// with an interfaced tacked on as well.
235#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
236#[cfg_attr(feature = "serde", derive(Serialize))]
237#[cfg_attr(feature = "serde", serde(into = "String"))]
238pub struct PackageName {
239    /// A namespace such as `wasi` in `wasi:foo/bar`
240    pub namespace: String,
241    /// The kebab-name of this package, which is always specified.
242    pub name: String,
243    /// Optional major/minor version information.
244    pub version: Option<Version>,
245}
246
247impl From<PackageName> for String {
248    fn from(name: PackageName) -> String {
249        name.to_string()
250    }
251}
252
253impl PackageName {
254    /// Returns the ID that this package name would assign the `interface` name
255    /// specified.
256    pub fn interface_id(&self, interface: &str) -> String {
257        let mut s = String::new();
258        s.push_str(&format!("{}:{}/{interface}", self.namespace, self.name));
259        if let Some(version) = &self.version {
260            s.push_str(&format!("@{version}"));
261        }
262        s
263    }
264
265    /// Determines the "semver compatible track" for the given version.
266    ///
267    /// This method implements the logic from the component model where semver
268    /// versions can be compatible with one another. For example versions 1.2.0
269    /// and 1.2.1 would be considered both compatible with one another because
270    /// they're on the same semver compatible track.
271    ///
272    /// This predicate is used during
273    /// [`Resolve::merge_world_imports_based_on_semver`] for example to
274    /// determine whether two imports can be merged together. This is
275    /// additionally used when creating components to match up imports in
276    /// core wasm to imports in worlds.
277    pub fn version_compat_track(version: &Version) -> Version {
278        let mut version = version.clone();
279        version.build = semver::BuildMetadata::EMPTY;
280        if !version.pre.is_empty() {
281            return version;
282        }
283        if version.major != 0 {
284            version.minor = 0;
285            version.patch = 0;
286            return version;
287        }
288        if version.minor != 0 {
289            version.patch = 0;
290            return version;
291        }
292        version
293    }
294
295    /// Returns the string corresponding to
296    /// [`PackageName::version_compat_track`]. This is done to match the
297    /// component model's expected naming scheme of imports and exports.
298    pub fn version_compat_track_string(version: &Version) -> String {
299        let version = Self::version_compat_track(version);
300        if !version.pre.is_empty() {
301            return version.to_string();
302        }
303        if version.major != 0 {
304            return format!("{}", version.major);
305        }
306        if version.minor != 0 {
307            return format!("{}.{}", version.major, version.minor);
308        }
309        version.to_string()
310    }
311}
312
313impl fmt::Display for PackageName {
314    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
315        write!(f, "{}:{}", self.namespace, self.name)?;
316        if let Some(version) = &self.version {
317            write!(f, "@{version}")?;
318        }
319        Ok(())
320    }
321}
322
323impl UnresolvedPackageGroup {
324    /// Parses the given string as a wit document.
325    ///
326    /// The `path` argument is used for error reporting. The `contents` provided
327    /// are considered to be the contents of `path`. This function does not read
328    /// the filesystem.
329    ///
330    /// On failure the constructed [`SourceMap`] is returned alongside the
331    /// typed [`ParseError`] so the caller can render a snippet via
332    /// [`ParseError::render`] or merge the source map elsewhere.
333    #[cfg(feature = "std")]
334    pub fn parse(
335        path: impl AsRef<Path>,
336        contents: &str,
337    ) -> Result<UnresolvedPackageGroup, (SourceMap, ParseError)> {
338        let mut map = SourceMap::default();
339        map.push(path.as_ref(), contents);
340        map.parse()
341    }
342
343    /// Parses a WIT package from the directory provided.
344    ///
345    /// This method will look at all files under the `path` specified. All
346    /// `*.wit` files are parsed and assumed to be part of the same package
347    /// grouping. This is useful when a WIT package is split across multiple
348    /// files.
349    #[cfg(feature = "std")]
350    pub fn parse_dir(path: impl AsRef<Path>) -> anyhow::Result<UnresolvedPackageGroup> {
351        let mut map = SourceMap::default();
352        map.push_dir(path.as_ref())?;
353        map.parse().map_err(|(map, e)| {
354            let rendered = e.render(&map);
355            anyhow::Error::from(e).context(rendered)
356        })
357    }
358}
359
360#[derive(Debug, Clone, PartialEq, Eq)]
361#[cfg_attr(feature = "serde", derive(Serialize))]
362pub struct World {
363    /// The WIT identifier name of this world.
364    pub name: String,
365
366    /// All imported items into this interface, both worlds and functions.
367    pub imports: IndexMap<WorldKey, WorldItem>,
368
369    /// All exported items from this interface, both worlds and functions.
370    pub exports: IndexMap<WorldKey, WorldItem>,
371
372    /// The package that owns this world.
373    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_optional_id"))]
374    pub package: Option<PackageId>,
375
376    /// Documentation associated with this world declaration.
377    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
378    pub docs: Docs,
379
380    /// Stability annotation for this world itself.
381    #[cfg_attr(
382        feature = "serde",
383        serde(skip_serializing_if = "Stability::is_unknown")
384    )]
385    pub stability: Stability,
386
387    /// All the included worlds from this world. Empty if this is fully resolved.
388    #[cfg_attr(feature = "serde", serde(skip))]
389    pub includes: Vec<WorldInclude>,
390
391    /// Source span for this world.
392    #[cfg_attr(feature = "serde", serde(skip))]
393    pub span: Span,
394}
395
396impl World {
397    /// Adjusts all spans in this world by adding the given byte offset.
398    pub(crate) fn adjust_spans(&mut self, offset: u32) {
399        self.span.adjust(offset);
400        for item in self.imports.values_mut().chain(self.exports.values_mut()) {
401            item.adjust_spans(offset);
402        }
403        for include in &mut self.includes {
404            include.span.adjust(offset);
405        }
406    }
407}
408
409#[derive(Debug, Clone, PartialEq, Eq)]
410pub struct IncludeName {
411    /// The name of the item
412    pub name: String,
413
414    /// The name to be replaced with
415    pub as_: String,
416}
417
418/// An entry in the `includes` list of a world, representing an `include`
419/// statement in WIT.
420#[derive(Debug, Clone, PartialEq, Eq)]
421pub struct WorldInclude {
422    /// The stability annotation on this include.
423    pub stability: Stability,
424
425    /// The world being included.
426    pub id: WorldId,
427
428    /// Names being renamed as part of this include.
429    pub names: Vec<IncludeName>,
430
431    /// Source span for this include statement.
432    pub span: Span,
433}
434
435/// The key to the import/export maps of a world. Either a kebab-name or a
436/// unique interface.
437#[derive(Debug, Clone, Eq)]
438#[cfg_attr(feature = "serde", derive(Serialize))]
439#[cfg_attr(feature = "serde", serde(into = "String"))]
440pub enum WorldKey {
441    /// A kebab-name.
442    Name(String),
443    /// An interface which is assigned no kebab-name.
444    Interface(InterfaceId),
445}
446
447impl Hash for WorldKey {
448    fn hash<H: Hasher>(&self, hasher: &mut H) {
449        match self {
450            WorldKey::Name(s) => {
451                0u8.hash(hasher);
452                s.as_str().hash(hasher);
453            }
454            WorldKey::Interface(i) => {
455                1u8.hash(hasher);
456                i.hash(hasher);
457            }
458        }
459    }
460}
461
462impl PartialEq for WorldKey {
463    fn eq(&self, other: &WorldKey) -> bool {
464        match (self, other) {
465            (WorldKey::Name(a), WorldKey::Name(b)) => a.as_str() == b.as_str(),
466            (WorldKey::Name(_), _) => false,
467            (WorldKey::Interface(a), WorldKey::Interface(b)) => a == b,
468            (WorldKey::Interface(_), _) => false,
469        }
470    }
471}
472
473impl From<WorldKey> for String {
474    fn from(key: WorldKey) -> String {
475        match key {
476            WorldKey::Name(name) => name,
477            WorldKey::Interface(id) => format!("interface-{}", id.index()),
478        }
479    }
480}
481
482impl WorldKey {
483    /// Asserts that this is `WorldKey::Name` and returns the name.
484    #[track_caller]
485    pub fn unwrap_name(self) -> String {
486        match self {
487            WorldKey::Name(name) => name,
488            WorldKey::Interface(_) => panic!("expected a name, found interface"),
489        }
490    }
491}
492
493#[derive(Debug, Clone, PartialEq, Eq)]
494#[cfg_attr(feature = "serde", derive(Serialize))]
495#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
496pub enum WorldItem {
497    /// An interface is being imported or exported from a world, indicating that
498    /// it's a namespace of functions.
499    Interface {
500        #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
501        id: InterfaceId,
502        #[cfg_attr(
503            feature = "serde",
504            serde(skip_serializing_if = "Stability::is_unknown")
505        )]
506        stability: Stability,
507        #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
508        external_id: Option<String>,
509        /// Documentation attached to the `import`/`export` statement.
510        #[cfg_attr(
511            feature = "serde",
512            serde(default, skip_serializing_if = "Docs::is_empty")
513        )]
514        docs: Docs,
515        #[cfg_attr(feature = "serde", serde(skip))]
516        span: Span,
517    },
518
519    /// A function is being directly imported or exported from this world.
520    Function(Function),
521
522    /// A type is being exported from this world.
523    ///
524    /// Note that types are never imported into worlds at this time.
525    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id_ignore_span"))]
526    Type { id: TypeId, span: Span },
527}
528
529impl WorldItem {
530    pub fn stability<'a>(&'a self, resolve: &'a Resolve) -> &'a Stability {
531        match self {
532            WorldItem::Interface { stability, .. } => stability,
533            WorldItem::Function(f) => &f.stability,
534            WorldItem::Type { id, .. } => &resolve.types[*id].stability,
535        }
536    }
537
538    pub fn span(&self) -> Span {
539        match self {
540            WorldItem::Interface { span, .. } => *span,
541            WorldItem::Function(f) => f.span,
542            WorldItem::Type { span, .. } => *span,
543        }
544    }
545
546    pub(crate) fn adjust_spans(&mut self, offset: u32) {
547        match self {
548            WorldItem::Function(f) => f.adjust_spans(offset),
549            WorldItem::Interface { span, .. } => span.adjust(offset),
550            WorldItem::Type { span, .. } => span.adjust(offset),
551        }
552    }
553}
554
555#[derive(Debug, Clone, PartialEq, Eq)]
556#[cfg_attr(feature = "serde", derive(Serialize))]
557pub struct Interface {
558    /// Optionally listed name of this interface.
559    ///
560    /// This is `None` for inline interfaces in worlds.
561    pub name: Option<String>,
562
563    /// Exported types from this interface.
564    ///
565    /// Export names are listed within the types themselves. Note that the
566    /// export name here matches the name listed in the `TypeDef`.
567    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id_map"))]
568    pub types: IndexMap<String, TypeId>,
569
570    /// Exported functions from this interface.
571    pub functions: IndexMap<String, Function>,
572
573    /// Documentation associated with this interface.
574    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
575    pub docs: Docs,
576
577    /// Stability attribute for this interface.
578    #[cfg_attr(
579        feature = "serde",
580        serde(skip_serializing_if = "Stability::is_unknown")
581    )]
582    pub stability: Stability,
583
584    /// The package that owns this interface.
585    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_optional_id"))]
586    pub package: Option<PackageId>,
587
588    /// Source span for this interface.
589    #[cfg_attr(feature = "serde", serde(skip))]
590    pub span: Span,
591
592    /// The interface that this one was cloned from, if any.
593    ///
594    /// Applicable for [`Resolve::generate_nominal_type_ids`].
595    #[cfg_attr(
596        feature = "serde",
597        serde(
598            skip_serializing_if = "Option::is_none",
599            serialize_with = "serialize_optional_id",
600        )
601    )]
602    pub clone_of: Option<InterfaceId>,
603}
604
605impl Interface {
606    /// Adjusts all spans in this interface by adding the given byte offset.
607    pub(crate) fn adjust_spans(&mut self, offset: u32) {
608        self.span.adjust(offset);
609        for func in self.functions.values_mut() {
610            func.adjust_spans(offset);
611        }
612    }
613}
614
615#[derive(Debug, Clone, PartialEq, Eq)]
616#[cfg_attr(feature = "serde", derive(Serialize))]
617pub struct TypeDef {
618    pub name: Option<String>,
619    pub kind: TypeDefKind,
620    pub owner: TypeOwner,
621    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
622    pub docs: Docs,
623    /// Stability attribute for this type.
624    #[cfg_attr(
625        feature = "serde",
626        serde(skip_serializing_if = "Stability::is_unknown")
627    )]
628    pub stability: Stability,
629    /// Source span for this type.
630    #[cfg_attr(feature = "serde", serde(skip))]
631    pub span: Span,
632    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
633    pub external_id: Option<String>,
634}
635
636impl TypeDef {
637    /// Adjusts all spans in this type definition by adding the given byte offset.
638    ///
639    /// This is used when merging source maps to update spans to point to the
640    /// correct location in the combined source map.
641    pub(crate) fn adjust_spans(&mut self, offset: u32) {
642        self.span.adjust(offset);
643        match &mut self.kind {
644            TypeDefKind::Record(r) => {
645                for field in &mut r.fields {
646                    field.span.adjust(offset);
647                }
648            }
649            TypeDefKind::Variant(v) => {
650                for case in &mut v.cases {
651                    case.span.adjust(offset);
652                }
653            }
654            TypeDefKind::Enum(e) => {
655                for case in &mut e.cases {
656                    case.span.adjust(offset);
657                }
658            }
659            TypeDefKind::Flags(f) => {
660                for flag in &mut f.flags {
661                    flag.span.adjust(offset);
662                }
663            }
664            _ => {}
665        }
666    }
667}
668
669#[derive(Debug, Clone, PartialEq, Hash, Eq)]
670#[cfg_attr(feature = "serde", derive(Serialize))]
671#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
672pub enum TypeDefKind {
673    Record(Record),
674    Resource,
675    Handle(Handle),
676    Flags(Flags),
677    Tuple(Tuple),
678    Variant(Variant),
679    Enum(Enum),
680    Option(Type),
681    Result(Result_),
682    List(Type),
683    Map(Type, Type),
684    FixedLengthList(Type, u32),
685    Future(Option<Type>),
686    Stream(Option<Type>),
687    Type(Type),
688
689    /// This represents a type of unknown structure imported from a foreign
690    /// interface.
691    ///
692    /// This variant is only used during the creation of `UnresolvedPackage` but
693    /// by the time a `Resolve` is created then this will not exist.
694    Unknown,
695}
696
697impl TypeDefKind {
698    pub fn as_str(&self) -> &'static str {
699        match self {
700            TypeDefKind::Record(_) => "record",
701            TypeDefKind::Resource => "resource",
702            TypeDefKind::Handle(handle) => match handle {
703                Handle::Own(_) => "own",
704                Handle::Borrow(_) => "borrow",
705            },
706            TypeDefKind::Flags(_) => "flags",
707            TypeDefKind::Tuple(_) => "tuple",
708            TypeDefKind::Variant(_) => "variant",
709            TypeDefKind::Enum(_) => "enum",
710            TypeDefKind::Option(_) => "option",
711            TypeDefKind::Result(_) => "result",
712            TypeDefKind::List(_) => "list",
713            TypeDefKind::Map(_, _) => "map",
714            TypeDefKind::FixedLengthList(..) => "fixed-length list",
715            TypeDefKind::Future(_) => "future",
716            TypeDefKind::Stream(_) => "stream",
717            TypeDefKind::Type(_) => "type",
718            TypeDefKind::Unknown => "unknown",
719        }
720    }
721}
722
723#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
724#[cfg_attr(feature = "serde", derive(Serialize))]
725#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
726pub enum TypeOwner {
727    /// This type was defined within a `world` block.
728    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
729    World(WorldId),
730    /// This type was defined within an `interface` block.
731    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
732    Interface(InterfaceId),
733    /// This type wasn't inherently defined anywhere, such as a `list<T>`, which
734    /// doesn't need an owner.
735    #[cfg_attr(feature = "serde", serde(untagged, serialize_with = "serialize_none"))]
736    None,
737}
738
739#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
740#[cfg_attr(feature = "serde", derive(Serialize))]
741#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
742pub enum Handle {
743    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
744    Own(TypeId),
745    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
746    Borrow(TypeId),
747}
748
749#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
750pub enum Type {
751    Bool,
752    U8,
753    U16,
754    U32,
755    U64,
756    S8,
757    S16,
758    S32,
759    S64,
760    F32,
761    F64,
762    Char,
763    String,
764    ErrorContext,
765    Id(TypeId),
766}
767
768#[derive(Debug, Copy, Clone, Eq, PartialEq)]
769pub enum Int {
770    U8,
771    U16,
772    U32,
773    U64,
774}
775
776#[derive(Debug, Clone, PartialEq, Hash, Eq)]
777#[cfg_attr(feature = "serde", derive(Serialize))]
778pub struct Record {
779    pub fields: Vec<Field>,
780}
781
782#[derive(Debug, Clone, PartialEq, Hash, Eq)]
783#[cfg_attr(feature = "serde", derive(Serialize))]
784pub struct Field {
785    pub name: String,
786    #[cfg_attr(feature = "serde", serde(rename = "type"))]
787    pub ty: Type,
788    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
789    pub docs: Docs,
790    /// Source span for this field.
791    #[cfg_attr(feature = "serde", serde(skip))]
792    pub span: Span,
793}
794
795#[derive(Debug, Clone, PartialEq, Hash, Eq)]
796#[cfg_attr(feature = "serde", derive(Serialize))]
797pub struct Flags {
798    pub flags: Vec<Flag>,
799}
800
801#[derive(Debug, Clone, PartialEq, Hash, Eq)]
802#[cfg_attr(feature = "serde", derive(Serialize))]
803pub struct Flag {
804    pub name: String,
805    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
806    pub docs: Docs,
807    /// Source span for this flag.
808    #[cfg_attr(feature = "serde", serde(skip))]
809    pub span: Span,
810}
811
812#[derive(Debug, Clone, PartialEq)]
813pub enum FlagsRepr {
814    U8,
815    U16,
816    U32(usize),
817}
818
819impl Flags {
820    pub fn repr(&self) -> FlagsRepr {
821        match self.flags.len() {
822            0 => FlagsRepr::U32(0),
823            n if n <= 8 => FlagsRepr::U8,
824            n if n <= 16 => FlagsRepr::U16,
825            n => FlagsRepr::U32(sizealign::align_to(n, 32) / 32),
826        }
827    }
828}
829
830impl FlagsRepr {
831    pub fn count(&self) -> usize {
832        match self {
833            FlagsRepr::U8 => 1,
834            FlagsRepr::U16 => 1,
835            FlagsRepr::U32(n) => *n,
836        }
837    }
838}
839
840#[derive(Debug, Clone, PartialEq, Hash, Eq)]
841#[cfg_attr(feature = "serde", derive(Serialize))]
842pub struct Tuple {
843    pub types: Vec<Type>,
844}
845
846#[derive(Debug, Clone, PartialEq, Hash, Eq)]
847#[cfg_attr(feature = "serde", derive(Serialize))]
848pub struct Variant {
849    pub cases: Vec<Case>,
850}
851
852#[derive(Debug, Clone, PartialEq, Hash, Eq)]
853#[cfg_attr(feature = "serde", derive(Serialize))]
854pub struct Case {
855    pub name: String,
856    #[cfg_attr(feature = "serde", serde(rename = "type"))]
857    pub ty: Option<Type>,
858    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
859    pub docs: Docs,
860    /// Source span for this variant case.
861    #[cfg_attr(feature = "serde", serde(skip))]
862    pub span: Span,
863}
864
865impl Variant {
866    pub fn tag(&self) -> Int {
867        discriminant_type(self.cases.len())
868    }
869}
870
871#[derive(Debug, Clone, PartialEq, Hash, Eq)]
872#[cfg_attr(feature = "serde", derive(Serialize))]
873pub struct Enum {
874    pub cases: Vec<EnumCase>,
875}
876
877#[derive(Debug, Clone, PartialEq, Hash, Eq)]
878#[cfg_attr(feature = "serde", derive(Serialize))]
879pub struct EnumCase {
880    pub name: String,
881    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
882    pub docs: Docs,
883    /// Source span for this enum case.
884    #[cfg_attr(feature = "serde", serde(skip))]
885    pub span: Span,
886}
887
888impl Enum {
889    pub fn tag(&self) -> Int {
890        discriminant_type(self.cases.len())
891    }
892}
893
894/// This corresponds to the `discriminant_type` function in the Canonical ABI.
895fn discriminant_type(num_cases: usize) -> Int {
896    match num_cases.checked_sub(1) {
897        None => Int::U8,
898        Some(n) if n <= u8::max_value() as usize => Int::U8,
899        Some(n) if n <= u16::max_value() as usize => Int::U16,
900        Some(n) if n <= u32::max_value() as usize => Int::U32,
901        _ => panic!("too many cases to fit in a repr"),
902    }
903}
904
905#[derive(Debug, Clone, PartialEq, Hash, Eq)]
906#[cfg_attr(feature = "serde", derive(Serialize))]
907pub struct Result_ {
908    pub ok: Option<Type>,
909    pub err: Option<Type>,
910}
911
912#[derive(Clone, Default, Debug, PartialEq, Eq, Hash)]
913#[cfg_attr(feature = "serde", derive(Serialize))]
914pub struct Docs {
915    pub contents: Option<String>,
916}
917
918impl Docs {
919    pub fn is_empty(&self) -> bool {
920        self.contents.is_none()
921    }
922}
923
924#[derive(Debug, Clone, PartialEq, Eq)]
925#[cfg_attr(feature = "serde", derive(Serialize))]
926pub struct Param {
927    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "String::is_empty"))]
928    pub name: String,
929    #[cfg_attr(feature = "serde", serde(rename = "type"))]
930    pub ty: Type,
931    #[cfg_attr(feature = "serde", serde(skip))]
932    pub span: Span,
933}
934
935#[derive(Debug, Clone, PartialEq, Eq)]
936#[cfg_attr(feature = "serde", derive(Serialize))]
937pub struct Function {
938    pub name: String,
939    pub kind: FunctionKind,
940    pub params: Vec<Param>,
941    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
942    pub result: Option<Type>,
943    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
944    pub docs: Docs,
945    /// Stability attribute for this function.
946    #[cfg_attr(
947        feature = "serde",
948        serde(skip_serializing_if = "Stability::is_unknown")
949    )]
950    pub stability: Stability,
951
952    /// Source span for this function.
953    #[cfg_attr(feature = "serde", serde(skip))]
954    pub span: Span,
955    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
956    pub external_id: Option<String>,
957}
958
959#[derive(Debug, Clone, PartialEq, Eq)]
960#[cfg_attr(feature = "serde", derive(Serialize))]
961#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
962pub enum FunctionKind {
963    /// A freestanding function.
964    ///
965    /// ```wit
966    /// interface foo {
967    ///     the-func: func();
968    /// }
969    /// ```
970    Freestanding,
971
972    /// An async freestanding function.
973    ///
974    /// ```wit
975    /// interface foo {
976    ///     the-func: async func();
977    /// }
978    /// ```
979    AsyncFreestanding,
980
981    /// A resource method where the first parameter is implicitly
982    /// `borrow<T>`.
983    ///
984    /// ```wit
985    /// interface foo {
986    ///     resource r {
987    ///         the-func: func();
988    ///     }
989    /// }
990    /// ```
991    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
992    Method(TypeId),
993
994    /// An async resource method where the first parameter is implicitly
995    /// `borrow<T>`.
996    ///
997    /// ```wit
998    /// interface foo {
999    ///     resource r {
1000    ///         the-func: async func();
1001    ///     }
1002    /// }
1003    /// ```
1004    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1005    AsyncMethod(TypeId),
1006
1007    /// A static resource method.
1008    ///
1009    /// ```wit
1010    /// interface foo {
1011    ///     resource r {
1012    ///         the-func: static func();
1013    ///     }
1014    /// }
1015    /// ```
1016    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1017    Static(TypeId),
1018
1019    /// An async static resource method.
1020    ///
1021    /// ```wit
1022    /// interface foo {
1023    ///     resource r {
1024    ///         the-func: static async func();
1025    ///     }
1026    /// }
1027    /// ```
1028    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1029    AsyncStatic(TypeId),
1030
1031    /// A resource constructor where the return value is implicitly `own<T>`.
1032    ///
1033    /// ```wit
1034    /// interface foo {
1035    ///     resource r {
1036    ///         constructor();
1037    ///     }
1038    /// }
1039    /// ```
1040    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1041    Constructor(TypeId),
1042}
1043
1044impl FunctionKind {
1045    /// Returns whether this is an async function or not.
1046    pub fn is_async(&self) -> bool {
1047        match self {
1048            FunctionKind::Freestanding
1049            | FunctionKind::Method(_)
1050            | FunctionKind::Static(_)
1051            | FunctionKind::Constructor(_) => false,
1052            FunctionKind::AsyncFreestanding
1053            | FunctionKind::AsyncMethod(_)
1054            | FunctionKind::AsyncStatic(_) => true,
1055        }
1056    }
1057
1058    /// Returns the resource, if present, that this function kind refers to.
1059    pub fn resource(&self) -> Option<TypeId> {
1060        match self {
1061            FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
1062            FunctionKind::Method(id)
1063            | FunctionKind::Static(id)
1064            | FunctionKind::Constructor(id)
1065            | FunctionKind::AsyncMethod(id)
1066            | FunctionKind::AsyncStatic(id) => Some(*id),
1067        }
1068    }
1069
1070    /// Returns the resource, if present, that this function kind refers to.
1071    pub fn resource_mut(&mut self) -> Option<&mut TypeId> {
1072        match self {
1073            FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
1074            FunctionKind::Method(id)
1075            | FunctionKind::Static(id)
1076            | FunctionKind::Constructor(id)
1077            | FunctionKind::AsyncMethod(id)
1078            | FunctionKind::AsyncStatic(id) => Some(id),
1079        }
1080    }
1081}
1082
1083/// Possible forms of name mangling that are supported by this crate.
1084#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1085pub enum Mangling {
1086    /// The "standard" component model mangling format for 32-bit linear
1087    /// memories. This is specified in WebAssembly/component-model#378
1088    Standard32,
1089
1090    /// The "legacy" name mangling supported in versions 218-and-prior for this
1091    /// crate. This is the original support for how components were created from
1092    /// core wasm modules and this does not correspond to any standard. This is
1093    /// preserved for now while tools transition to the new scheme.
1094    Legacy,
1095}
1096
1097impl core::str::FromStr for Mangling {
1098    type Err = anyhow::Error;
1099
1100    fn from_str(s: &str) -> anyhow::Result<Mangling> {
1101        match s {
1102            "legacy" => Ok(Mangling::Legacy),
1103            "standard32" => Ok(Mangling::Standard32),
1104            _ => {
1105                anyhow::bail!(
1106                    "unknown name mangling `{s}`, \
1107                     supported values are `legacy` or `standard32`"
1108                )
1109            }
1110        }
1111    }
1112}
1113
1114/// Possible lift/lower ABI choices supported when mangling names.
1115#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1116pub enum LiftLowerAbi {
1117    /// Both imports and exports will use the synchronous ABI.
1118    Sync,
1119
1120    /// Both imports and exports will use the async ABI (with a callback for
1121    /// each export).
1122    AsyncCallback,
1123
1124    /// Both imports and exports will use the async ABI (with no callbacks for
1125    /// exports).
1126    AsyncStackful,
1127}
1128
1129impl LiftLowerAbi {
1130    fn import_prefix(self) -> &'static str {
1131        match self {
1132            Self::Sync => "",
1133            Self::AsyncCallback | Self::AsyncStackful => "[async-lower]",
1134        }
1135    }
1136
1137    /// Get the import [`AbiVariant`] corresponding to this [`LiftLowerAbi`]
1138    pub fn import_variant(self) -> AbiVariant {
1139        match self {
1140            Self::Sync => AbiVariant::GuestImport,
1141            Self::AsyncCallback | Self::AsyncStackful => AbiVariant::GuestImportAsync,
1142        }
1143    }
1144
1145    fn export_prefix(self) -> &'static str {
1146        match self {
1147            Self::Sync => "",
1148            Self::AsyncCallback => "[async-lift]",
1149            Self::AsyncStackful => "[async-lift-stackful]",
1150        }
1151    }
1152
1153    /// Get the export [`AbiVariant`] corresponding to this [`LiftLowerAbi`]
1154    pub fn export_variant(self) -> AbiVariant {
1155        match self {
1156            Self::Sync => AbiVariant::GuestExport,
1157            Self::AsyncCallback => AbiVariant::GuestExportAsync,
1158            Self::AsyncStackful => AbiVariant::GuestExportAsyncStackful,
1159        }
1160    }
1161}
1162
1163/// Combination of [`Mangling`] and [`LiftLowerAbi`].
1164#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1165pub enum ManglingAndAbi {
1166    /// See [`Mangling::Standard32`].
1167    ///
1168    /// As of this writing, the standard name mangling only supports the
1169    /// synchronous ABI.
1170    Standard32,
1171
1172    /// See [`Mangling::Legacy`] and [`LiftLowerAbi`].
1173    Legacy(LiftLowerAbi),
1174}
1175
1176impl ManglingAndAbi {
1177    /// Get the import [`AbiVariant`] corresponding to this [`ManglingAndAbi`]
1178    pub fn import_variant(self) -> AbiVariant {
1179        match self {
1180            Self::Standard32 => AbiVariant::GuestImport,
1181            Self::Legacy(abi) => abi.import_variant(),
1182        }
1183    }
1184
1185    /// Get the export [`AbiVariant`] corresponding to this [`ManglingAndAbi`]
1186    pub fn export_variant(self) -> AbiVariant {
1187        match self {
1188            Self::Standard32 => AbiVariant::GuestExport,
1189            Self::Legacy(abi) => abi.export_variant(),
1190        }
1191    }
1192
1193    /// Switch the ABI to be sync if it's async.
1194    pub fn sync(self) -> Self {
1195        match self {
1196            Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => self,
1197            Self::Legacy(LiftLowerAbi::AsyncCallback)
1198            | Self::Legacy(LiftLowerAbi::AsyncStackful) => Self::Legacy(LiftLowerAbi::Sync),
1199        }
1200    }
1201
1202    /// Returns whether this is an async ABI
1203    pub fn is_async(&self) -> bool {
1204        match self {
1205            Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => false,
1206            Self::Legacy(LiftLowerAbi::AsyncCallback)
1207            | Self::Legacy(LiftLowerAbi::AsyncStackful) => true,
1208        }
1209    }
1210
1211    pub fn mangling(&self) -> Mangling {
1212        match self {
1213            Self::Standard32 => Mangling::Standard32,
1214            Self::Legacy(_) => Mangling::Legacy,
1215        }
1216    }
1217
1218    /// Returns a suitable [`ManglingAndAbi`], based on `self`, to use for
1219    /// `func`.
1220    ///
1221    /// This handles the case where `func` is a synchronous function which means
1222    /// that it's forced to use the sync ABI no matter what.
1223    pub fn for_func(&self, func: &Function) -> Self {
1224        match self {
1225            Self::Standard32 => *self,
1226            Self::Legacy(abi) => {
1227                if !func.kind.is_async() {
1228                    Self::Legacy(LiftLowerAbi::Sync)
1229                } else {
1230                    Self::Legacy(*abi)
1231                }
1232            }
1233        }
1234    }
1235}
1236
1237impl Function {
1238    /// Adjusts all spans in this function by adding the given byte offset.
1239    pub(crate) fn adjust_spans(&mut self, offset: u32) {
1240        self.span.adjust(offset);
1241        for param in &mut self.params {
1242            param.span.adjust(offset);
1243        }
1244    }
1245
1246    pub fn item_name(&self) -> &str {
1247        match &self.kind {
1248            FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => &self.name,
1249            FunctionKind::Method(_)
1250            | FunctionKind::Static(_)
1251            | FunctionKind::AsyncMethod(_)
1252            | FunctionKind::AsyncStatic(_) => &self.name[self.name.find('.').unwrap() + 1..],
1253            FunctionKind::Constructor(_) => "constructor",
1254        }
1255    }
1256
1257    /// Returns an iterator over the types used in parameters and results.
1258    ///
1259    /// Note that this iterator is not transitive, it only iterates over the
1260    /// direct references to types that this function has.
1261    pub fn parameter_and_result_types(&self) -> impl Iterator<Item = Type> + '_ {
1262        self.params.iter().map(|p| p.ty).chain(self.result)
1263    }
1264
1265    /// Gets the core export name for this function.
1266    pub fn standard32_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1267        self.core_export_name(interface, Mangling::Standard32)
1268    }
1269
1270    pub fn legacy_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1271        self.core_export_name(interface, Mangling::Legacy)
1272    }
1273    /// Gets the core export name for this function.
1274    pub fn core_export_name<'a>(
1275        &'a self,
1276        interface: Option<&str>,
1277        mangling: Mangling,
1278    ) -> Cow<'a, str> {
1279        match interface {
1280            Some(interface) => match mangling {
1281                Mangling::Standard32 => Cow::Owned(format!("cm32p2|{interface}|{}", self.name)),
1282                Mangling::Legacy => Cow::Owned(format!("{interface}#{}", self.name)),
1283            },
1284            None => match mangling {
1285                Mangling::Standard32 => Cow::Owned(format!("cm32p2||{}", self.name)),
1286                Mangling::Legacy => Cow::Borrowed(&self.name),
1287            },
1288        }
1289    }
1290    /// Collect any future and stream types appearing in the signature of this
1291    /// function by doing a depth-first search over the parameter types and then
1292    /// the result types.
1293    ///
1294    /// For example, given the WIT function `foo: func(x: future<future<u32>>,
1295    /// y: u32) -> stream<u8>`, we would return `[future<u32>,
1296    /// future<future<u32>>, stream<u8>]`.
1297    ///
1298    /// This may be used by binding generators to refer to specific `future` and
1299    /// `stream` types when importing canonical built-ins such as `stream.new`,
1300    /// `future.read`, etc.  Using the example above, the import
1301    /// `[future-new-0]foo` would indicate a call to `future.new` for the type
1302    /// `future<u32>`.  Likewise, `[future-new-1]foo` would indicate a call to
1303    /// `future.new` for `future<future<u32>>`, and `[stream-new-2]foo` would
1304    /// indicate a call to `stream.new` for `stream<u8>`.
1305    pub fn find_futures_and_streams(&self, resolve: &Resolve) -> Vec<TypeId> {
1306        let mut results = Vec::new();
1307        for param in self.params.iter() {
1308            find_futures_and_streams(resolve, param.ty, &mut results);
1309        }
1310        if let Some(ty) = self.result {
1311            find_futures_and_streams(resolve, ty, &mut results);
1312        }
1313        results
1314    }
1315
1316    /// Check if this function is a resource constructor in shorthand form.
1317    /// I.e. without an explicit return type annotation.
1318    pub fn is_constructor_shorthand(&self, resolve: &Resolve) -> bool {
1319        let FunctionKind::Constructor(containing_resource_id) = self.kind else {
1320            return false;
1321        };
1322
1323        let Some(Type::Id(id)) = &self.result else {
1324            return false;
1325        };
1326
1327        let TypeDefKind::Handle(Handle::Own(returned_resource_id)) = resolve.types[*id].kind else {
1328            return false;
1329        };
1330
1331        return containing_resource_id == returned_resource_id;
1332    }
1333
1334    /// Returns the `module`, `name`, and signature to use when importing this
1335    /// function's `task.return` intrinsic using the `mangling` specified.
1336    pub fn task_return_import(
1337        &self,
1338        resolve: &Resolve,
1339        interface: Option<&WorldKey>,
1340        mangling: Mangling,
1341    ) -> (String, String, abi::WasmSignature) {
1342        match mangling {
1343            Mangling::Standard32 => todo!(),
1344            Mangling::Legacy => {}
1345        }
1346        // For exported async functions, generate a `task.return` intrinsic.
1347        let module = match interface {
1348            Some(key) => format!("[export]{}", resolve.name_world_key(key)),
1349            None => "[export]$root".to_string(),
1350        };
1351        let name = format!("[task-return]{}", self.name);
1352
1353        let mut func_tmp = self.clone();
1354        func_tmp.params = Vec::new();
1355        func_tmp.result = None;
1356        if let Some(ty) = self.result {
1357            func_tmp.params.push(Param {
1358                name: "x".to_string(),
1359                ty,
1360                span: Default::default(),
1361            });
1362        }
1363        let sig = resolve.wasm_signature(AbiVariant::GuestImport, &func_tmp);
1364        (module, name, sig)
1365    }
1366
1367    // push_imported_future_and_stream_intrinsics(wat, resolve, "[export]", interface, func);
1368}
1369
1370fn find_futures_and_streams(resolve: &Resolve, ty: Type, results: &mut Vec<TypeId>) {
1371    let Type::Id(id) = ty else {
1372        return;
1373    };
1374
1375    match &resolve.types[id].kind {
1376        TypeDefKind::Resource
1377        | TypeDefKind::Handle(_)
1378        | TypeDefKind::Flags(_)
1379        | TypeDefKind::Enum(_) => {}
1380        TypeDefKind::Record(r) => {
1381            for Field { ty, .. } in &r.fields {
1382                find_futures_and_streams(resolve, *ty, results);
1383            }
1384        }
1385        TypeDefKind::Tuple(t) => {
1386            for ty in &t.types {
1387                find_futures_and_streams(resolve, *ty, results);
1388            }
1389        }
1390        TypeDefKind::Variant(v) => {
1391            for Case { ty, .. } in &v.cases {
1392                if let Some(ty) = ty {
1393                    find_futures_and_streams(resolve, *ty, results);
1394                }
1395            }
1396        }
1397        TypeDefKind::Option(ty)
1398        | TypeDefKind::List(ty)
1399        | TypeDefKind::FixedLengthList(ty, ..)
1400        | TypeDefKind::Type(ty) => {
1401            find_futures_and_streams(resolve, *ty, results);
1402        }
1403        TypeDefKind::Map(k, v) => {
1404            find_futures_and_streams(resolve, *k, results);
1405            find_futures_and_streams(resolve, *v, results);
1406        }
1407        TypeDefKind::Result(r) => {
1408            if let Some(ty) = r.ok {
1409                find_futures_and_streams(resolve, ty, results);
1410            }
1411            if let Some(ty) = r.err {
1412                find_futures_and_streams(resolve, ty, results);
1413            }
1414        }
1415        TypeDefKind::Future(ty) => {
1416            if let Some(ty) = ty {
1417                find_futures_and_streams(resolve, *ty, results);
1418            }
1419            results.push(id);
1420        }
1421        TypeDefKind::Stream(ty) => {
1422            if let Some(ty) = ty {
1423                find_futures_and_streams(resolve, *ty, results);
1424            }
1425            results.push(id);
1426        }
1427        TypeDefKind::Unknown => unreachable!(),
1428    }
1429}
1430
1431/// Representation of the stability attributes associated with a world,
1432/// interface, function, or type.
1433///
1434/// This is added for WebAssembly/component-model#332 where @since and @unstable
1435/// annotations were added to WIT.
1436///
1437/// The order of the of enum values is significant since it is used with Ord and PartialOrd
1438#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1439#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize, Serialize))]
1440#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1441pub enum Stability {
1442    /// This item does not have either `@since` or `@unstable`.
1443    Unknown,
1444
1445    /// `@unstable(feature = foo)`
1446    ///
1447    /// This item is explicitly tagged `@unstable`. A feature name is listed and
1448    /// this item is excluded by default in `Resolve` unless explicitly enabled.
1449    Unstable {
1450        feature: String,
1451        #[cfg_attr(
1452            feature = "serde",
1453            serde(
1454                skip_serializing_if = "Option::is_none",
1455                default,
1456                serialize_with = "serialize_optional_version",
1457                deserialize_with = "deserialize_optional_version"
1458            )
1459        )]
1460        deprecated: Option<Version>,
1461    },
1462
1463    /// `@since(version = 1.2.3)`
1464    ///
1465    /// This item is explicitly tagged with `@since` as stable since the
1466    /// specified version.  This may optionally have a feature listed as well.
1467    Stable {
1468        #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_version"))]
1469        #[cfg_attr(feature = "serde", serde(deserialize_with = "deserialize_version"))]
1470        since: Version,
1471        #[cfg_attr(
1472            feature = "serde",
1473            serde(
1474                skip_serializing_if = "Option::is_none",
1475                default,
1476                serialize_with = "serialize_optional_version",
1477                deserialize_with = "deserialize_optional_version"
1478            )
1479        )]
1480        deprecated: Option<Version>,
1481    },
1482}
1483
1484impl Stability {
1485    /// Returns whether this is `Stability::Unknown`.
1486    pub fn is_unknown(&self) -> bool {
1487        matches!(self, Stability::Unknown)
1488    }
1489
1490    pub fn is_stable(&self) -> bool {
1491        matches!(self, Stability::Stable { .. })
1492    }
1493}
1494
1495impl Default for Stability {
1496    fn default() -> Stability {
1497        Stability::Unknown
1498    }
1499}
1500
1501#[cfg(test)]
1502mod test {
1503    use super::*;
1504    use alloc::vec;
1505
1506    #[test]
1507    fn test_discriminant_type() {
1508        assert_eq!(discriminant_type(1), Int::U8);
1509        assert_eq!(discriminant_type(0x100), Int::U8);
1510        assert_eq!(discriminant_type(0x101), Int::U16);
1511        assert_eq!(discriminant_type(0x10000), Int::U16);
1512        assert_eq!(discriminant_type(0x10001), Int::U32);
1513        if let Ok(num_cases) = usize::try_from(0x100000000_u64) {
1514            assert_eq!(discriminant_type(num_cases), Int::U32);
1515        }
1516    }
1517
1518    #[test]
1519    fn test_find_futures_and_streams() {
1520        let mut resolve = Resolve::default();
1521        let t0 = resolve.types.alloc(TypeDef {
1522            name: None,
1523            kind: TypeDefKind::Future(Some(Type::U32)),
1524            owner: TypeOwner::None,
1525            docs: Docs::default(),
1526            stability: Stability::Unknown,
1527            span: Default::default(),
1528            external_id: Default::default(),
1529        });
1530        let t1 = resolve.types.alloc(TypeDef {
1531            name: None,
1532            kind: TypeDefKind::Future(Some(Type::Id(t0))),
1533            owner: TypeOwner::None,
1534            docs: Docs::default(),
1535            stability: Stability::Unknown,
1536            span: Default::default(),
1537            external_id: Default::default(),
1538        });
1539        let t2 = resolve.types.alloc(TypeDef {
1540            name: None,
1541            kind: TypeDefKind::Stream(Some(Type::U32)),
1542            owner: TypeOwner::None,
1543            docs: Docs::default(),
1544            stability: Stability::Unknown,
1545            span: Default::default(),
1546            external_id: Default::default(),
1547        });
1548        let found = Function {
1549            name: "foo".into(),
1550            kind: FunctionKind::Freestanding,
1551            params: vec![
1552                Param {
1553                    name: "p1".into(),
1554                    ty: Type::Id(t1),
1555                    span: Default::default(),
1556                },
1557                Param {
1558                    name: "p2".into(),
1559                    ty: Type::U32,
1560                    span: Default::default(),
1561                },
1562            ],
1563            result: Some(Type::Id(t2)),
1564            docs: Docs::default(),
1565            stability: Stability::Unknown,
1566            span: Default::default(),
1567            external_id: Default::default(),
1568        }
1569        .find_futures_and_streams(&resolve);
1570        assert_eq!(3, found.len());
1571        assert_eq!(t0, found[0]);
1572        assert_eq!(t1, found[1]);
1573        assert_eq!(t2, found[2]);
1574    }
1575}