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    Type(Type),
575
576    /// This represents a type of unknown structure imported from a foreign
577    /// interface.
578    ///
579    /// This variant is only used during the creation of `UnresolvedPackage` but
580    /// by the time a `Resolve` is created then this will not exist.
581    Unknown,
582}
583
584impl TypeDefKind {
585    pub fn as_str(&self) -> &'static str {
586        match self {
587            TypeDefKind::Record(_) => "record",
588            TypeDefKind::Resource => "resource",
589            TypeDefKind::Handle(handle) => match handle {
590                Handle::Own(_) => "own",
591                Handle::Borrow(_) => "borrow",
592            },
593            TypeDefKind::Flags(_) => "flags",
594            TypeDefKind::Tuple(_) => "tuple",
595            TypeDefKind::Variant(_) => "variant",
596            TypeDefKind::Enum(_) => "enum",
597            TypeDefKind::Option(_) => "option",
598            TypeDefKind::Result(_) => "result",
599            TypeDefKind::List(_) => "list",
600            TypeDefKind::Future(_) => "future",
601            TypeDefKind::Stream(_) => "stream",
602            TypeDefKind::Type(_) => "type",
603            TypeDefKind::Unknown => "unknown",
604        }
605    }
606}
607
608#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
609#[cfg_attr(feature = "serde", derive(Serialize))]
610#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
611pub enum TypeOwner {
612    /// This type was defined within a `world` block.
613    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
614    World(WorldId),
615    /// This type was defined within an `interface` block.
616    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
617    Interface(InterfaceId),
618    /// This type wasn't inherently defined anywhere, such as a `list<T>`, which
619    /// doesn't need an owner.
620    #[cfg_attr(feature = "serde", serde(untagged, serialize_with = "serialize_none"))]
621    None,
622}
623
624#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
625#[cfg_attr(feature = "serde", derive(Serialize))]
626#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
627pub enum Handle {
628    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
629    Own(TypeId),
630    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
631    Borrow(TypeId),
632}
633
634#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
635pub enum Type {
636    Bool,
637    U8,
638    U16,
639    U32,
640    U64,
641    S8,
642    S16,
643    S32,
644    S64,
645    F32,
646    F64,
647    Char,
648    String,
649    ErrorContext,
650    Id(TypeId),
651}
652
653#[derive(Debug, Copy, Clone, Eq, PartialEq)]
654pub enum Int {
655    U8,
656    U16,
657    U32,
658    U64,
659}
660
661#[derive(Debug, Clone, PartialEq)]
662#[cfg_attr(feature = "serde", derive(Serialize))]
663pub struct Record {
664    pub fields: Vec<Field>,
665}
666
667#[derive(Debug, Clone, PartialEq)]
668#[cfg_attr(feature = "serde", derive(Serialize))]
669pub struct Field {
670    pub name: String,
671    #[cfg_attr(feature = "serde", serde(rename = "type"))]
672    pub ty: Type,
673    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
674    pub docs: Docs,
675}
676
677#[derive(Debug, Clone, PartialEq)]
678#[cfg_attr(feature = "serde", derive(Serialize))]
679pub struct Flags {
680    pub flags: Vec<Flag>,
681}
682
683#[derive(Debug, Clone, PartialEq)]
684#[cfg_attr(feature = "serde", derive(Serialize))]
685pub struct Flag {
686    pub name: String,
687    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
688    pub docs: Docs,
689}
690
691#[derive(Debug, Clone, PartialEq)]
692pub enum FlagsRepr {
693    U8,
694    U16,
695    U32(usize),
696}
697
698impl Flags {
699    pub fn repr(&self) -> FlagsRepr {
700        match self.flags.len() {
701            0 => FlagsRepr::U32(0),
702            n if n <= 8 => FlagsRepr::U8,
703            n if n <= 16 => FlagsRepr::U16,
704            n => FlagsRepr::U32(sizealign::align_to(n, 32) / 32),
705        }
706    }
707}
708
709impl FlagsRepr {
710    pub fn count(&self) -> usize {
711        match self {
712            FlagsRepr::U8 => 1,
713            FlagsRepr::U16 => 1,
714            FlagsRepr::U32(n) => *n,
715        }
716    }
717}
718
719#[derive(Debug, Clone, PartialEq)]
720#[cfg_attr(feature = "serde", derive(Serialize))]
721pub struct Tuple {
722    pub types: Vec<Type>,
723}
724
725#[derive(Debug, Clone, PartialEq)]
726#[cfg_attr(feature = "serde", derive(Serialize))]
727pub struct Variant {
728    pub cases: Vec<Case>,
729}
730
731#[derive(Debug, Clone, PartialEq)]
732#[cfg_attr(feature = "serde", derive(Serialize))]
733pub struct Case {
734    pub name: String,
735    #[cfg_attr(feature = "serde", serde(rename = "type"))]
736    pub ty: Option<Type>,
737    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
738    pub docs: Docs,
739}
740
741impl Variant {
742    pub fn tag(&self) -> Int {
743        discriminant_type(self.cases.len())
744    }
745}
746
747#[derive(Debug, Clone, PartialEq)]
748#[cfg_attr(feature = "serde", derive(Serialize))]
749pub struct Enum {
750    pub cases: Vec<EnumCase>,
751}
752
753#[derive(Debug, Clone, PartialEq)]
754#[cfg_attr(feature = "serde", derive(Serialize))]
755pub struct EnumCase {
756    pub name: String,
757    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
758    pub docs: Docs,
759}
760
761impl Enum {
762    pub fn tag(&self) -> Int {
763        discriminant_type(self.cases.len())
764    }
765}
766
767/// This corresponds to the `discriminant_type` function in the Canonical ABI.
768fn discriminant_type(num_cases: usize) -> Int {
769    match num_cases.checked_sub(1) {
770        None => Int::U8,
771        Some(n) if n <= u8::max_value() as usize => Int::U8,
772        Some(n) if n <= u16::max_value() as usize => Int::U16,
773        Some(n) if n <= u32::max_value() as usize => Int::U32,
774        _ => panic!("too many cases to fit in a repr"),
775    }
776}
777
778#[derive(Debug, Clone, PartialEq)]
779#[cfg_attr(feature = "serde", derive(Serialize))]
780pub struct Result_ {
781    pub ok: Option<Type>,
782    pub err: Option<Type>,
783}
784
785#[derive(Clone, Default, Debug, PartialEq, Eq)]
786#[cfg_attr(feature = "serde", derive(Serialize))]
787pub struct Docs {
788    pub contents: Option<String>,
789}
790
791impl Docs {
792    pub fn is_empty(&self) -> bool {
793        self.contents.is_none()
794    }
795}
796
797#[derive(Debug, Clone, PartialEq, Eq)]
798#[cfg_attr(feature = "serde", derive(Serialize))]
799pub struct Function {
800    pub name: String,
801    pub kind: FunctionKind,
802    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_params"))]
803    pub params: Vec<(String, Type)>,
804    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
805    pub result: Option<Type>,
806    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
807    pub docs: Docs,
808    /// Stability attribute for this function.
809    #[cfg_attr(
810        feature = "serde",
811        serde(skip_serializing_if = "Stability::is_unknown")
812    )]
813    pub stability: Stability,
814}
815
816#[derive(Debug, Clone, PartialEq, Eq)]
817#[cfg_attr(feature = "serde", derive(Serialize))]
818#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
819pub enum FunctionKind {
820    /// A freestanding function.
821    ///
822    /// ```wit
823    /// interface foo {
824    ///     the-func: func();
825    /// }
826    /// ```
827    Freestanding,
828
829    /// An async freestanding function.
830    ///
831    /// ```wit
832    /// interface foo {
833    ///     the-func: async func();
834    /// }
835    /// ```
836    AsyncFreestanding,
837
838    /// A resource method where the first parameter is implicitly
839    /// `borrow<T>`.
840    ///
841    /// ```wit
842    /// interface foo {
843    ///     resource r {
844    ///         the-func: func();
845    ///     }
846    /// }
847    /// ```
848    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
849    Method(TypeId),
850
851    /// An async resource method where the first parameter is implicitly
852    /// `borrow<T>`.
853    ///
854    /// ```wit
855    /// interface foo {
856    ///     resource r {
857    ///         the-func: async func();
858    ///     }
859    /// }
860    /// ```
861    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
862    AsyncMethod(TypeId),
863
864    /// A static resource method.
865    ///
866    /// ```wit
867    /// interface foo {
868    ///     resource r {
869    ///         the-func: static func();
870    ///     }
871    /// }
872    /// ```
873    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
874    Static(TypeId),
875
876    /// An async static resource method.
877    ///
878    /// ```wit
879    /// interface foo {
880    ///     resource r {
881    ///         the-func: static async func();
882    ///     }
883    /// }
884    /// ```
885    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
886    AsyncStatic(TypeId),
887
888    /// A resource constructor where the return value is implicitly `own<T>`.
889    ///
890    /// ```wit
891    /// interface foo {
892    ///     resource r {
893    ///         constructor();
894    ///     }
895    /// }
896    /// ```
897    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
898    Constructor(TypeId),
899}
900
901impl FunctionKind {
902    /// Returns the resource, if present, that this function kind refers to.
903    pub fn resource(&self) -> Option<TypeId> {
904        match self {
905            FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
906            FunctionKind::Method(id)
907            | FunctionKind::Static(id)
908            | FunctionKind::Constructor(id)
909            | FunctionKind::AsyncMethod(id)
910            | FunctionKind::AsyncStatic(id) => Some(*id),
911        }
912    }
913
914    /// Returns the resource, if present, that this function kind refers to.
915    pub fn resource_mut(&mut self) -> Option<&mut TypeId> {
916        match self {
917            FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
918            FunctionKind::Method(id)
919            | FunctionKind::Static(id)
920            | FunctionKind::Constructor(id)
921            | FunctionKind::AsyncMethod(id)
922            | FunctionKind::AsyncStatic(id) => Some(id),
923        }
924    }
925}
926
927/// Possible forms of name mangling that are supported by this crate.
928#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
929pub enum Mangling {
930    /// The "standard" component model mangling format for 32-bit linear
931    /// memories. This is specified in WebAssembly/component-model#378
932    Standard32,
933
934    /// The "legacy" name mangling supported in versions 218-and-prior for this
935    /// crate. This is the original support for how components were created from
936    /// core wasm modules and this does not correspond to any standard. This is
937    /// preserved for now while tools transition to the new scheme.
938    Legacy,
939}
940
941impl std::str::FromStr for Mangling {
942    type Err = anyhow::Error;
943
944    fn from_str(s: &str) -> Result<Mangling> {
945        match s {
946            "legacy" => Ok(Mangling::Legacy),
947            "standard32" => Ok(Mangling::Standard32),
948            _ => {
949                bail!(
950                    "unknown name mangling `{s}`, \
951                     supported values are `legacy` or `standard32`"
952                )
953            }
954        }
955    }
956}
957
958/// Possible lift/lower ABI choices supported when mangling names.
959#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
960pub enum LiftLowerAbi {
961    /// Both imports and exports will use the synchronous ABI.
962    Sync,
963
964    /// Both imports and exports will use the async ABI (with a callback for
965    /// each export).
966    AsyncCallback,
967
968    /// Both imports and exports will use the async ABI (with no callbacks for
969    /// exports).
970    AsyncStackful,
971}
972
973impl LiftLowerAbi {
974    fn import_prefix(self) -> &'static str {
975        match self {
976            Self::Sync => "",
977            Self::AsyncCallback | Self::AsyncStackful => "[async-lower]",
978        }
979    }
980
981    /// Get the import [`AbiVariant`] corresponding to this [`LiftLowerAbi`]
982    pub fn import_variant(self) -> AbiVariant {
983        match self {
984            Self::Sync => AbiVariant::GuestImport,
985            Self::AsyncCallback | Self::AsyncStackful => AbiVariant::GuestImportAsync,
986        }
987    }
988
989    fn export_prefix(self) -> &'static str {
990        match self {
991            Self::Sync => "",
992            Self::AsyncCallback => "[async-lift]",
993            Self::AsyncStackful => "[async-lift-stackful]",
994        }
995    }
996
997    /// Get the export [`AbiVariant`] corresponding to this [`LiftLowerAbi`]
998    pub fn export_variant(self) -> AbiVariant {
999        match self {
1000            Self::Sync => AbiVariant::GuestExport,
1001            Self::AsyncCallback => AbiVariant::GuestExportAsync,
1002            Self::AsyncStackful => AbiVariant::GuestExportAsyncStackful,
1003        }
1004    }
1005}
1006
1007/// Combination of [`Mangling`] and [`LiftLowerAbi`].
1008#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1009pub enum ManglingAndAbi {
1010    /// See [`Mangling::Standard32`].
1011    ///
1012    /// As of this writing, the standard name mangling only supports the
1013    /// synchronous ABI.
1014    Standard32,
1015
1016    /// See [`Mangling::Legacy`] and [`LiftLowerAbi`].
1017    Legacy(LiftLowerAbi),
1018}
1019
1020impl ManglingAndAbi {
1021    /// Get the import [`AbiVariant`] corresponding to this [`ManglingAndAbi`]
1022    pub fn import_variant(self) -> AbiVariant {
1023        match self {
1024            Self::Standard32 => AbiVariant::GuestImport,
1025            Self::Legacy(abi) => abi.import_variant(),
1026        }
1027    }
1028
1029    /// Get the export [`AbiVariant`] corresponding to this [`ManglingAndAbi`]
1030    pub fn export_variant(self) -> AbiVariant {
1031        match self {
1032            Self::Standard32 => AbiVariant::GuestExport,
1033            Self::Legacy(abi) => abi.export_variant(),
1034        }
1035    }
1036
1037    /// Switch the ABI to be sync if it's async.
1038    pub fn sync(self) -> Self {
1039        match self {
1040            Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => self,
1041            Self::Legacy(LiftLowerAbi::AsyncCallback)
1042            | Self::Legacy(LiftLowerAbi::AsyncStackful) => Self::Legacy(LiftLowerAbi::Sync),
1043        }
1044    }
1045
1046    /// Returns whether this is an async ABI
1047    pub fn is_async(&self) -> bool {
1048        match self {
1049            Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => false,
1050            Self::Legacy(LiftLowerAbi::AsyncCallback)
1051            | Self::Legacy(LiftLowerAbi::AsyncStackful) => true,
1052        }
1053    }
1054}
1055
1056impl Function {
1057    pub fn item_name(&self) -> &str {
1058        match &self.kind {
1059            FunctionKind::Freestanding => &self.name,
1060            FunctionKind::AsyncFreestanding => &self.name["[async]".len()..],
1061            FunctionKind::Method(_)
1062            | FunctionKind::Static(_)
1063            | FunctionKind::AsyncMethod(_)
1064            | FunctionKind::AsyncStatic(_) => &self.name[self.name.find('.').unwrap() + 1..],
1065            FunctionKind::Constructor(_) => "constructor",
1066        }
1067    }
1068
1069    /// Returns an iterator over the types used in parameters and results.
1070    ///
1071    /// Note that this iterator is not transitive, it only iterates over the
1072    /// direct references to types that this function has.
1073    pub fn parameter_and_result_types(&self) -> impl Iterator<Item = Type> + '_ {
1074        self.params.iter().map(|(_, t)| *t).chain(self.result)
1075    }
1076
1077    /// Gets the core export name for this function.
1078    pub fn standard32_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1079        self.core_export_name(interface, Mangling::Standard32)
1080    }
1081
1082    pub fn legacy_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1083        self.core_export_name(interface, Mangling::Legacy)
1084    }
1085    /// Gets the core export name for this function.
1086    pub fn core_export_name<'a>(
1087        &'a self,
1088        interface: Option<&str>,
1089        mangling: Mangling,
1090    ) -> Cow<'a, str> {
1091        match interface {
1092            Some(interface) => match mangling {
1093                Mangling::Standard32 => Cow::Owned(format!("cm32p2|{interface}|{}", self.name)),
1094                Mangling::Legacy => Cow::Owned(format!("{interface}#{}", self.name)),
1095            },
1096            None => match mangling {
1097                Mangling::Standard32 => Cow::Owned(format!("cm32p2||{}", self.name)),
1098                Mangling::Legacy => Cow::Borrowed(&self.name),
1099            },
1100        }
1101    }
1102    /// Collect any future and stream types appearing in the signature of this
1103    /// function by doing a depth-first search over the parameter types and then
1104    /// the result types.
1105    ///
1106    /// For example, given the WIT function `foo: func(x: future<future<u32>>,
1107    /// y: u32) -> stream<u8>`, we would return `[future<u32>,
1108    /// future<future<u32>>, stream<u8>]`.
1109    ///
1110    /// This may be used by binding generators to refer to specific `future` and
1111    /// `stream` types when importing canonical built-ins such as `stream.new`,
1112    /// `future.read`, etc.  Using the example above, the import
1113    /// `[future-new-0]foo` would indicate a call to `future.new` for the type
1114    /// `future<u32>`.  Likewise, `[future-new-1]foo` would indicate a call to
1115    /// `future.new` for `future<future<u32>>`, and `[stream-new-2]foo` would
1116    /// indicate a call to `stream.new` for `stream<u8>`.
1117    pub fn find_futures_and_streams(&self, resolve: &Resolve) -> Vec<TypeId> {
1118        let mut results = Vec::new();
1119        for (_, ty) in self.params.iter() {
1120            find_futures_and_streams(resolve, *ty, &mut results);
1121        }
1122        if let Some(ty) = self.result {
1123            find_futures_and_streams(resolve, ty, &mut results);
1124        }
1125        results
1126    }
1127}
1128
1129fn find_futures_and_streams(resolve: &Resolve, ty: Type, results: &mut Vec<TypeId>) {
1130    let Type::Id(id) = ty else {
1131        return;
1132    };
1133
1134    match &resolve.types[id].kind {
1135        TypeDefKind::Resource
1136        | TypeDefKind::Handle(_)
1137        | TypeDefKind::Flags(_)
1138        | TypeDefKind::Enum(_) => {}
1139        TypeDefKind::Record(r) => {
1140            for Field { ty, .. } in &r.fields {
1141                find_futures_and_streams(resolve, *ty, results);
1142            }
1143        }
1144        TypeDefKind::Tuple(t) => {
1145            for ty in &t.types {
1146                find_futures_and_streams(resolve, *ty, results);
1147            }
1148        }
1149        TypeDefKind::Variant(v) => {
1150            for Case { ty, .. } in &v.cases {
1151                if let Some(ty) = ty {
1152                    find_futures_and_streams(resolve, *ty, results);
1153                }
1154            }
1155        }
1156        TypeDefKind::Option(ty) | TypeDefKind::List(ty) | TypeDefKind::Type(ty) => {
1157            find_futures_and_streams(resolve, *ty, results);
1158        }
1159        TypeDefKind::Result(r) => {
1160            if let Some(ty) = r.ok {
1161                find_futures_and_streams(resolve, ty, results);
1162            }
1163            if let Some(ty) = r.err {
1164                find_futures_and_streams(resolve, ty, results);
1165            }
1166        }
1167        TypeDefKind::Future(ty) => {
1168            if let Some(ty) = ty {
1169                find_futures_and_streams(resolve, *ty, results);
1170            }
1171            results.push(id);
1172        }
1173        TypeDefKind::Stream(ty) => {
1174            if let Some(ty) = ty {
1175                find_futures_and_streams(resolve, *ty, results);
1176            }
1177            results.push(id);
1178        }
1179        TypeDefKind::Unknown => unreachable!(),
1180    }
1181}
1182
1183/// Representation of the stability attributes associated with a world,
1184/// interface, function, or type.
1185///
1186/// This is added for WebAssembly/component-model#332 where @since and @unstable
1187/// annotations were added to WIT.
1188///
1189/// The order of the of enum values is significant since it is used with Ord and PartialOrd
1190#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1191#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize, Serialize))]
1192#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1193pub enum Stability {
1194    /// This item does not have either `@since` or `@unstable`.
1195    Unknown,
1196
1197    /// `@unstable(feature = foo)`
1198    ///
1199    /// This item is explicitly tagged `@unstable`. A feature name is listed and
1200    /// this item is excluded by default in `Resolve` unless explicitly enabled.
1201    Unstable {
1202        feature: String,
1203        #[cfg_attr(
1204            feature = "serde",
1205            serde(
1206                skip_serializing_if = "Option::is_none",
1207                default,
1208                serialize_with = "serialize_optional_version",
1209                deserialize_with = "deserialize_optional_version"
1210            )
1211        )]
1212        deprecated: Option<Version>,
1213    },
1214
1215    /// `@since(version = 1.2.3)`
1216    ///
1217    /// This item is explicitly tagged with `@since` as stable since the
1218    /// specified version.  This may optionally have a feature listed as well.
1219    Stable {
1220        #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_version"))]
1221        #[cfg_attr(feature = "serde", serde(deserialize_with = "deserialize_version"))]
1222        since: Version,
1223        #[cfg_attr(
1224            feature = "serde",
1225            serde(
1226                skip_serializing_if = "Option::is_none",
1227                default,
1228                serialize_with = "serialize_optional_version",
1229                deserialize_with = "deserialize_optional_version"
1230            )
1231        )]
1232        deprecated: Option<Version>,
1233    },
1234}
1235
1236impl Stability {
1237    /// Returns whether this is `Stability::Unknown`.
1238    pub fn is_unknown(&self) -> bool {
1239        matches!(self, Stability::Unknown)
1240    }
1241}
1242
1243impl Default for Stability {
1244    fn default() -> Stability {
1245        Stability::Unknown
1246    }
1247}
1248
1249#[cfg(test)]
1250mod test {
1251    use super::*;
1252
1253    #[test]
1254    fn test_discriminant_type() {
1255        assert_eq!(discriminant_type(1), Int::U8);
1256        assert_eq!(discriminant_type(0x100), Int::U8);
1257        assert_eq!(discriminant_type(0x101), Int::U16);
1258        assert_eq!(discriminant_type(0x10000), Int::U16);
1259        assert_eq!(discriminant_type(0x10001), Int::U32);
1260        if let Ok(num_cases) = usize::try_from(0x100000000_u64) {
1261            assert_eq!(discriminant_type(num_cases), Int::U32);
1262        }
1263    }
1264
1265    #[test]
1266    fn test_find_futures_and_streams() {
1267        let mut resolve = Resolve::default();
1268        let t0 = resolve.types.alloc(TypeDef {
1269            name: None,
1270            kind: TypeDefKind::Future(Some(Type::U32)),
1271            owner: TypeOwner::None,
1272            docs: Docs::default(),
1273            stability: Stability::Unknown,
1274        });
1275        let t1 = resolve.types.alloc(TypeDef {
1276            name: None,
1277            kind: TypeDefKind::Future(Some(Type::Id(t0))),
1278            owner: TypeOwner::None,
1279            docs: Docs::default(),
1280            stability: Stability::Unknown,
1281        });
1282        let t2 = resolve.types.alloc(TypeDef {
1283            name: None,
1284            kind: TypeDefKind::Stream(Some(Type::U32)),
1285            owner: TypeOwner::None,
1286            docs: Docs::default(),
1287            stability: Stability::Unknown,
1288        });
1289        let found = Function {
1290            name: "foo".into(),
1291            kind: FunctionKind::Freestanding,
1292            params: vec![("p1".into(), Type::Id(t1)), ("p2".into(), Type::U32)],
1293            result: Some(Type::Id(t2)),
1294            docs: Docs::default(),
1295            stability: Stability::Unknown,
1296        }
1297        .find_futures_and_streams(&resolve);
1298        assert_eq!(3, found.len());
1299        assert_eq!(t0, found[0]);
1300        assert_eq!(t1, found[1]);
1301        assert_eq!(t2, found[2]);
1302    }
1303}