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    Future(Option<Type>),
573    Stream(Option<Type>),
574    ErrorContext,
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::Future(_) => "future",
602            TypeDefKind::Stream(_) => "stream",
603            TypeDefKind::ErrorContext => "error-context",
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    Id(TypeId),
652}
653
654#[derive(Debug, Copy, Clone, Eq, PartialEq)]
655pub enum Int {
656    U8,
657    U16,
658    U32,
659    U64,
660}
661
662#[derive(Debug, Clone, PartialEq)]
663#[cfg_attr(feature = "serde", derive(Serialize))]
664pub struct Record {
665    pub fields: Vec<Field>,
666}
667
668#[derive(Debug, Clone, PartialEq)]
669#[cfg_attr(feature = "serde", derive(Serialize))]
670pub struct Field {
671    pub name: String,
672    #[cfg_attr(feature = "serde", serde(rename = "type"))]
673    pub ty: Type,
674    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
675    pub docs: Docs,
676}
677
678#[derive(Debug, Clone, PartialEq)]
679#[cfg_attr(feature = "serde", derive(Serialize))]
680pub struct Flags {
681    pub flags: Vec<Flag>,
682}
683
684#[derive(Debug, Clone, PartialEq)]
685#[cfg_attr(feature = "serde", derive(Serialize))]
686pub struct Flag {
687    pub name: String,
688    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
689    pub docs: Docs,
690}
691
692#[derive(Debug, Clone, PartialEq)]
693pub enum FlagsRepr {
694    U8,
695    U16,
696    U32(usize),
697}
698
699impl Flags {
700    pub fn repr(&self) -> FlagsRepr {
701        match self.flags.len() {
702            0 => FlagsRepr::U32(0),
703            n if n <= 8 => FlagsRepr::U8,
704            n if n <= 16 => FlagsRepr::U16,
705            n => FlagsRepr::U32(sizealign::align_to(n, 32) / 32),
706        }
707    }
708}
709
710impl FlagsRepr {
711    pub fn count(&self) -> usize {
712        match self {
713            FlagsRepr::U8 => 1,
714            FlagsRepr::U16 => 1,
715            FlagsRepr::U32(n) => *n,
716        }
717    }
718}
719
720#[derive(Debug, Clone, PartialEq)]
721#[cfg_attr(feature = "serde", derive(Serialize))]
722pub struct Tuple {
723    pub types: Vec<Type>,
724}
725
726#[derive(Debug, Clone, PartialEq)]
727#[cfg_attr(feature = "serde", derive(Serialize))]
728pub struct Variant {
729    pub cases: Vec<Case>,
730}
731
732#[derive(Debug, Clone, PartialEq)]
733#[cfg_attr(feature = "serde", derive(Serialize))]
734pub struct Case {
735    pub name: String,
736    #[cfg_attr(feature = "serde", serde(rename = "type"))]
737    pub ty: Option<Type>,
738    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
739    pub docs: Docs,
740}
741
742impl Variant {
743    pub fn tag(&self) -> Int {
744        discriminant_type(self.cases.len())
745    }
746}
747
748#[derive(Debug, Clone, PartialEq)]
749#[cfg_attr(feature = "serde", derive(Serialize))]
750pub struct Enum {
751    pub cases: Vec<EnumCase>,
752}
753
754#[derive(Debug, Clone, PartialEq)]
755#[cfg_attr(feature = "serde", derive(Serialize))]
756pub struct EnumCase {
757    pub name: String,
758    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
759    pub docs: Docs,
760}
761
762impl Enum {
763    pub fn tag(&self) -> Int {
764        discriminant_type(self.cases.len())
765    }
766}
767
768/// This corresponds to the `discriminant_type` function in the Canonical ABI.
769fn discriminant_type(num_cases: usize) -> Int {
770    match num_cases.checked_sub(1) {
771        None => Int::U8,
772        Some(n) if n <= u8::max_value() as usize => Int::U8,
773        Some(n) if n <= u16::max_value() as usize => Int::U16,
774        Some(n) if n <= u32::max_value() as usize => Int::U32,
775        _ => panic!("too many cases to fit in a repr"),
776    }
777}
778
779#[derive(Debug, Clone, PartialEq)]
780#[cfg_attr(feature = "serde", derive(Serialize))]
781pub struct Result_ {
782    pub ok: Option<Type>,
783    pub err: Option<Type>,
784}
785
786#[derive(Clone, Default, Debug, PartialEq, Eq)]
787#[cfg_attr(feature = "serde", derive(Serialize))]
788pub struct Docs {
789    pub contents: Option<String>,
790}
791
792impl Docs {
793    pub fn is_empty(&self) -> bool {
794        self.contents.is_none()
795    }
796}
797
798#[derive(Debug, Clone, PartialEq, Eq)]
799#[cfg_attr(feature = "serde", derive(Serialize))]
800pub struct Function {
801    pub name: String,
802    pub kind: FunctionKind,
803    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_params"))]
804    pub params: Vec<(String, Type)>,
805    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
806    pub result: Option<Type>,
807    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
808    pub docs: Docs,
809    /// Stability attribute for this function.
810    #[cfg_attr(
811        feature = "serde",
812        serde(skip_serializing_if = "Stability::is_unknown")
813    )]
814    pub stability: Stability,
815}
816
817#[derive(Debug, Clone, PartialEq, Eq)]
818#[cfg_attr(feature = "serde", derive(Serialize))]
819#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
820pub enum FunctionKind {
821    Freestanding,
822    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
823    Method(TypeId),
824    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
825    Static(TypeId),
826    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
827    Constructor(TypeId),
828}
829
830impl FunctionKind {
831    /// Returns the resource, if present, that this function kind refers to.
832    pub fn resource(&self) -> Option<TypeId> {
833        match self {
834            FunctionKind::Freestanding => None,
835            FunctionKind::Method(id) | FunctionKind::Static(id) | FunctionKind::Constructor(id) => {
836                Some(*id)
837            }
838        }
839    }
840}
841
842/// Possible forms of name mangling that are supported by this crate.
843#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
844pub enum Mangling {
845    /// The "standard" component model mangling format for 32-bit linear
846    /// memories. This is specified in WebAssembly/component-model#378
847    Standard32,
848
849    /// The "legacy" name mangling supported in versions 218-and-prior for this
850    /// crate. This is the original support for how components were created from
851    /// core wasm modules and this does not correspond to any standard. This is
852    /// preserved for now while tools transition to the new scheme.
853    Legacy,
854}
855
856impl std::str::FromStr for Mangling {
857    type Err = anyhow::Error;
858
859    fn from_str(s: &str) -> Result<Mangling> {
860        match s {
861            "legacy" => Ok(Mangling::Legacy),
862            "standard32" => Ok(Mangling::Standard32),
863            _ => {
864                bail!(
865                    "unknown name mangling `{s}`, \
866                     supported values are `legacy` or `standard32`"
867                )
868            }
869        }
870    }
871}
872
873/// Possible lift/lower ABI choices supported when mangling names.
874#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
875pub enum LiftLowerAbi {
876    /// Both imports and exports will use the synchronous ABI.
877    Sync,
878
879    /// Both imports and exports will use the async ABI (with a callback for
880    /// each export).
881    AsyncCallback,
882
883    /// Both imports and exports will use the async ABI (with no callbacks for
884    /// exports).
885    AsyncStackful,
886}
887
888impl LiftLowerAbi {
889    fn import_prefix(self) -> &'static str {
890        match self {
891            Self::Sync => "",
892            Self::AsyncCallback | Self::AsyncStackful => "[async]",
893        }
894    }
895
896    /// Get the import [`AbiVariant`] corresponding to this [`LiftLowerAbi`]
897    pub fn import_variant(self) -> AbiVariant {
898        match self {
899            Self::Sync => AbiVariant::GuestImport,
900            Self::AsyncCallback | Self::AsyncStackful => AbiVariant::GuestImportAsync,
901        }
902    }
903
904    fn export_prefix(self) -> &'static str {
905        match self {
906            Self::Sync => "",
907            Self::AsyncCallback => "[async]",
908            Self::AsyncStackful => "[async-stackful]",
909        }
910    }
911
912    /// Get the export [`AbiVariant`] corresponding to this [`LiftLowerAbi`]
913    pub fn export_variant(self) -> AbiVariant {
914        match self {
915            Self::Sync => AbiVariant::GuestExport,
916            Self::AsyncCallback => AbiVariant::GuestExportAsync,
917            Self::AsyncStackful => AbiVariant::GuestExportAsyncStackful,
918        }
919    }
920}
921
922/// Combination of [`Mangling`] and [`LiftLowerAbi`].
923#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
924pub enum ManglingAndAbi {
925    /// See [`Mangling::Standard32`].
926    ///
927    /// As of this writing, the standard name mangling only supports the
928    /// synchronous ABI.
929    Standard32,
930
931    /// See [`Mangling::Legacy`] and [`LiftLowerAbi`].
932    Legacy(LiftLowerAbi),
933}
934
935impl ManglingAndAbi {
936    /// Get the import [`AbiVariant`] corresponding to this [`ManglingAndAbi`]
937    pub fn import_variant(self) -> AbiVariant {
938        match self {
939            Self::Standard32 => AbiVariant::GuestImport,
940            Self::Legacy(abi) => abi.import_variant(),
941        }
942    }
943
944    /// Get the export [`AbiVariant`] corresponding to this [`ManglingAndAbi`]
945    pub fn export_variant(self) -> AbiVariant {
946        match self {
947            Self::Standard32 => AbiVariant::GuestExport,
948            Self::Legacy(abi) => abi.export_variant(),
949        }
950    }
951}
952
953impl Function {
954    pub fn item_name(&self) -> &str {
955        match &self.kind {
956            FunctionKind::Freestanding => &self.name,
957            FunctionKind::Method(_) | FunctionKind::Static(_) => {
958                &self.name[self.name.find('.').unwrap() + 1..]
959            }
960            FunctionKind::Constructor(_) => "constructor",
961        }
962    }
963
964    /// Returns an iterator over the types used in parameters and results.
965    ///
966    /// Note that this iterator is not transitive, it only iterates over the
967    /// direct references to types that this function has.
968    pub fn parameter_and_result_types(&self) -> impl Iterator<Item = Type> + '_ {
969        self.params.iter().map(|(_, t)| *t).chain(self.result)
970    }
971
972    /// Gets the core export name for this function.
973    pub fn standard32_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
974        self.core_export_name(interface, Mangling::Standard32)
975    }
976
977    pub fn legacy_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
978        self.core_export_name(interface, Mangling::Legacy)
979    }
980    /// Gets the core export name for this function.
981    pub fn core_export_name<'a>(
982        &'a self,
983        interface: Option<&str>,
984        mangling: Mangling,
985    ) -> Cow<'a, str> {
986        match interface {
987            Some(interface) => match mangling {
988                Mangling::Standard32 => Cow::Owned(format!("cm32p2|{interface}|{}", self.name)),
989                Mangling::Legacy => Cow::Owned(format!("{interface}#{}", self.name)),
990            },
991            None => match mangling {
992                Mangling::Standard32 => Cow::Owned(format!("cm32p2||{}", self.name)),
993                Mangling::Legacy => Cow::Borrowed(&self.name),
994            },
995        }
996    }
997    /// Collect any future and stream types appearing in the signature of this
998    /// function by doing a depth-first search over the parameter types and then
999    /// the result types.
1000    ///
1001    /// For example, given the WIT function `foo: func(x: future<future<u32>>,
1002    /// y: u32) -> stream<u8>`, we would return `[future<u32>,
1003    /// future<future<u32>>, stream<u8>]`.
1004    ///
1005    /// This may be used by binding generators to refer to specific `future` and
1006    /// `stream` types when importing canonical built-ins such as `stream.new`,
1007    /// `future.read`, etc.  Using the example above, the import
1008    /// `[future-new-0]foo` would indicate a call to `future.new` for the type
1009    /// `future<u32>`.  Likewise, `[future-new-1]foo` would indicate a call to
1010    /// `future.new` for `future<future<u32>>`, and `[stream-new-2]foo` would
1011    /// indicate a call to `stream.new` for `stream<u8>`.
1012    pub fn find_futures_and_streams(&self, resolve: &Resolve) -> Vec<TypeId> {
1013        let mut results = Vec::new();
1014        for (_, ty) in self.params.iter() {
1015            find_futures_and_streams(resolve, *ty, &mut results);
1016        }
1017        if let Some(ty) = self.result {
1018            find_futures_and_streams(resolve, ty, &mut results);
1019        }
1020        results
1021    }
1022}
1023
1024fn find_futures_and_streams(resolve: &Resolve, ty: Type, results: &mut Vec<TypeId>) {
1025    let Type::Id(id) = ty else {
1026        return;
1027    };
1028
1029    match &resolve.types[id].kind {
1030        TypeDefKind::Resource
1031        | TypeDefKind::Handle(_)
1032        | TypeDefKind::Flags(_)
1033        | TypeDefKind::Enum(_)
1034        | TypeDefKind::ErrorContext => {}
1035        TypeDefKind::Record(r) => {
1036            for Field { ty, .. } in &r.fields {
1037                find_futures_and_streams(resolve, *ty, results);
1038            }
1039        }
1040        TypeDefKind::Tuple(t) => {
1041            for ty in &t.types {
1042                find_futures_and_streams(resolve, *ty, results);
1043            }
1044        }
1045        TypeDefKind::Variant(v) => {
1046            for Case { ty, .. } in &v.cases {
1047                if let Some(ty) = ty {
1048                    find_futures_and_streams(resolve, *ty, results);
1049                }
1050            }
1051        }
1052        TypeDefKind::Option(ty) | TypeDefKind::List(ty) | TypeDefKind::Type(ty) => {
1053            find_futures_and_streams(resolve, *ty, results);
1054        }
1055        TypeDefKind::Result(r) => {
1056            if let Some(ty) = r.ok {
1057                find_futures_and_streams(resolve, ty, results);
1058            }
1059            if let Some(ty) = r.err {
1060                find_futures_and_streams(resolve, ty, results);
1061            }
1062        }
1063        TypeDefKind::Future(ty) => {
1064            if let Some(ty) = ty {
1065                find_futures_and_streams(resolve, *ty, results);
1066            }
1067            results.push(id);
1068        }
1069        TypeDefKind::Stream(ty) => {
1070            if let Some(ty) = ty {
1071                find_futures_and_streams(resolve, *ty, results);
1072            }
1073            results.push(id);
1074        }
1075        TypeDefKind::Unknown => unreachable!(),
1076    }
1077}
1078
1079/// Representation of the stability attributes associated with a world,
1080/// interface, function, or type.
1081///
1082/// This is added for WebAssembly/component-model#332 where @since and @unstable
1083/// annotations were added to WIT.
1084#[derive(Debug, Clone, PartialEq, Eq)]
1085#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize, Serialize))]
1086#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1087pub enum Stability {
1088    /// `@since(version = 1.2.3)`
1089    ///
1090    /// This item is explicitly tagged with `@since` as stable since the
1091    /// specified version.  This may optionally have a feature listed as well.
1092    Stable {
1093        #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_version"))]
1094        #[cfg_attr(feature = "serde", serde(deserialize_with = "deserialize_version"))]
1095        since: Version,
1096        #[cfg_attr(
1097            feature = "serde",
1098            serde(
1099                skip_serializing_if = "Option::is_none",
1100                default,
1101                serialize_with = "serialize_optional_version",
1102                deserialize_with = "deserialize_optional_version"
1103            )
1104        )]
1105        deprecated: Option<Version>,
1106    },
1107
1108    /// `@unstable(feature = foo)`
1109    ///
1110    /// This item is explicitly tagged `@unstable`. A feature name is listed and
1111    /// this item is excluded by default in `Resolve` unless explicitly enabled.
1112    Unstable {
1113        feature: String,
1114        #[cfg_attr(
1115            feature = "serde",
1116            serde(
1117                skip_serializing_if = "Option::is_none",
1118                default,
1119                serialize_with = "serialize_optional_version",
1120                deserialize_with = "deserialize_optional_version"
1121            )
1122        )]
1123        deprecated: Option<Version>,
1124    },
1125
1126    /// This item does not have either `@since` or `@unstable`.
1127    Unknown,
1128}
1129
1130impl Stability {
1131    /// Returns whether this is `Stability::Unknown`.
1132    pub fn is_unknown(&self) -> bool {
1133        matches!(self, Stability::Unknown)
1134    }
1135}
1136
1137impl Default for Stability {
1138    fn default() -> Stability {
1139        Stability::Unknown
1140    }
1141}
1142
1143#[cfg(test)]
1144mod test {
1145    use super::*;
1146
1147    #[test]
1148    fn test_discriminant_type() {
1149        assert_eq!(discriminant_type(1), Int::U8);
1150        assert_eq!(discriminant_type(0x100), Int::U8);
1151        assert_eq!(discriminant_type(0x101), Int::U16);
1152        assert_eq!(discriminant_type(0x10000), Int::U16);
1153        assert_eq!(discriminant_type(0x10001), Int::U32);
1154        if let Ok(num_cases) = usize::try_from(0x100000000_u64) {
1155            assert_eq!(discriminant_type(num_cases), Int::U32);
1156        }
1157    }
1158
1159    #[test]
1160    fn test_find_futures_and_streams() {
1161        let mut resolve = Resolve::default();
1162        let t0 = resolve.types.alloc(TypeDef {
1163            name: None,
1164            kind: TypeDefKind::Future(Some(Type::U32)),
1165            owner: TypeOwner::None,
1166            docs: Docs::default(),
1167            stability: Stability::Unknown,
1168        });
1169        let t1 = resolve.types.alloc(TypeDef {
1170            name: None,
1171            kind: TypeDefKind::Future(Some(Type::Id(t0))),
1172            owner: TypeOwner::None,
1173            docs: Docs::default(),
1174            stability: Stability::Unknown,
1175        });
1176        let t2 = resolve.types.alloc(TypeDef {
1177            name: None,
1178            kind: TypeDefKind::Stream(Some(Type::U32)),
1179            owner: TypeOwner::None,
1180            docs: Docs::default(),
1181            stability: Stability::Unknown,
1182        });
1183        let found = Function {
1184            name: "foo".into(),
1185            kind: FunctionKind::Freestanding,
1186            params: vec![("p1".into(), Type::Id(t1)), ("p2".into(), Type::U32)],
1187            result: Some(Type::Id(t2)),
1188            docs: Docs::default(),
1189            stability: Stability::Unknown,
1190        }
1191        .find_futures_and_streams(&resolve);
1192        assert_eq!(3, found.len());
1193        assert_eq!(t0, found[0]);
1194        assert_eq!(t1, found[1]);
1195        assert_eq!(t2, found[2]);
1196    }
1197}