wit_parser/
lib.rs

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