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(start:0, id: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: &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: &String) = &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: &PackageName 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: String) => name,
456 WorldKey::Interface(id: 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: String) => 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, .. } => stability,
502 WorldItem::Function(f: &Function) => &f.stability,
503 WorldItem::Type(id: &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(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: &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: usize if n <= 8 => FlagsRepr::U8,
704 n: usize if n <= 16 => FlagsRepr::U16,
705 n: usize => FlagsRepr::U32(sizealign::align_to(val:n, align: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: &usize) => *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: usize) if n <= u8::max_value() as usize => Int::U8,
773 Some(n: usize) if n <= u16::max_value() as usize => Int::U16,
774 Some(n: usize) 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
798pub type Params = Vec<(String, Type)>;
799
800#[derive(Debug, Clone, PartialEq, Eq, Hash)]
801#[cfg_attr(feature = "serde", derive(Serialize))]
802#[cfg_attr(feature = "serde", serde(untagged))]
803pub enum Results {
804 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_params"))]
805 Named(Params),
806 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_anon_result"))]
807 Anon(Type),
808}
809
810pub enum ResultsTypeIter<'a> {
811 Named(std::slice::Iter<'a, (String, Type)>),
812 Anon(std::iter::Once<&'a Type>),
813}
814
815impl<'a> Iterator for ResultsTypeIter<'a> {
816 type Item = &'a Type;
817
818 fn next(&mut self) -> Option<&'a Type> {
819 match self {
820 ResultsTypeIter::Named(ps: &mut Iter<'_, (String, Type)>) => ps.next().map(|p: &(String, Type)| &p.1),
821 ResultsTypeIter::Anon(ty: impl Iterator) => ty.next(),
822 }
823 }
824
825 fn size_hint(&self) -> (usize, Option<usize>) {
826 match self {
827 ResultsTypeIter::Named(ps: &Iter<'_, (String, Type)>) => ps.size_hint(),
828 ResultsTypeIter::Anon(ty: &Once<&Type>) => ty.size_hint(),
829 }
830 }
831}
832
833impl<'a> ExactSizeIterator for ResultsTypeIter<'a> {}
834
835impl Results {
836 // For the common case of an empty results list.
837 pub fn empty() -> Results {
838 Results::Named(Vec::new())
839 }
840
841 pub fn len(&self) -> usize {
842 match self {
843 Results::Named(params) => params.len(),
844 Results::Anon(_) => 1,
845 }
846 }
847
848 pub fn throws<'a>(&self, resolve: &'a Resolve) -> Option<(Option<&'a Type>, Option<&'a Type>)> {
849 if self.len() != 1 {
850 return None;
851 }
852 match self.iter_types().next().unwrap() {
853 Type::Id(id) => match &resolve.types[*id].kind {
854 TypeDefKind::Result(r) => Some((r.ok.as_ref(), r.err.as_ref())),
855 _ => None,
856 },
857 _ => None,
858 }
859 }
860
861 pub fn iter_types(&self) -> ResultsTypeIter {
862 match self {
863 Results::Named(ps) => ResultsTypeIter::Named(ps.iter()),
864 Results::Anon(ty) => ResultsTypeIter::Anon(std::iter::once(ty)),
865 }
866 }
867}
868
869#[derive(Debug, Clone, PartialEq, Eq)]
870#[cfg_attr(feature = "serde", derive(Serialize))]
871pub struct Function {
872 pub name: String,
873 pub kind: FunctionKind,
874 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_params"))]
875 pub params: Params,
876 pub results: Results,
877 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
878 pub docs: Docs,
879 /// Stability attribute for this function.
880 #[cfg_attr(
881 feature = "serde",
882 serde(skip_serializing_if = "Stability::is_unknown")
883 )]
884 pub stability: Stability,
885}
886
887#[derive(Debug, Clone, PartialEq, Eq)]
888#[cfg_attr(feature = "serde", derive(Serialize))]
889#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
890pub enum FunctionKind {
891 Freestanding,
892 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
893 Method(TypeId),
894 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
895 Static(TypeId),
896 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
897 Constructor(TypeId),
898}
899
900impl FunctionKind {
901 /// Returns the resource, if present, that this function kind refers to.
902 pub fn resource(&self) -> Option<TypeId> {
903 match self {
904 FunctionKind::Freestanding => None,
905 FunctionKind::Method(id: &Id) | FunctionKind::Static(id: &Id) | FunctionKind::Constructor(id: &Id) => {
906 Some(*id)
907 }
908 }
909 }
910}
911
912/// Possible forms of name mangling that are supported by this crate.
913#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
914pub enum Mangling {
915 /// The "standard" component model mangling format for 32-bit linear
916 /// memories. This is specified in WebAssembly/component-model#378
917 Standard32,
918
919 /// The "legacy" name mangling supported in versions 218-and-prior for this
920 /// crate. This is the original support for how components were created from
921 /// core wasm modules and this does not correspond to any standard. This is
922 /// preserved for now while tools transition to the new scheme.
923 Legacy,
924}
925
926impl std::str::FromStr for Mangling {
927 type Err = anyhow::Error;
928
929 fn from_str(s: &str) -> Result<Mangling> {
930 match s {
931 "legacy" => Ok(Mangling::Legacy),
932 "standard32" => Ok(Mangling::Standard32),
933 _ => {
934 bail!(
935 "unknown name mangling `{s}`, \
936 supported values are `legacy` or `standard32`"
937 )
938 }
939 }
940 }
941}
942
943/// Possible lift/lower ABI choices supported when mangling names.
944#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
945pub enum LiftLowerAbi {
946 /// Both imports and exports will use the synchronous ABI.
947 Sync,
948
949 /// Both imports and exports will use the async ABI (with a callback for
950 /// each export).
951 AsyncCallback,
952
953 /// Both imports and exports will use the async ABI (with no callbacks for
954 /// exports).
955 AsyncStackful,
956}
957
958impl LiftLowerAbi {
959 fn import_prefix(self) -> &'static str {
960 match self {
961 Self::Sync => "",
962 Self::AsyncCallback | Self::AsyncStackful => "[async]",
963 }
964 }
965
966 /// Get the import [`AbiVariant`] corresponding to this [`LiftLowerAbi`]
967 pub fn import_variant(self) -> AbiVariant {
968 match self {
969 Self::Sync => AbiVariant::GuestImport,
970 Self::AsyncCallback | Self::AsyncStackful => AbiVariant::GuestImportAsync,
971 }
972 }
973
974 fn export_prefix(self) -> &'static str {
975 match self {
976 Self::Sync => "",
977 Self::AsyncCallback => "[async]",
978 Self::AsyncStackful => "[async-stackful]",
979 }
980 }
981
982 /// Get the export [`AbiVariant`] corresponding to this [`LiftLowerAbi`]
983 pub fn export_variant(self) -> AbiVariant {
984 match self {
985 Self::Sync => AbiVariant::GuestExport,
986 Self::AsyncCallback => AbiVariant::GuestExportAsync,
987 Self::AsyncStackful => AbiVariant::GuestExportAsyncStackful,
988 }
989 }
990}
991
992/// Combination of [`Mangling`] and [`LiftLowerAbi`].
993#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
994pub enum ManglingAndAbi {
995 /// See [`Mangling::Standard32`].
996 ///
997 /// As of this writing, the standard name mangling only supports the
998 /// synchronous ABI.
999 Standard32,
1000
1001 /// See [`Mangling::Legacy`] and [`LiftLowerAbi`].
1002 Legacy(LiftLowerAbi),
1003}
1004
1005impl ManglingAndAbi {
1006 /// Get the import [`AbiVariant`] corresponding to this [`ManglingAndAbi`]
1007 pub fn import_variant(self) -> AbiVariant {
1008 match self {
1009 Self::Standard32 => AbiVariant::GuestImport,
1010 Self::Legacy(abi: LiftLowerAbi) => abi.import_variant(),
1011 }
1012 }
1013
1014 /// Get the export [`AbiVariant`] corresponding to this [`ManglingAndAbi`]
1015 pub fn export_variant(self) -> AbiVariant {
1016 match self {
1017 Self::Standard32 => AbiVariant::GuestExport,
1018 Self::Legacy(abi: LiftLowerAbi) => abi.export_variant(),
1019 }
1020 }
1021}
1022
1023impl Function {
1024 pub fn item_name(&self) -> &str {
1025 match &self.kind {
1026 FunctionKind::Freestanding => &self.name,
1027 FunctionKind::Method(_) | FunctionKind::Static(_) => {
1028 &self.name[self.name.find('.').unwrap() + 1..]
1029 }
1030 FunctionKind::Constructor(_) => "constructor",
1031 }
1032 }
1033
1034 /// Returns an iterator over the types used in parameters and results.
1035 ///
1036 /// Note that this iterator is not transitive, it only iterates over the
1037 /// direct references to types that this function has.
1038 pub fn parameter_and_result_types(&self) -> impl Iterator<Item = Type> + '_ {
1039 self.params
1040 .iter()
1041 .map(|(_, t)| *t)
1042 .chain(self.results.iter_types().copied())
1043 }
1044
1045 /// Gets the core export name for this function.
1046 pub fn standard32_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1047 self.core_export_name(interface, Mangling::Standard32)
1048 }
1049
1050 pub fn legacy_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1051 self.core_export_name(interface, Mangling::Legacy)
1052 }
1053 /// Gets the core export name for this function.
1054 pub fn core_export_name<'a>(
1055 &'a self,
1056 interface: Option<&str>,
1057 mangling: Mangling,
1058 ) -> Cow<'a, str> {
1059 match interface {
1060 Some(interface) => match mangling {
1061 Mangling::Standard32 => Cow::Owned(format!("cm32p2|{interface}|{}", self.name)),
1062 Mangling::Legacy => Cow::Owned(format!("{interface}#{}", self.name)),
1063 },
1064 None => match mangling {
1065 Mangling::Standard32 => Cow::Owned(format!("cm32p2||{}", self.name)),
1066 Mangling::Legacy => Cow::Borrowed(&self.name),
1067 },
1068 }
1069 }
1070 /// Collect any future and stream types appearing in the signature of this
1071 /// function by doing a depth-first search over the parameter types and then
1072 /// the result types.
1073 ///
1074 /// For example, given the WIT function `foo: func(x: future<future<u32>>,
1075 /// y: u32) -> stream<u8>`, we would return `[future<u32>,
1076 /// future<future<u32>>, stream<u8>]`.
1077 ///
1078 /// This may be used by binding generators to refer to specific `future` and
1079 /// `stream` types when importing canonical built-ins such as `stream.new`,
1080 /// `future.read`, etc. Using the example above, the import
1081 /// `[future-new-0]foo` would indicate a call to `future.new` for the type
1082 /// `future<u32>`. Likewise, `[future-new-1]foo` would indicate a call to
1083 /// `future.new` for `future<future<u32>>`, and `[stream-new-2]foo` would
1084 /// indicate a call to `stream.new` for `stream<u8>`.
1085 pub fn find_futures_and_streams(&self, resolve: &Resolve) -> Vec<TypeId> {
1086 let mut results = Vec::new();
1087 for (_, ty) in self.params.iter() {
1088 find_futures_and_streams(resolve, *ty, &mut results);
1089 }
1090 for ty in self.results.iter_types() {
1091 find_futures_and_streams(resolve, *ty, &mut results);
1092 }
1093 results
1094 }
1095}
1096
1097fn find_futures_and_streams(resolve: &Resolve, ty: Type, results: &mut Vec<TypeId>) {
1098 let Type::Id(id) = ty else {
1099 return;
1100 };
1101
1102 match &resolve.types[id].kind {
1103 TypeDefKind::Resource
1104 | TypeDefKind::Handle(_)
1105 | TypeDefKind::Flags(_)
1106 | TypeDefKind::Enum(_)
1107 | TypeDefKind::ErrorContext => {}
1108 TypeDefKind::Record(r) => {
1109 for Field { ty, .. } in &r.fields {
1110 find_futures_and_streams(resolve, *ty, results);
1111 }
1112 }
1113 TypeDefKind::Tuple(t) => {
1114 for ty in &t.types {
1115 find_futures_and_streams(resolve, *ty, results);
1116 }
1117 }
1118 TypeDefKind::Variant(v) => {
1119 for Case { ty, .. } in &v.cases {
1120 if let Some(ty) = ty {
1121 find_futures_and_streams(resolve, *ty, results);
1122 }
1123 }
1124 }
1125 TypeDefKind::Option(ty) | TypeDefKind::List(ty) | TypeDefKind::Type(ty) => {
1126 find_futures_and_streams(resolve, *ty, results);
1127 }
1128 TypeDefKind::Result(r) => {
1129 if let Some(ty) = r.ok {
1130 find_futures_and_streams(resolve, ty, results);
1131 }
1132 if let Some(ty) = r.err {
1133 find_futures_and_streams(resolve, ty, results);
1134 }
1135 }
1136 TypeDefKind::Future(ty) => {
1137 if let Some(ty) = ty {
1138 find_futures_and_streams(resolve, *ty, results);
1139 }
1140 results.push(id);
1141 }
1142 TypeDefKind::Stream(ty) => {
1143 find_futures_and_streams(resolve, *ty, results);
1144 results.push(id);
1145 }
1146 TypeDefKind::Unknown => unreachable!(),
1147 }
1148}
1149
1150/// Representation of the stability attributes associated with a world,
1151/// interface, function, or type.
1152///
1153/// This is added for WebAssembly/component-model#332 where @since and @unstable
1154/// annotations were added to WIT.
1155#[derive(Debug, Clone, PartialEq, Eq)]
1156#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize, Serialize))]
1157#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1158pub enum Stability {
1159 /// `@since(version = 1.2.3)`
1160 ///
1161 /// This item is explicitly tagged with `@since` as stable since the
1162 /// specified version. This may optionally have a feature listed as well.
1163 Stable {
1164 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_version"))]
1165 #[cfg_attr(feature = "serde", serde(deserialize_with = "deserialize_version"))]
1166 since: Version,
1167 #[cfg_attr(
1168 feature = "serde",
1169 serde(
1170 skip_serializing_if = "Option::is_none",
1171 default,
1172 serialize_with = "serialize_optional_version",
1173 deserialize_with = "deserialize_optional_version"
1174 )
1175 )]
1176 deprecated: Option<Version>,
1177 },
1178
1179 /// `@unstable(feature = foo)`
1180 ///
1181 /// This item is explicitly tagged `@unstable`. A feature name is listed and
1182 /// this item is excluded by default in `Resolve` unless explicitly enabled.
1183 Unstable {
1184 feature: String,
1185 #[cfg_attr(
1186 feature = "serde",
1187 serde(
1188 skip_serializing_if = "Option::is_none",
1189 default,
1190 serialize_with = "serialize_optional_version",
1191 deserialize_with = "deserialize_optional_version"
1192 )
1193 )]
1194 deprecated: Option<Version>,
1195 },
1196
1197 /// This item does not have either `@since` or `@unstable`.
1198 Unknown,
1199}
1200
1201impl Stability {
1202 /// Returns whether this is `Stability::Unknown`.
1203 pub fn is_unknown(&self) -> bool {
1204 matches!(self, Stability::Unknown)
1205 }
1206}
1207
1208impl Default for Stability {
1209 fn default() -> Stability {
1210 Stability::Unknown
1211 }
1212}
1213
1214#[cfg(test)]
1215mod test {
1216 use super::*;
1217
1218 #[test]
1219 fn test_discriminant_type() {
1220 assert_eq!(discriminant_type(1), Int::U8);
1221 assert_eq!(discriminant_type(0x100), Int::U8);
1222 assert_eq!(discriminant_type(0x101), Int::U16);
1223 assert_eq!(discriminant_type(0x10000), Int::U16);
1224 assert_eq!(discriminant_type(0x10001), Int::U32);
1225 if let Ok(num_cases) = usize::try_from(0x100000000_u64) {
1226 assert_eq!(discriminant_type(num_cases), Int::U32);
1227 }
1228 }
1229
1230 #[test]
1231 fn test_find_futures_and_streams() {
1232 let mut resolve = Resolve::default();
1233 let t0 = resolve.types.alloc(TypeDef {
1234 name: None,
1235 kind: TypeDefKind::Future(Some(Type::U32)),
1236 owner: TypeOwner::None,
1237 docs: Docs::default(),
1238 stability: Stability::Unknown,
1239 });
1240 let t1 = resolve.types.alloc(TypeDef {
1241 name: None,
1242 kind: TypeDefKind::Future(Some(Type::Id(t0))),
1243 owner: TypeOwner::None,
1244 docs: Docs::default(),
1245 stability: Stability::Unknown,
1246 });
1247 let t2 = resolve.types.alloc(TypeDef {
1248 name: None,
1249 kind: TypeDefKind::Stream(Type::U32),
1250 owner: TypeOwner::None,
1251 docs: Docs::default(),
1252 stability: Stability::Unknown,
1253 });
1254 let found = Function {
1255 name: "foo".into(),
1256 kind: FunctionKind::Freestanding,
1257 params: vec![("p1".into(), Type::Id(t1)), ("p2".into(), Type::U32)],
1258 results: Results::Anon(Type::Id(t2)),
1259 docs: Docs::default(),
1260 stability: Stability::Unknown,
1261 }
1262 .find_futures_and_streams(&resolve);
1263 assert_eq!(3, found.len());
1264 assert_eq!(t0, found[0]);
1265 assert_eq!(t1, found[1]);
1266 assert_eq!(t2, found[2]);
1267 }
1268}
1269