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