1#![no_std]
2
3extern crate alloc;
4
5#[cfg(feature = "std")]
6extern crate std;
7
8use crate::abi::AbiVariant;
9use alloc::format;
10use alloc::string::{String, ToString};
11use alloc::vec::Vec;
12use id_arena::{Arena, Id};
13use semver::Version;
14
15#[cfg(feature = "std")]
16pub type IndexMap<K, V> = indexmap::IndexMap<K, V, std::hash::RandomState>;
17#[cfg(feature = "std")]
18pub type IndexSet<T> = indexmap::IndexSet<T, std::hash::RandomState>;
19#[cfg(not(feature = "std"))]
20pub type IndexMap<K, V> = indexmap::IndexMap<K, V, hashbrown::DefaultHashBuilder>;
21#[cfg(not(feature = "std"))]
22pub type IndexSet<T> = indexmap::IndexSet<T, hashbrown::DefaultHashBuilder>;
23
24#[cfg(feature = "std")]
25pub(crate) use std::collections::{HashMap, HashSet};
26
27#[cfg(not(feature = "std"))]
28pub(crate) use hashbrown::{HashMap, HashSet};
29
30use alloc::borrow::Cow;
31use core::fmt;
32use core::hash::{Hash, Hasher};
33#[cfg(feature = "std")]
34use std::path::Path;
35
36#[cfg(feature = "decoding")]
37pub mod decoding;
38#[cfg(feature = "decoding")]
39mod metadata;
40#[cfg(feature = "decoding")]
41pub use metadata::PackageMetadata;
42
43pub mod abi;
44mod ast;
45pub use ast::error::*;
46pub use ast::lex::Span;
47pub use ast::{ItemName, SourceMap, SpanLocation};
48pub use ast::{ParsedUsePath, parse_use_path};
49mod sizealign;
50pub use sizealign::*;
51mod resolve;
52pub use resolve::error::*;
53pub use resolve::*;
54mod live;
55pub use live::{LiveTypes, TypeIdVisitor};
56
57#[cfg(feature = "serde")]
58use serde_derive::Serialize;
59#[cfg(feature = "serde")]
60mod serde_;
61#[cfg(feature = "serde")]
62use serde_::*;
63
64pub fn validate_id(s: &str) -> anyhow::Result<()> {
66 ast::validate_id(0, s)?;
67 Ok(())
68}
69
70pub(crate) fn parse_component_name(
74 name: &str,
75) -> wasmparser::Result<wasmparser::names::ComponentName> {
76 wasmparser::names::ComponentName::new_with_features(name, 0, wasmparser::WasmFeatures::all())
77}
78
79#[cfg(feature = "std")]
92pub fn render_anyhow_error(err: &anyhow::Error, source_map: &SourceMap) -> String {
93 err.chain()
94 .map(|layer| {
95 if let Some(re) = layer.downcast_ref::<ResolveError>() {
96 re.render(source_map)
97 } else if let Some(pe) = layer.downcast_ref::<ParseError>() {
98 pe.render(source_map)
99 } else {
100 layer.to_string()
101 }
102 })
103 .collect::<Vec<_>>()
104 .join(": ")
105}
106
107pub type WorldId = Id<World>;
108pub type InterfaceId = Id<Interface>;
109pub type TypeId = Id<TypeDef>;
110
111#[derive(Clone, Debug, PartialEq, Eq)]
137pub struct UnresolvedPackage {
138 pub name: PackageName,
140
141 pub worlds: Arena<World>,
145
146 pub interfaces: Arena<Interface>,
153
154 pub types: Arena<TypeDef>,
161
162 pub foreign_deps: IndexMap<PackageName, IndexMap<String, (AstItem, Vec<Stability>)>>,
171
172 pub docs: Docs,
174
175 #[cfg_attr(not(feature = "std"), allow(dead_code))]
176 package_name_span: Span,
177 unknown_type_spans: Vec<Span>,
178 foreign_dep_spans: Vec<Span>,
179 required_resource_types: Vec<(TypeId, Span)>,
180}
181
182impl UnresolvedPackage {
183 pub(crate) fn adjust_spans(&mut self, offset: u32) {
188 self.package_name_span.adjust(offset);
190 for span in &mut self.unknown_type_spans {
191 span.adjust(offset);
192 }
193 for span in &mut self.foreign_dep_spans {
194 span.adjust(offset);
195 }
196 for (_, span) in &mut self.required_resource_types {
197 span.adjust(offset);
198 }
199
200 for (_, world) in self.worlds.iter_mut() {
202 world.adjust_spans(offset);
203 }
204 for (_, iface) in self.interfaces.iter_mut() {
205 iface.adjust_spans(offset);
206 }
207 for (_, ty) in self.types.iter_mut() {
208 ty.adjust_spans(offset);
209 }
210 }
211}
212
213#[derive(Clone, Debug, PartialEq, Eq)]
215pub struct UnresolvedPackageGroup {
216 pub main: UnresolvedPackage,
221
222 pub nested: Vec<UnresolvedPackage>,
224
225 pub source_map: SourceMap,
227}
228
229#[derive(Debug, Copy, Clone, PartialEq, Eq)]
230#[cfg_attr(feature = "serde", derive(Serialize))]
231#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
232pub enum AstItem {
233 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
234 Interface(InterfaceId),
235 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
236 World(WorldId),
237}
238
239#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
245#[cfg_attr(feature = "serde", derive(Serialize))]
246#[cfg_attr(feature = "serde", serde(into = "String"))]
247pub struct PackageName {
248 pub namespace: String,
250 pub name: String,
252 pub version: Option<Version>,
254}
255
256impl From<PackageName> for String {
257 fn from(name: PackageName) -> String {
258 name.to_string()
259 }
260}
261
262impl PackageName {
263 pub fn interface_id(&self, interface: &str) -> String {
266 let mut s = String::new();
267 s.push_str(&format!("{}:{}/{interface}", self.namespace, self.name));
268 if let Some(version) = &self.version {
269 s.push_str(&format!("@{version}"));
270 }
271 s
272 }
273
274 pub fn version_compat_track(version: &Version) -> (Version, Option<String>) {
288 let (_, suffix) = Self::version_compat_track_string(version);
289 let mut version = version.clone();
290 version.build = semver::BuildMetadata::EMPTY;
291 if version.pre.is_empty() {
292 if version.major != 0 {
293 version.minor = 0;
294 version.patch = 0;
295 } else if version.minor != 0 {
296 version.patch = 0;
297 }
298 }
299 (version, suffix)
300 }
301
302 pub fn version_compat_track_string(version: &Version) -> (String, Option<String>) {
309 let version = version.to_string();
310 let (track, suffix) = wasmparser::names::split_canonical_version(&version)
311 .expect("a `Version` should always display as a valid version");
312 (track.to_string(), suffix.map(|s| s.to_string()))
313 }
314}
315
316impl fmt::Display for PackageName {
317 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
318 write!(f, "{}:{}", self.namespace, self.name)?;
319 if let Some(version) = &self.version {
320 write!(f, "@{version}")?;
321 }
322 Ok(())
323 }
324}
325
326impl UnresolvedPackageGroup {
327 #[cfg(feature = "std")]
337 pub fn parse(
338 path: impl AsRef<Path>,
339 contents: &str,
340 ) -> Result<UnresolvedPackageGroup, (SourceMap, ParseError)> {
341 let mut map = SourceMap::default();
342 map.push(path.as_ref(), contents);
343 map.parse()
344 }
345
346 #[cfg(feature = "std")]
353 pub fn parse_dir(path: impl AsRef<Path>) -> anyhow::Result<UnresolvedPackageGroup> {
354 let mut map = SourceMap::default();
355 map.push_dir(path.as_ref())?;
356 map.parse().map_err(|(map, e)| {
357 let rendered = e.render(&map);
358 anyhow::Error::from(e).context(rendered)
359 })
360 }
361}
362
363#[derive(Debug, Clone, PartialEq, Eq)]
364#[cfg_attr(feature = "serde", derive(Serialize))]
365pub struct World {
366 pub name: String,
368
369 pub imports: IndexMap<WorldKey, WorldItem>,
371
372 pub exports: IndexMap<WorldKey, WorldItem>,
374
375 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_optional_id"))]
377 pub package: Option<PackageId>,
378
379 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
381 pub docs: Docs,
382
383 #[cfg_attr(
385 feature = "serde",
386 serde(skip_serializing_if = "Stability::is_unknown")
387 )]
388 pub stability: Stability,
389
390 #[cfg_attr(feature = "serde", serde(skip))]
392 pub includes: Vec<WorldInclude>,
393
394 #[cfg_attr(feature = "serde", serde(skip))]
396 pub span: Span,
397}
398
399impl World {
400 pub(crate) fn adjust_spans(&mut self, offset: u32) {
402 self.span.adjust(offset);
403 for item in self.imports.values_mut().chain(self.exports.values_mut()) {
404 item.adjust_spans(offset);
405 }
406 for include in &mut self.includes {
407 include.span.adjust(offset);
408 }
409 }
410}
411
412#[derive(Debug, Clone, PartialEq, Eq)]
413pub struct IncludeName {
414 pub name: String,
416
417 pub as_: String,
419}
420
421#[derive(Debug, Clone, PartialEq, Eq)]
424pub struct WorldInclude {
425 pub stability: Stability,
427
428 pub id: WorldId,
430
431 pub names: Vec<IncludeName>,
433
434 pub span: Span,
436}
437
438#[derive(Debug, Clone, Eq)]
441#[cfg_attr(feature = "serde", derive(Serialize))]
442#[cfg_attr(feature = "serde", serde(into = "String"))]
443pub enum WorldKey {
444 Name(String),
446 Interface(InterfaceId),
448}
449
450impl Hash for WorldKey {
451 fn hash<H: Hasher>(&self, hasher: &mut H) {
452 match self {
453 WorldKey::Name(s) => {
454 0u8.hash(hasher);
455 s.as_str().hash(hasher);
456 }
457 WorldKey::Interface(i) => {
458 1u8.hash(hasher);
459 i.hash(hasher);
460 }
461 }
462 }
463}
464
465impl PartialEq for WorldKey {
466 fn eq(&self, other: &WorldKey) -> bool {
467 match (self, other) {
468 (WorldKey::Name(a), WorldKey::Name(b)) => a.as_str() == b.as_str(),
469 (WorldKey::Name(_), _) => false,
470 (WorldKey::Interface(a), WorldKey::Interface(b)) => a == b,
471 (WorldKey::Interface(_), _) => false,
472 }
473 }
474}
475
476impl From<WorldKey> for String {
477 fn from(key: WorldKey) -> String {
478 match key {
479 WorldKey::Name(name) => name,
480 WorldKey::Interface(id) => format!("interface-{}", id.index()),
481 }
482 }
483}
484
485impl WorldKey {
486 #[track_caller]
488 pub fn unwrap_name(self) -> String {
489 match self {
490 WorldKey::Name(name) => name,
491 WorldKey::Interface(_) => panic!("expected a name, found interface"),
492 }
493 }
494}
495
496#[derive(Debug, Clone, PartialEq, Eq)]
497#[cfg_attr(feature = "serde", derive(Serialize))]
498#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
499pub enum WorldItem {
500 Interface {
503 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
504 id: InterfaceId,
505 #[cfg_attr(
506 feature = "serde",
507 serde(skip_serializing_if = "Stability::is_unknown")
508 )]
509 stability: Stability,
510 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
511 external_id: Option<String>,
512 #[cfg_attr(
514 feature = "serde",
515 serde(default, skip_serializing_if = "Docs::is_empty")
516 )]
517 docs: Docs,
518 #[cfg_attr(feature = "serde", serde(skip))]
519 span: Span,
520 },
521
522 Function(Function),
524
525 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id_ignore_span"))]
529 Type { id: TypeId, span: Span },
530}
531
532impl WorldItem {
533 pub fn stability<'a>(&'a self, resolve: &'a Resolve) -> &'a Stability {
534 match self {
535 WorldItem::Interface { stability, .. } => stability,
536 WorldItem::Function(f) => &f.stability,
537 WorldItem::Type { id, .. } => &resolve.types[*id].stability,
538 }
539 }
540
541 pub fn span(&self) -> Span {
542 match self {
543 WorldItem::Interface { span, .. } => *span,
544 WorldItem::Function(f) => f.span,
545 WorldItem::Type { span, .. } => *span,
546 }
547 }
548
549 pub(crate) fn adjust_spans(&mut self, offset: u32) {
550 match self {
551 WorldItem::Function(f) => f.adjust_spans(offset),
552 WorldItem::Interface { span, .. } => span.adjust(offset),
553 WorldItem::Type { span, .. } => span.adjust(offset),
554 }
555 }
556}
557
558#[derive(Debug, Clone, PartialEq, Eq)]
559#[cfg_attr(feature = "serde", derive(Serialize))]
560pub struct Interface {
561 pub name: Option<String>,
565
566 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id_map"))]
571 pub types: IndexMap<String, TypeId>,
572
573 pub functions: IndexMap<String, Function>,
575
576 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
578 pub docs: Docs,
579
580 #[cfg_attr(
582 feature = "serde",
583 serde(skip_serializing_if = "Stability::is_unknown")
584 )]
585 pub stability: Stability,
586
587 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_optional_id"))]
589 pub package: Option<PackageId>,
590
591 #[cfg_attr(feature = "serde", serde(skip))]
593 pub span: Span,
594
595 #[cfg_attr(
599 feature = "serde",
600 serde(
601 skip_serializing_if = "Option::is_none",
602 serialize_with = "serialize_optional_id",
603 )
604 )]
605 pub clone_of: Option<InterfaceId>,
606}
607
608impl Interface {
609 pub(crate) fn adjust_spans(&mut self, offset: u32) {
611 self.span.adjust(offset);
612 for func in self.functions.values_mut() {
613 func.adjust_spans(offset);
614 }
615 }
616}
617
618#[derive(Debug, Clone, PartialEq, Eq)]
619#[cfg_attr(feature = "serde", derive(Serialize))]
620pub struct TypeDef {
621 pub name: Option<String>,
622 pub kind: TypeDefKind,
623 pub owner: TypeOwner,
624 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
625 pub docs: Docs,
626 #[cfg_attr(
628 feature = "serde",
629 serde(skip_serializing_if = "Stability::is_unknown")
630 )]
631 pub stability: Stability,
632 #[cfg_attr(feature = "serde", serde(skip))]
634 pub span: Span,
635 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
636 pub external_id: Option<String>,
637}
638
639impl TypeDef {
640 pub(crate) fn adjust_spans(&mut self, offset: u32) {
645 self.span.adjust(offset);
646 match &mut self.kind {
647 TypeDefKind::Record(r) => {
648 for field in &mut r.fields {
649 field.span.adjust(offset);
650 }
651 }
652 TypeDefKind::Variant(v) => {
653 for case in &mut v.cases {
654 case.span.adjust(offset);
655 }
656 }
657 TypeDefKind::Enum(e) => {
658 for case in &mut e.cases {
659 case.span.adjust(offset);
660 }
661 }
662 TypeDefKind::Flags(f) => {
663 for flag in &mut f.flags {
664 flag.span.adjust(offset);
665 }
666 }
667 _ => {}
668 }
669 }
670}
671
672#[derive(Debug, Clone, PartialEq, Hash, Eq)]
673#[cfg_attr(feature = "serde", derive(Serialize))]
674#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
675pub enum TypeDefKind {
676 Record(Record),
677 Resource,
678 Handle(Handle),
679 Flags(Flags),
680 Tuple(Tuple),
681 Variant(Variant),
682 Enum(Enum),
683 Option(Type),
684 Result(Result_),
685 List(Type),
686 Map(Type, Type),
687 FixedLengthList(Type, u32),
688 Future(Option<Type>),
689 Stream(Option<Type>),
690 Type(Type),
691
692 Unknown,
698}
699
700impl TypeDefKind {
701 pub fn as_str(&self) -> &'static str {
702 match self {
703 TypeDefKind::Record(_) => "record",
704 TypeDefKind::Resource => "resource",
705 TypeDefKind::Handle(handle) => match handle {
706 Handle::Own(_) => "own",
707 Handle::Borrow(_) => "borrow",
708 },
709 TypeDefKind::Flags(_) => "flags",
710 TypeDefKind::Tuple(_) => "tuple",
711 TypeDefKind::Variant(_) => "variant",
712 TypeDefKind::Enum(_) => "enum",
713 TypeDefKind::Option(_) => "option",
714 TypeDefKind::Result(_) => "result",
715 TypeDefKind::List(_) => "list",
716 TypeDefKind::Map(_, _) => "map",
717 TypeDefKind::FixedLengthList(..) => "fixed-length list",
718 TypeDefKind::Future(_) => "future",
719 TypeDefKind::Stream(_) => "stream",
720 TypeDefKind::Type(_) => "type",
721 TypeDefKind::Unknown => "unknown",
722 }
723 }
724}
725
726#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
727#[cfg_attr(feature = "serde", derive(Serialize))]
728#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
729pub enum TypeOwner {
730 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
732 World(WorldId),
733 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
735 Interface(InterfaceId),
736 #[cfg_attr(feature = "serde", serde(untagged, serialize_with = "serialize_none"))]
739 None,
740}
741
742#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
743#[cfg_attr(feature = "serde", derive(Serialize))]
744#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
745pub enum Handle {
746 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
747 Own(TypeId),
748 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
749 Borrow(TypeId),
750}
751
752#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
753pub enum Type {
754 Bool,
755 U8,
756 U16,
757 U32,
758 U64,
759 S8,
760 S16,
761 S32,
762 S64,
763 F32,
764 F64,
765 Char,
766 String,
767 ErrorContext,
768 Id(TypeId),
769}
770
771#[derive(Debug, Copy, Clone, Eq, PartialEq)]
772pub enum Int {
773 U8,
774 U16,
775 U32,
776 U64,
777}
778
779#[derive(Debug, Clone, PartialEq, Hash, Eq)]
780#[cfg_attr(feature = "serde", derive(Serialize))]
781pub struct Record {
782 pub fields: Vec<Field>,
783}
784
785#[derive(Debug, Clone, PartialEq, Hash, Eq)]
786#[cfg_attr(feature = "serde", derive(Serialize))]
787pub struct Field {
788 pub name: String,
789 #[cfg_attr(feature = "serde", serde(rename = "type"))]
790 pub ty: Type,
791 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
792 pub docs: Docs,
793 #[cfg_attr(feature = "serde", serde(skip))]
795 pub span: Span,
796}
797
798#[derive(Debug, Clone, PartialEq, Hash, Eq)]
799#[cfg_attr(feature = "serde", derive(Serialize))]
800pub struct Flags {
801 pub flags: Vec<Flag>,
802}
803
804#[derive(Debug, Clone, PartialEq, Hash, Eq)]
805#[cfg_attr(feature = "serde", derive(Serialize))]
806pub struct Flag {
807 pub name: String,
808 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
809 pub docs: Docs,
810 #[cfg_attr(feature = "serde", serde(skip))]
812 pub span: Span,
813}
814
815#[derive(Debug, Clone, PartialEq)]
816pub enum FlagsRepr {
817 U8,
818 U16,
819 U32(usize),
820}
821
822impl Flags {
823 pub fn repr(&self) -> FlagsRepr {
824 match self.flags.len() {
825 0 => FlagsRepr::U32(0),
826 n if n <= 8 => FlagsRepr::U8,
827 n if n <= 16 => FlagsRepr::U16,
828 n => FlagsRepr::U32(sizealign::align_to(n, 32) / 32),
829 }
830 }
831}
832
833impl FlagsRepr {
834 pub fn count(&self) -> usize {
835 match self {
836 FlagsRepr::U8 => 1,
837 FlagsRepr::U16 => 1,
838 FlagsRepr::U32(n) => *n,
839 }
840 }
841}
842
843#[derive(Debug, Clone, PartialEq, Hash, Eq)]
844#[cfg_attr(feature = "serde", derive(Serialize))]
845pub struct Tuple {
846 pub types: Vec<Type>,
847}
848
849#[derive(Debug, Clone, PartialEq, Hash, Eq)]
850#[cfg_attr(feature = "serde", derive(Serialize))]
851pub struct Variant {
852 pub cases: Vec<Case>,
853}
854
855#[derive(Debug, Clone, PartialEq, Hash, Eq)]
856#[cfg_attr(feature = "serde", derive(Serialize))]
857pub struct Case {
858 pub name: String,
859 #[cfg_attr(feature = "serde", serde(rename = "type"))]
860 pub ty: Option<Type>,
861 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
862 pub docs: Docs,
863 #[cfg_attr(feature = "serde", serde(skip))]
865 pub span: Span,
866}
867
868impl Variant {
869 pub fn tag(&self) -> Int {
870 discriminant_type(self.cases.len())
871 }
872}
873
874#[derive(Debug, Clone, PartialEq, Hash, Eq)]
875#[cfg_attr(feature = "serde", derive(Serialize))]
876pub struct Enum {
877 pub cases: Vec<EnumCase>,
878}
879
880#[derive(Debug, Clone, PartialEq, Hash, Eq)]
881#[cfg_attr(feature = "serde", derive(Serialize))]
882pub struct EnumCase {
883 pub name: String,
884 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
885 pub docs: Docs,
886 #[cfg_attr(feature = "serde", serde(skip))]
888 pub span: Span,
889}
890
891impl Enum {
892 pub fn tag(&self) -> Int {
893 discriminant_type(self.cases.len())
894 }
895}
896
897fn discriminant_type(num_cases: usize) -> Int {
899 match num_cases.checked_sub(1) {
900 None => Int::U8,
901 Some(n) if n <= u8::MAX as usize => Int::U8,
902 Some(n) if n <= u16::MAX as usize => Int::U16,
903 Some(n) if n <= u32::MAX as usize => Int::U32,
904 _ => panic!("too many cases to fit in a repr"),
905 }
906}
907
908#[derive(Debug, Clone, PartialEq, Hash, Eq)]
909#[cfg_attr(feature = "serde", derive(Serialize))]
910pub struct Result_ {
911 pub ok: Option<Type>,
912 pub err: Option<Type>,
913}
914
915#[derive(Clone, Default, Debug, PartialEq, Eq, Hash)]
916#[cfg_attr(feature = "serde", derive(Serialize))]
917pub struct Docs {
918 pub contents: Option<String>,
919}
920
921impl Docs {
922 pub fn is_empty(&self) -> bool {
923 self.contents.is_none()
924 }
925}
926
927#[derive(Debug, Clone, PartialEq, Eq)]
928#[cfg_attr(feature = "serde", derive(Serialize))]
929pub struct Param {
930 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "String::is_empty"))]
931 pub name: String,
932 #[cfg_attr(feature = "serde", serde(rename = "type"))]
933 pub ty: Type,
934 #[cfg_attr(feature = "serde", serde(skip))]
935 pub span: Span,
936}
937
938#[derive(Debug, Clone, PartialEq, Eq)]
939#[cfg_attr(feature = "serde", derive(Serialize))]
940pub struct Function {
941 pub name: String,
942 pub kind: FunctionKind,
943 pub params: Vec<Param>,
944 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
945 pub result: Option<Type>,
946 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
947 pub docs: Docs,
948 #[cfg_attr(
950 feature = "serde",
951 serde(skip_serializing_if = "Stability::is_unknown")
952 )]
953 pub stability: Stability,
954
955 #[cfg_attr(feature = "serde", serde(skip))]
957 pub span: Span,
958 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
959 pub external_id: Option<String>,
960}
961
962#[derive(Debug, Clone, PartialEq, Eq)]
963#[cfg_attr(feature = "serde", derive(Serialize))]
964#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
965pub enum FunctionKind {
966 Freestanding,
974
975 AsyncFreestanding,
983
984 Getter,
992
993 Setter,
1002
1003 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1014 Method(TypeId),
1015
1016 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1027 AsyncMethod(TypeId),
1028
1029 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1039 MethodGetter(TypeId),
1040
1041 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1051 MethodSetter(TypeId),
1052
1053 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1063 Static(TypeId),
1064
1065 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1075 AsyncStatic(TypeId),
1076
1077 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1087 StaticGetter(TypeId),
1088
1089 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1099 StaticSetter(TypeId),
1100
1101 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
1111 Constructor(TypeId),
1112}
1113
1114impl FunctionKind {
1115 pub fn is_async(&self) -> bool {
1117 match self {
1118 FunctionKind::Freestanding
1119 | FunctionKind::Method(_)
1120 | FunctionKind::Static(_)
1121 | FunctionKind::Constructor(_)
1122 | FunctionKind::Getter
1123 | FunctionKind::Setter
1124 | FunctionKind::MethodGetter(_)
1125 | FunctionKind::MethodSetter(_)
1126 | FunctionKind::StaticGetter(_)
1127 | FunctionKind::StaticSetter(_) => false,
1128 FunctionKind::AsyncFreestanding
1129 | FunctionKind::AsyncMethod(_)
1130 | FunctionKind::AsyncStatic(_) => true,
1131 }
1132 }
1133
1134 pub fn accessor(&self) -> Option<AccessorKind> {
1136 match self {
1137 FunctionKind::Getter
1138 | FunctionKind::MethodGetter(_)
1139 | FunctionKind::StaticGetter(_) => Some(AccessorKind::Getter),
1140 FunctionKind::Setter
1141 | FunctionKind::MethodSetter(_)
1142 | FunctionKind::StaticSetter(_) => Some(AccessorKind::Setter),
1143 FunctionKind::Freestanding
1144 | FunctionKind::AsyncFreestanding
1145 | FunctionKind::Method(_)
1146 | FunctionKind::AsyncMethod(_)
1147 | FunctionKind::Static(_)
1148 | FunctionKind::AsyncStatic(_)
1149 | FunctionKind::Constructor(_) => None,
1150 }
1151 }
1152
1153 pub fn resource(&self) -> Option<TypeId> {
1155 match self {
1156 FunctionKind::Freestanding
1157 | FunctionKind::AsyncFreestanding
1158 | FunctionKind::Getter
1159 | FunctionKind::Setter => None,
1160 FunctionKind::Method(id)
1161 | FunctionKind::Static(id)
1162 | FunctionKind::Constructor(id)
1163 | FunctionKind::AsyncMethod(id)
1164 | FunctionKind::AsyncStatic(id)
1165 | FunctionKind::MethodGetter(id)
1166 | FunctionKind::MethodSetter(id)
1167 | FunctionKind::StaticGetter(id)
1168 | FunctionKind::StaticSetter(id) => Some(*id),
1169 }
1170 }
1171
1172 pub fn resource_mut(&mut self) -> Option<&mut TypeId> {
1174 match self {
1175 FunctionKind::Freestanding
1176 | FunctionKind::AsyncFreestanding
1177 | FunctionKind::Getter
1178 | FunctionKind::Setter => None,
1179 FunctionKind::Method(id)
1180 | FunctionKind::Static(id)
1181 | FunctionKind::Constructor(id)
1182 | FunctionKind::AsyncMethod(id)
1183 | FunctionKind::AsyncStatic(id)
1184 | FunctionKind::MethodGetter(id)
1185 | FunctionKind::MethodSetter(id)
1186 | FunctionKind::StaticGetter(id)
1187 | FunctionKind::StaticSetter(id) => Some(id),
1188 }
1189 }
1190}
1191
1192#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1194#[cfg_attr(feature = "serde", derive(Serialize))]
1195#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1196pub enum AccessorKind {
1197 Getter,
1199 Setter,
1201}
1202
1203pub(crate) fn place_setters_after_getters<K, V>(
1207 items: &mut IndexMap<K, V>,
1208 func: impl Fn(&V) -> Option<&Function>,
1209) {
1210 let mut getters_seen = HashSet::new();
1217 let mut i = 0;
1218 while let Some((_, item)) = items.get_index(i) {
1219 match func(item) {
1220 Some(f) => match f.kind.accessor() {
1221 Some(AccessorKind::Getter) => {
1222 getters_seen.insert(f.name.clone());
1223 }
1224 Some(AccessorKind::Setter) => {
1225 let getter_name = f.name.replacen("[set]", "[get]", 1);
1226 if !getters_seen.contains(&getter_name) {
1227 let getter_index = (i + 1..items.len())
1229 .find(|&j| func(&items[j]).is_some_and(|g| g.name == getter_name));
1230 if let Some(g) = getter_index {
1231 items.move_index(i, g);
1235 continue;
1236 }
1237 }
1238 }
1239 None => {}
1240 },
1241 None => {}
1242 }
1243 i += 1;
1244 }
1245}
1246
1247pub(crate) fn world_item_func(item: &WorldItem) -> Option<&Function> {
1249 match item {
1250 WorldItem::Function(f) => Some(f),
1251 _ => None,
1252 }
1253}
1254
1255#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1257pub enum Mangling {
1258 Standard32,
1261
1262 Legacy,
1267}
1268
1269impl core::str::FromStr for Mangling {
1270 type Err = anyhow::Error;
1271
1272 fn from_str(s: &str) -> anyhow::Result<Mangling> {
1273 match s {
1274 "legacy" => Ok(Mangling::Legacy),
1275 "standard32" => Ok(Mangling::Standard32),
1276 _ => {
1277 anyhow::bail!(
1278 "unknown name mangling `{s}`, \
1279 supported values are `legacy` or `standard32`"
1280 )
1281 }
1282 }
1283 }
1284}
1285
1286#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1288pub enum LiftLowerAbi {
1289 Sync,
1291
1292 AsyncCallback,
1295
1296 AsyncStackful,
1299}
1300
1301impl LiftLowerAbi {
1302 fn import_prefix(self) -> &'static str {
1303 match self {
1304 Self::Sync => "",
1305 Self::AsyncCallback | Self::AsyncStackful => "[async-lower]",
1306 }
1307 }
1308
1309 pub fn import_variant(self) -> AbiVariant {
1311 match self {
1312 Self::Sync => AbiVariant::GuestImport,
1313 Self::AsyncCallback | Self::AsyncStackful => AbiVariant::GuestImportAsync,
1314 }
1315 }
1316
1317 fn export_prefix(self) -> &'static str {
1318 match self {
1319 Self::Sync => "",
1320 Self::AsyncCallback => "[async-lift]",
1321 Self::AsyncStackful => "[async-lift-stackful]",
1322 }
1323 }
1324
1325 pub fn export_variant(self) -> AbiVariant {
1327 match self {
1328 Self::Sync => AbiVariant::GuestExport,
1329 Self::AsyncCallback => AbiVariant::GuestExportAsync,
1330 Self::AsyncStackful => AbiVariant::GuestExportAsyncStackful,
1331 }
1332 }
1333}
1334
1335#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1337pub enum ManglingAndAbi {
1338 Standard32,
1343
1344 Legacy(LiftLowerAbi),
1346}
1347
1348impl ManglingAndAbi {
1349 pub fn import_variant(self) -> AbiVariant {
1351 match self {
1352 Self::Standard32 => AbiVariant::GuestImport,
1353 Self::Legacy(abi) => abi.import_variant(),
1354 }
1355 }
1356
1357 pub fn export_variant(self) -> AbiVariant {
1359 match self {
1360 Self::Standard32 => AbiVariant::GuestExport,
1361 Self::Legacy(abi) => abi.export_variant(),
1362 }
1363 }
1364
1365 pub fn sync(self) -> Self {
1367 match self {
1368 Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => self,
1369 Self::Legacy(LiftLowerAbi::AsyncCallback)
1370 | Self::Legacy(LiftLowerAbi::AsyncStackful) => Self::Legacy(LiftLowerAbi::Sync),
1371 }
1372 }
1373
1374 pub fn is_async(&self) -> bool {
1376 match self {
1377 Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => false,
1378 Self::Legacy(LiftLowerAbi::AsyncCallback)
1379 | Self::Legacy(LiftLowerAbi::AsyncStackful) => true,
1380 }
1381 }
1382
1383 pub fn mangling(&self) -> Mangling {
1384 match self {
1385 Self::Standard32 => Mangling::Standard32,
1386 Self::Legacy(_) => Mangling::Legacy,
1387 }
1388 }
1389
1390 pub fn for_func(&self, func: &Function) -> Self {
1396 match self {
1397 Self::Standard32 => *self,
1398 Self::Legacy(abi) => {
1399 if !func.kind.is_async() {
1400 Self::Legacy(LiftLowerAbi::Sync)
1401 } else {
1402 Self::Legacy(*abi)
1403 }
1404 }
1405 }
1406 }
1407}
1408
1409impl Function {
1410 pub(crate) fn adjust_spans(&mut self, offset: u32) {
1412 self.span.adjust(offset);
1413 for param in &mut self.params {
1414 param.span.adjust(offset);
1415 }
1416 }
1417
1418 pub fn item_name(&self) -> &str {
1419 match &self.kind {
1420 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => &self.name,
1421 FunctionKind::Method(_)
1422 | FunctionKind::Static(_)
1423 | FunctionKind::AsyncMethod(_)
1424 | FunctionKind::AsyncStatic(_)
1425 | FunctionKind::MethodGetter(_)
1426 | FunctionKind::MethodSetter(_)
1427 | FunctionKind::StaticGetter(_)
1428 | FunctionKind::StaticSetter(_) => &self.name[self.name.find('.').unwrap() + 1..],
1429 FunctionKind::Getter | FunctionKind::Setter => {
1430 &self.name[self.name.find(']').unwrap() + 1..]
1431 }
1432 FunctionKind::Constructor(_) => "constructor",
1433 }
1434 }
1435
1436 pub fn parameter_and_result_types(&self) -> impl Iterator<Item = Type> + '_ {
1441 self.params.iter().map(|p| p.ty).chain(self.result)
1442 }
1443
1444 pub fn standard32_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1446 self.core_export_name(interface, Mangling::Standard32)
1447 }
1448
1449 pub fn legacy_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1450 self.core_export_name(interface, Mangling::Legacy)
1451 }
1452 pub fn core_export_name<'a>(
1454 &'a self,
1455 interface: Option<&str>,
1456 mangling: Mangling,
1457 ) -> Cow<'a, str> {
1458 match interface {
1459 Some(interface) => match mangling {
1460 Mangling::Standard32 => Cow::Owned(format!("cm32p2|{interface}|{}", self.name)),
1461 Mangling::Legacy => Cow::Owned(format!("{interface}#{}", self.name)),
1462 },
1463 None => match mangling {
1464 Mangling::Standard32 => Cow::Owned(format!("cm32p2||{}", self.name)),
1465 Mangling::Legacy => Cow::Borrowed(&self.name),
1466 },
1467 }
1468 }
1469 pub fn find_futures_and_streams(&self, resolve: &Resolve) -> Vec<TypeId> {
1485 let mut results = Vec::new();
1486 for param in self.params.iter() {
1487 find_futures_and_streams(resolve, param.ty, &mut results);
1488 }
1489 if let Some(ty) = self.result {
1490 find_futures_and_streams(resolve, ty, &mut results);
1491 }
1492 results
1493 }
1494
1495 pub fn is_constructor_shorthand(&self, resolve: &Resolve) -> bool {
1498 let FunctionKind::Constructor(containing_resource_id) = self.kind else {
1499 return false;
1500 };
1501
1502 let Some(Type::Id(id)) = &self.result else {
1503 return false;
1504 };
1505
1506 let TypeDefKind::Handle(Handle::Own(returned_resource_id)) = resolve.types[*id].kind else {
1507 return false;
1508 };
1509
1510 return containing_resource_id == returned_resource_id;
1511 }
1512
1513 pub fn task_return_import(
1516 &self,
1517 resolve: &Resolve,
1518 interface: Option<&WorldKey>,
1519 mangling: Mangling,
1520 ) -> (String, String, abi::WasmSignature) {
1521 match mangling {
1522 Mangling::Standard32 => todo!(),
1523 Mangling::Legacy => {}
1524 }
1525 let module = match interface {
1527 Some(key) => format!("[export]{}", resolve.name_world_key(key)),
1528 None => "[export]$root".to_string(),
1529 };
1530 let name = format!("[task-return]{}", self.name);
1531
1532 let mut func_tmp = self.clone();
1533 func_tmp.params = Vec::new();
1534 func_tmp.result = None;
1535 if let Some(ty) = self.result {
1536 func_tmp.params.push(Param {
1537 name: "x".to_string(),
1538 ty,
1539 span: Default::default(),
1540 });
1541 }
1542 let sig = resolve.wasm_signature(AbiVariant::GuestImport, &func_tmp);
1543 (module, name, sig)
1544 }
1545
1546 }
1548
1549fn find_futures_and_streams(resolve: &Resolve, ty: Type, results: &mut Vec<TypeId>) {
1550 let Type::Id(id) = ty else {
1551 return;
1552 };
1553
1554 match &resolve.types[id].kind {
1555 TypeDefKind::Resource
1556 | TypeDefKind::Handle(_)
1557 | TypeDefKind::Flags(_)
1558 | TypeDefKind::Enum(_) => {}
1559 TypeDefKind::Record(r) => {
1560 for Field { ty, .. } in &r.fields {
1561 find_futures_and_streams(resolve, *ty, results);
1562 }
1563 }
1564 TypeDefKind::Tuple(t) => {
1565 for ty in &t.types {
1566 find_futures_and_streams(resolve, *ty, results);
1567 }
1568 }
1569 TypeDefKind::Variant(v) => {
1570 for Case { ty, .. } in &v.cases {
1571 if let Some(ty) = ty {
1572 find_futures_and_streams(resolve, *ty, results);
1573 }
1574 }
1575 }
1576 TypeDefKind::Option(ty)
1577 | TypeDefKind::List(ty)
1578 | TypeDefKind::FixedLengthList(ty, ..)
1579 | TypeDefKind::Type(ty) => {
1580 find_futures_and_streams(resolve, *ty, results);
1581 }
1582 TypeDefKind::Map(k, v) => {
1583 find_futures_and_streams(resolve, *k, results);
1584 find_futures_and_streams(resolve, *v, results);
1585 }
1586 TypeDefKind::Result(r) => {
1587 if let Some(ty) = r.ok {
1588 find_futures_and_streams(resolve, ty, results);
1589 }
1590 if let Some(ty) = r.err {
1591 find_futures_and_streams(resolve, ty, results);
1592 }
1593 }
1594 TypeDefKind::Future(ty) => {
1595 if let Some(ty) = ty {
1596 find_futures_and_streams(resolve, *ty, results);
1597 }
1598 results.push(id);
1599 }
1600 TypeDefKind::Stream(ty) => {
1601 if let Some(ty) = ty {
1602 find_futures_and_streams(resolve, *ty, results);
1603 }
1604 results.push(id);
1605 }
1606 TypeDefKind::Unknown => unreachable!(),
1607 }
1608}
1609
1610#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1618#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize, Serialize))]
1619#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1620pub enum Stability {
1621 Unknown,
1623
1624 Unstable {
1629 feature: String,
1630 #[cfg_attr(
1631 feature = "serde",
1632 serde(
1633 skip_serializing_if = "Option::is_none",
1634 default,
1635 serialize_with = "serialize_optional_version",
1636 deserialize_with = "deserialize_optional_version"
1637 )
1638 )]
1639 deprecated: Option<Version>,
1640 },
1641
1642 Stable {
1647 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_version"))]
1648 #[cfg_attr(feature = "serde", serde(deserialize_with = "deserialize_version"))]
1649 since: Version,
1650 #[cfg_attr(
1651 feature = "serde",
1652 serde(
1653 skip_serializing_if = "Option::is_none",
1654 default,
1655 serialize_with = "serialize_optional_version",
1656 deserialize_with = "deserialize_optional_version"
1657 )
1658 )]
1659 deprecated: Option<Version>,
1660 },
1661}
1662
1663impl Stability {
1664 pub fn is_unknown(&self) -> bool {
1666 matches!(self, Stability::Unknown)
1667 }
1668
1669 pub fn is_stable(&self) -> bool {
1670 matches!(self, Stability::Stable { .. })
1671 }
1672}
1673
1674impl Default for Stability {
1675 fn default() -> Stability {
1676 Stability::Unknown
1677 }
1678}
1679
1680#[cfg(test)]
1681mod test {
1682 use super::*;
1683 use alloc::vec;
1684
1685 #[test]
1686 fn test_discriminant_type() {
1687 assert_eq!(discriminant_type(1), Int::U8);
1688 assert_eq!(discriminant_type(0x100), Int::U8);
1689 assert_eq!(discriminant_type(0x101), Int::U16);
1690 assert_eq!(discriminant_type(0x10000), Int::U16);
1691 assert_eq!(discriminant_type(0x10001), Int::U32);
1692 if let Ok(num_cases) = usize::try_from(0x100000000_u64) {
1693 assert_eq!(discriminant_type(num_cases), Int::U32);
1694 }
1695 }
1696
1697 #[test]
1698 fn test_find_futures_and_streams() {
1699 let mut resolve = Resolve::default();
1700 let t0 = resolve.types.alloc(TypeDef {
1701 name: None,
1702 kind: TypeDefKind::Future(Some(Type::U32)),
1703 owner: TypeOwner::None,
1704 docs: Docs::default(),
1705 stability: Stability::Unknown,
1706 span: Default::default(),
1707 external_id: Default::default(),
1708 });
1709 let t1 = resolve.types.alloc(TypeDef {
1710 name: None,
1711 kind: TypeDefKind::Future(Some(Type::Id(t0))),
1712 owner: TypeOwner::None,
1713 docs: Docs::default(),
1714 stability: Stability::Unknown,
1715 span: Default::default(),
1716 external_id: Default::default(),
1717 });
1718 let t2 = resolve.types.alloc(TypeDef {
1719 name: None,
1720 kind: TypeDefKind::Stream(Some(Type::U32)),
1721 owner: TypeOwner::None,
1722 docs: Docs::default(),
1723 stability: Stability::Unknown,
1724 span: Default::default(),
1725 external_id: Default::default(),
1726 });
1727 let found = Function {
1728 name: "foo".into(),
1729 kind: FunctionKind::Freestanding,
1730 params: vec![
1731 Param {
1732 name: "p1".into(),
1733 ty: Type::Id(t1),
1734 span: Default::default(),
1735 },
1736 Param {
1737 name: "p2".into(),
1738 ty: Type::U32,
1739 span: Default::default(),
1740 },
1741 ],
1742 result: Some(Type::Id(t2)),
1743 docs: Docs::default(),
1744 stability: Stability::Unknown,
1745 span: Default::default(),
1746 external_id: Default::default(),
1747 }
1748 .find_futures_and_streams(&resolve);
1749 assert_eq!(3, found.len());
1750 assert_eq!(t0, found[0]);
1751 assert_eq!(t1, found[1]);
1752 assert_eq!(t2, found[2]);
1753 }
1754
1755 #[test]
1756 fn test_canon_version_split() {
1757 use semver::Version;
1758
1759 let v = Version::parse("1.2.3").unwrap();
1760 assert_eq!(
1761 PackageName::version_compat_track_string(&v),
1762 ("1".to_string(), Some(".2.3".to_string()))
1763 );
1764
1765 let v = Version::parse("101.201.301").unwrap();
1766 assert_eq!(
1767 PackageName::version_compat_track_string(&v),
1768 ("101".to_string(), Some(".201.301".to_string()))
1769 );
1770
1771 let v = Version::parse("0.2.6-rc.1").unwrap();
1772 assert_eq!(
1773 PackageName::version_compat_track_string(&v),
1774 ("0.2.6-rc.1".to_string(), None)
1775 );
1776
1777 let v = Version::parse("0.10.0+build.1").unwrap();
1778 assert_eq!(
1779 PackageName::version_compat_track_string(&v),
1780 ("0.10".to_string(), Some(".0+build.1".to_string()))
1781 );
1782
1783 let v = Version::parse("0.0.1-alpha+build.1").unwrap();
1784 assert_eq!(
1785 PackageName::version_compat_track_string(&v),
1786 ("0.0.1-alpha".to_string(), Some("+build.1".to_string()))
1787 );
1788
1789 let v = Version::parse("0.0.0").unwrap();
1790 assert_eq!(
1791 PackageName::version_compat_track_string(&v),
1792 ("0.0.0".to_string(), None)
1793 );
1794
1795 let v = Version::parse("1.0.0-beta.1").unwrap();
1796 assert_eq!(
1797 PackageName::version_compat_track_string(&v),
1798 ("1.0.0-beta.1".to_string(), None)
1799 );
1800
1801 let v = Version::parse("0.0.100+build.1").unwrap();
1802 assert_eq!(
1803 PackageName::version_compat_track_string(&v),
1804 ("0.0.100".to_string(), Some("+build.1".to_string()))
1805 );
1806 }
1807}