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
36pub 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#[derive(Clone)]
72pub struct UnresolvedPackage {
73 pub name: PackageName,
75
76 pub worlds: Arena<World>,
80
81 pub interfaces: Arena<Interface>,
88
89 pub types: Arena<TypeDef>,
96
97 pub foreign_deps: IndexMap<PackageName, IndexMap<String, AstItem>>,
106
107 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#[derive(Clone)]
121pub struct UnresolvedPackageGroup {
122 pub main: UnresolvedPackage,
127
128 pub nested: Vec<UnresolvedPackage>,
130
131 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#[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 pub namespace: String,
170 pub name: String,
172 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 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 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 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 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 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 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 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 pub name: String,
400
401 pub imports: IndexMap<WorldKey, WorldItem>,
403
404 pub exports: IndexMap<WorldKey, WorldItem>,
406
407 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_optional_id"))]
409 pub package: Option<PackageId>,
410
411 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
413 pub docs: Docs,
414
415 #[cfg_attr(
417 feature = "serde",
418 serde(skip_serializing_if = "Stability::is_unknown")
419 )]
420 pub stability: Stability,
421
422 #[cfg_attr(feature = "serde", serde(skip))]
424 pub includes: Vec<(Stability, WorldId)>,
425
426 #[cfg_attr(feature = "serde", serde(skip))]
428 pub include_names: Vec<Vec<IncludeName>>,
429}
430
431#[derive(Debug, Clone)]
432pub struct IncludeName {
433 pub name: String,
435
436 pub as_: String,
438}
439
440#[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 Name(String),
448 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 #[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 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 Function(Function),
490
491 #[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 pub name: Option<String>,
515
516 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id_map"))]
521 pub types: IndexMap<String, TypeId>,
522
523 pub functions: IndexMap<String, Function>,
525
526 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
528 pub docs: Docs,
529
530 #[cfg_attr(
532 feature = "serde",
533 serde(skip_serializing_if = "Stability::is_unknown")
534 )]
535 pub stability: Stability,
536
537 #[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 #[cfg_attr(
552 feature = "serde",
553 serde(skip_serializing_if = "Stability::is_unknown")
554 )]
555 pub stability: Stability,
556}
557
558#[derive(Debug, Clone, PartialEq)]
559#[cfg_attr(feature = "serde", derive(Serialize))]
560#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
561pub enum TypeDefKind {
562 Record(Record),
563 Resource,
564 Handle(Handle),
565 Flags(Flags),
566 Tuple(Tuple),
567 Variant(Variant),
568 Enum(Enum),
569 Option(Type),
570 Result(Result_),
571 List(Type),
572 FixedSizeList(Type, u32),
573 Future(Option<Type>),
574 Stream(Option<Type>),
575 Type(Type),
576
577 Unknown,
583}
584
585impl TypeDefKind {
586 pub fn as_str(&self) -> &'static str {
587 match self {
588 TypeDefKind::Record(_) => "record",
589 TypeDefKind::Resource => "resource",
590 TypeDefKind::Handle(handle) => match handle {
591 Handle::Own(_) => "own",
592 Handle::Borrow(_) => "borrow",
593 },
594 TypeDefKind::Flags(_) => "flags",
595 TypeDefKind::Tuple(_) => "tuple",
596 TypeDefKind::Variant(_) => "variant",
597 TypeDefKind::Enum(_) => "enum",
598 TypeDefKind::Option(_) => "option",
599 TypeDefKind::Result(_) => "result",
600 TypeDefKind::List(_) => "list",
601 TypeDefKind::FixedSizeList(..) => "fixed size list",
602 TypeDefKind::Future(_) => "future",
603 TypeDefKind::Stream(_) => "stream",
604 TypeDefKind::Type(_) => "type",
605 TypeDefKind::Unknown => "unknown",
606 }
607 }
608}
609
610#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
611#[cfg_attr(feature = "serde", derive(Serialize))]
612#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
613pub enum TypeOwner {
614 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
616 World(WorldId),
617 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
619 Interface(InterfaceId),
620 #[cfg_attr(feature = "serde", serde(untagged, serialize_with = "serialize_none"))]
623 None,
624}
625
626#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
627#[cfg_attr(feature = "serde", derive(Serialize))]
628#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
629pub enum Handle {
630 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
631 Own(TypeId),
632 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
633 Borrow(TypeId),
634}
635
636#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
637pub enum Type {
638 Bool,
639 U8,
640 U16,
641 U32,
642 U64,
643 S8,
644 S16,
645 S32,
646 S64,
647 F32,
648 F64,
649 Char,
650 String,
651 ErrorContext,
652 Id(TypeId),
653}
654
655#[derive(Debug, Copy, Clone, Eq, PartialEq)]
656pub enum Int {
657 U8,
658 U16,
659 U32,
660 U64,
661}
662
663#[derive(Debug, Clone, PartialEq)]
664#[cfg_attr(feature = "serde", derive(Serialize))]
665pub struct Record {
666 pub fields: Vec<Field>,
667}
668
669#[derive(Debug, Clone, PartialEq)]
670#[cfg_attr(feature = "serde", derive(Serialize))]
671pub struct Field {
672 pub name: String,
673 #[cfg_attr(feature = "serde", serde(rename = "type"))]
674 pub ty: Type,
675 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
676 pub docs: Docs,
677}
678
679#[derive(Debug, Clone, PartialEq)]
680#[cfg_attr(feature = "serde", derive(Serialize))]
681pub struct Flags {
682 pub flags: Vec<Flag>,
683}
684
685#[derive(Debug, Clone, PartialEq)]
686#[cfg_attr(feature = "serde", derive(Serialize))]
687pub struct Flag {
688 pub name: String,
689 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
690 pub docs: Docs,
691}
692
693#[derive(Debug, Clone, PartialEq)]
694pub enum FlagsRepr {
695 U8,
696 U16,
697 U32(usize),
698}
699
700impl Flags {
701 pub fn repr(&self) -> FlagsRepr {
702 match self.flags.len() {
703 0 => FlagsRepr::U32(0),
704 n if n <= 8 => FlagsRepr::U8,
705 n if n <= 16 => FlagsRepr::U16,
706 n => FlagsRepr::U32(sizealign::align_to(n, 32) / 32),
707 }
708 }
709}
710
711impl FlagsRepr {
712 pub fn count(&self) -> usize {
713 match self {
714 FlagsRepr::U8 => 1,
715 FlagsRepr::U16 => 1,
716 FlagsRepr::U32(n) => *n,
717 }
718 }
719}
720
721#[derive(Debug, Clone, PartialEq)]
722#[cfg_attr(feature = "serde", derive(Serialize))]
723pub struct Tuple {
724 pub types: Vec<Type>,
725}
726
727#[derive(Debug, Clone, PartialEq)]
728#[cfg_attr(feature = "serde", derive(Serialize))]
729pub struct Variant {
730 pub cases: Vec<Case>,
731}
732
733#[derive(Debug, Clone, PartialEq)]
734#[cfg_attr(feature = "serde", derive(Serialize))]
735pub struct Case {
736 pub name: String,
737 #[cfg_attr(feature = "serde", serde(rename = "type"))]
738 pub ty: Option<Type>,
739 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
740 pub docs: Docs,
741}
742
743impl Variant {
744 pub fn tag(&self) -> Int {
745 discriminant_type(self.cases.len())
746 }
747}
748
749#[derive(Debug, Clone, PartialEq)]
750#[cfg_attr(feature = "serde", derive(Serialize))]
751pub struct Enum {
752 pub cases: Vec<EnumCase>,
753}
754
755#[derive(Debug, Clone, PartialEq)]
756#[cfg_attr(feature = "serde", derive(Serialize))]
757pub struct EnumCase {
758 pub name: String,
759 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
760 pub docs: Docs,
761}
762
763impl Enum {
764 pub fn tag(&self) -> Int {
765 discriminant_type(self.cases.len())
766 }
767}
768
769fn discriminant_type(num_cases: usize) -> Int {
771 match num_cases.checked_sub(1) {
772 None => Int::U8,
773 Some(n) if n <= u8::max_value() as usize => Int::U8,
774 Some(n) if n <= u16::max_value() as usize => Int::U16,
775 Some(n) if n <= u32::max_value() as usize => Int::U32,
776 _ => panic!("too many cases to fit in a repr"),
777 }
778}
779
780#[derive(Debug, Clone, PartialEq)]
781#[cfg_attr(feature = "serde", derive(Serialize))]
782pub struct Result_ {
783 pub ok: Option<Type>,
784 pub err: Option<Type>,
785}
786
787#[derive(Clone, Default, Debug, PartialEq, Eq)]
788#[cfg_attr(feature = "serde", derive(Serialize))]
789pub struct Docs {
790 pub contents: Option<String>,
791}
792
793impl Docs {
794 pub fn is_empty(&self) -> bool {
795 self.contents.is_none()
796 }
797}
798
799#[derive(Debug, Clone, PartialEq, Eq)]
800#[cfg_attr(feature = "serde", derive(Serialize))]
801pub struct Function {
802 pub name: String,
803 pub kind: FunctionKind,
804 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_params"))]
805 pub params: Vec<(String, Type)>,
806 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
807 pub result: Option<Type>,
808 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
809 pub docs: Docs,
810 #[cfg_attr(
812 feature = "serde",
813 serde(skip_serializing_if = "Stability::is_unknown")
814 )]
815 pub stability: Stability,
816}
817
818#[derive(Debug, Clone, PartialEq, Eq)]
819#[cfg_attr(feature = "serde", derive(Serialize))]
820#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
821pub enum FunctionKind {
822 Freestanding,
830
831 AsyncFreestanding,
839
840 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
851 Method(TypeId),
852
853 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
864 AsyncMethod(TypeId),
865
866 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
876 Static(TypeId),
877
878 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
888 AsyncStatic(TypeId),
889
890 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
900 Constructor(TypeId),
901}
902
903impl FunctionKind {
904 pub fn resource(&self) -> Option<TypeId> {
906 match self {
907 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
908 FunctionKind::Method(id)
909 | FunctionKind::Static(id)
910 | FunctionKind::Constructor(id)
911 | FunctionKind::AsyncMethod(id)
912 | FunctionKind::AsyncStatic(id) => Some(*id),
913 }
914 }
915
916 pub fn resource_mut(&mut self) -> Option<&mut TypeId> {
918 match self {
919 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
920 FunctionKind::Method(id)
921 | FunctionKind::Static(id)
922 | FunctionKind::Constructor(id)
923 | FunctionKind::AsyncMethod(id)
924 | FunctionKind::AsyncStatic(id) => Some(id),
925 }
926 }
927}
928
929#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
931pub enum Mangling {
932 Standard32,
935
936 Legacy,
941}
942
943impl std::str::FromStr for Mangling {
944 type Err = anyhow::Error;
945
946 fn from_str(s: &str) -> Result<Mangling> {
947 match s {
948 "legacy" => Ok(Mangling::Legacy),
949 "standard32" => Ok(Mangling::Standard32),
950 _ => {
951 bail!(
952 "unknown name mangling `{s}`, \
953 supported values are `legacy` or `standard32`"
954 )
955 }
956 }
957 }
958}
959
960#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
962pub enum LiftLowerAbi {
963 Sync,
965
966 AsyncCallback,
969
970 AsyncStackful,
973}
974
975impl LiftLowerAbi {
976 fn import_prefix(self) -> &'static str {
977 match self {
978 Self::Sync => "",
979 Self::AsyncCallback | Self::AsyncStackful => "[async-lower]",
980 }
981 }
982
983 pub fn import_variant(self) -> AbiVariant {
985 match self {
986 Self::Sync => AbiVariant::GuestImport,
987 Self::AsyncCallback | Self::AsyncStackful => AbiVariant::GuestImportAsync,
988 }
989 }
990
991 fn export_prefix(self) -> &'static str {
992 match self {
993 Self::Sync => "",
994 Self::AsyncCallback => "[async-lift]",
995 Self::AsyncStackful => "[async-lift-stackful]",
996 }
997 }
998
999 pub fn export_variant(self) -> AbiVariant {
1001 match self {
1002 Self::Sync => AbiVariant::GuestExport,
1003 Self::AsyncCallback => AbiVariant::GuestExportAsync,
1004 Self::AsyncStackful => AbiVariant::GuestExportAsyncStackful,
1005 }
1006 }
1007}
1008
1009#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1011pub enum ManglingAndAbi {
1012 Standard32,
1017
1018 Legacy(LiftLowerAbi),
1020}
1021
1022impl ManglingAndAbi {
1023 pub fn import_variant(self) -> AbiVariant {
1025 match self {
1026 Self::Standard32 => AbiVariant::GuestImport,
1027 Self::Legacy(abi) => abi.import_variant(),
1028 }
1029 }
1030
1031 pub fn export_variant(self) -> AbiVariant {
1033 match self {
1034 Self::Standard32 => AbiVariant::GuestExport,
1035 Self::Legacy(abi) => abi.export_variant(),
1036 }
1037 }
1038
1039 pub fn sync(self) -> Self {
1041 match self {
1042 Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => self,
1043 Self::Legacy(LiftLowerAbi::AsyncCallback)
1044 | Self::Legacy(LiftLowerAbi::AsyncStackful) => Self::Legacy(LiftLowerAbi::Sync),
1045 }
1046 }
1047
1048 pub fn is_async(&self) -> bool {
1050 match self {
1051 Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => false,
1052 Self::Legacy(LiftLowerAbi::AsyncCallback)
1053 | Self::Legacy(LiftLowerAbi::AsyncStackful) => true,
1054 }
1055 }
1056}
1057
1058impl Function {
1059 pub fn item_name(&self) -> &str {
1060 match &self.kind {
1061 FunctionKind::Freestanding => &self.name,
1062 FunctionKind::AsyncFreestanding => &self.name["[async]".len()..],
1063 FunctionKind::Method(_)
1064 | FunctionKind::Static(_)
1065 | FunctionKind::AsyncMethod(_)
1066 | FunctionKind::AsyncStatic(_) => &self.name[self.name.find('.').unwrap() + 1..],
1067 FunctionKind::Constructor(_) => "constructor",
1068 }
1069 }
1070
1071 pub fn parameter_and_result_types(&self) -> impl Iterator<Item = Type> + '_ {
1076 self.params.iter().map(|(_, t)| *t).chain(self.result)
1077 }
1078
1079 pub fn standard32_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1081 self.core_export_name(interface, Mangling::Standard32)
1082 }
1083
1084 pub fn legacy_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1085 self.core_export_name(interface, Mangling::Legacy)
1086 }
1087 pub fn core_export_name<'a>(
1089 &'a self,
1090 interface: Option<&str>,
1091 mangling: Mangling,
1092 ) -> Cow<'a, str> {
1093 match interface {
1094 Some(interface) => match mangling {
1095 Mangling::Standard32 => Cow::Owned(format!("cm32p2|{interface}|{}", self.name)),
1096 Mangling::Legacy => Cow::Owned(format!("{interface}#{}", self.name)),
1097 },
1098 None => match mangling {
1099 Mangling::Standard32 => Cow::Owned(format!("cm32p2||{}", self.name)),
1100 Mangling::Legacy => Cow::Borrowed(&self.name),
1101 },
1102 }
1103 }
1104 pub fn find_futures_and_streams(&self, resolve: &Resolve) -> Vec<TypeId> {
1120 let mut results = Vec::new();
1121 for (_, ty) in self.params.iter() {
1122 find_futures_and_streams(resolve, *ty, &mut results);
1123 }
1124 if let Some(ty) = self.result {
1125 find_futures_and_streams(resolve, ty, &mut results);
1126 }
1127 results
1128 }
1129}
1130
1131fn find_futures_and_streams(resolve: &Resolve, ty: Type, results: &mut Vec<TypeId>) {
1132 let Type::Id(id) = ty else {
1133 return;
1134 };
1135
1136 match &resolve.types[id].kind {
1137 TypeDefKind::Resource
1138 | TypeDefKind::Handle(_)
1139 | TypeDefKind::Flags(_)
1140 | TypeDefKind::Enum(_) => {}
1141 TypeDefKind::Record(r) => {
1142 for Field { ty, .. } in &r.fields {
1143 find_futures_and_streams(resolve, *ty, results);
1144 }
1145 }
1146 TypeDefKind::Tuple(t) => {
1147 for ty in &t.types {
1148 find_futures_and_streams(resolve, *ty, results);
1149 }
1150 }
1151 TypeDefKind::Variant(v) => {
1152 for Case { ty, .. } in &v.cases {
1153 if let Some(ty) = ty {
1154 find_futures_and_streams(resolve, *ty, results);
1155 }
1156 }
1157 }
1158 TypeDefKind::Option(ty)
1159 | TypeDefKind::List(ty)
1160 | TypeDefKind::FixedSizeList(ty, ..)
1161 | TypeDefKind::Type(ty) => {
1162 find_futures_and_streams(resolve, *ty, results);
1163 }
1164 TypeDefKind::Result(r) => {
1165 if let Some(ty) = r.ok {
1166 find_futures_and_streams(resolve, ty, results);
1167 }
1168 if let Some(ty) = r.err {
1169 find_futures_and_streams(resolve, ty, results);
1170 }
1171 }
1172 TypeDefKind::Future(ty) => {
1173 if let Some(ty) = ty {
1174 find_futures_and_streams(resolve, *ty, results);
1175 }
1176 results.push(id);
1177 }
1178 TypeDefKind::Stream(ty) => {
1179 if let Some(ty) = ty {
1180 find_futures_and_streams(resolve, *ty, results);
1181 }
1182 results.push(id);
1183 }
1184 TypeDefKind::Unknown => unreachable!(),
1185 }
1186}
1187
1188#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1196#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize, Serialize))]
1197#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1198pub enum Stability {
1199 Unknown,
1201
1202 Unstable {
1207 feature: String,
1208 #[cfg_attr(
1209 feature = "serde",
1210 serde(
1211 skip_serializing_if = "Option::is_none",
1212 default,
1213 serialize_with = "serialize_optional_version",
1214 deserialize_with = "deserialize_optional_version"
1215 )
1216 )]
1217 deprecated: Option<Version>,
1218 },
1219
1220 Stable {
1225 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_version"))]
1226 #[cfg_attr(feature = "serde", serde(deserialize_with = "deserialize_version"))]
1227 since: Version,
1228 #[cfg_attr(
1229 feature = "serde",
1230 serde(
1231 skip_serializing_if = "Option::is_none",
1232 default,
1233 serialize_with = "serialize_optional_version",
1234 deserialize_with = "deserialize_optional_version"
1235 )
1236 )]
1237 deprecated: Option<Version>,
1238 },
1239}
1240
1241impl Stability {
1242 pub fn is_unknown(&self) -> bool {
1244 matches!(self, Stability::Unknown)
1245 }
1246
1247 pub fn is_stable(&self) -> bool {
1248 matches!(self, Stability::Stable { .. })
1249 }
1250}
1251
1252impl Default for Stability {
1253 fn default() -> Stability {
1254 Stability::Unknown
1255 }
1256}
1257
1258#[cfg(test)]
1259mod test {
1260 use super::*;
1261
1262 #[test]
1263 fn test_discriminant_type() {
1264 assert_eq!(discriminant_type(1), Int::U8);
1265 assert_eq!(discriminant_type(0x100), Int::U8);
1266 assert_eq!(discriminant_type(0x101), Int::U16);
1267 assert_eq!(discriminant_type(0x10000), Int::U16);
1268 assert_eq!(discriminant_type(0x10001), Int::U32);
1269 if let Ok(num_cases) = usize::try_from(0x100000000_u64) {
1270 assert_eq!(discriminant_type(num_cases), Int::U32);
1271 }
1272 }
1273
1274 #[test]
1275 fn test_find_futures_and_streams() {
1276 let mut resolve = Resolve::default();
1277 let t0 = resolve.types.alloc(TypeDef {
1278 name: None,
1279 kind: TypeDefKind::Future(Some(Type::U32)),
1280 owner: TypeOwner::None,
1281 docs: Docs::default(),
1282 stability: Stability::Unknown,
1283 });
1284 let t1 = resolve.types.alloc(TypeDef {
1285 name: None,
1286 kind: TypeDefKind::Future(Some(Type::Id(t0))),
1287 owner: TypeOwner::None,
1288 docs: Docs::default(),
1289 stability: Stability::Unknown,
1290 });
1291 let t2 = resolve.types.alloc(TypeDef {
1292 name: None,
1293 kind: TypeDefKind::Stream(Some(Type::U32)),
1294 owner: TypeOwner::None,
1295 docs: Docs::default(),
1296 stability: Stability::Unknown,
1297 });
1298 let found = Function {
1299 name: "foo".into(),
1300 kind: FunctionKind::Freestanding,
1301 params: vec![("p1".into(), Type::Id(t1)), ("p2".into(), Type::U32)],
1302 result: Some(Type::Id(t2)),
1303 docs: Docs::default(),
1304 stability: Stability::Unknown,
1305 }
1306 .find_futures_and_streams(&resolve);
1307 assert_eq!(3, found.len());
1308 assert_eq!(t0, found[0]);
1309 assert_eq!(t1, found[1]);
1310 assert_eq!(t2, found[2]);
1311 }
1312}