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