wit_parser/
lib.rs

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