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 Future(Option<Type>),
573 Stream(Option<Type>),
574 Type(Type),
575
576 Unknown,
582}
583
584impl TypeDefKind {
585 pub fn as_str(&self) -> &'static str {
586 match self {
587 TypeDefKind::Record(_) => "record",
588 TypeDefKind::Resource => "resource",
589 TypeDefKind::Handle(handle) => match handle {
590 Handle::Own(_) => "own",
591 Handle::Borrow(_) => "borrow",
592 },
593 TypeDefKind::Flags(_) => "flags",
594 TypeDefKind::Tuple(_) => "tuple",
595 TypeDefKind::Variant(_) => "variant",
596 TypeDefKind::Enum(_) => "enum",
597 TypeDefKind::Option(_) => "option",
598 TypeDefKind::Result(_) => "result",
599 TypeDefKind::List(_) => "list",
600 TypeDefKind::Future(_) => "future",
601 TypeDefKind::Stream(_) => "stream",
602 TypeDefKind::Type(_) => "type",
603 TypeDefKind::Unknown => "unknown",
604 }
605 }
606}
607
608#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
609#[cfg_attr(feature = "serde", derive(Serialize))]
610#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
611pub enum TypeOwner {
612 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
614 World(WorldId),
615 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
617 Interface(InterfaceId),
618 #[cfg_attr(feature = "serde", serde(untagged, serialize_with = "serialize_none"))]
621 None,
622}
623
624#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
625#[cfg_attr(feature = "serde", derive(Serialize))]
626#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
627pub enum Handle {
628 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
629 Own(TypeId),
630 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
631 Borrow(TypeId),
632}
633
634#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
635pub enum Type {
636 Bool,
637 U8,
638 U16,
639 U32,
640 U64,
641 S8,
642 S16,
643 S32,
644 S64,
645 F32,
646 F64,
647 Char,
648 String,
649 ErrorContext,
650 Id(TypeId),
651}
652
653#[derive(Debug, Copy, Clone, Eq, PartialEq)]
654pub enum Int {
655 U8,
656 U16,
657 U32,
658 U64,
659}
660
661#[derive(Debug, Clone, PartialEq)]
662#[cfg_attr(feature = "serde", derive(Serialize))]
663pub struct Record {
664 pub fields: Vec<Field>,
665}
666
667#[derive(Debug, Clone, PartialEq)]
668#[cfg_attr(feature = "serde", derive(Serialize))]
669pub struct Field {
670 pub name: String,
671 #[cfg_attr(feature = "serde", serde(rename = "type"))]
672 pub ty: Type,
673 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
674 pub docs: Docs,
675}
676
677#[derive(Debug, Clone, PartialEq)]
678#[cfg_attr(feature = "serde", derive(Serialize))]
679pub struct Flags {
680 pub flags: Vec<Flag>,
681}
682
683#[derive(Debug, Clone, PartialEq)]
684#[cfg_attr(feature = "serde", derive(Serialize))]
685pub struct Flag {
686 pub name: String,
687 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
688 pub docs: Docs,
689}
690
691#[derive(Debug, Clone, PartialEq)]
692pub enum FlagsRepr {
693 U8,
694 U16,
695 U32(usize),
696}
697
698impl Flags {
699 pub fn repr(&self) -> FlagsRepr {
700 match self.flags.len() {
701 0 => FlagsRepr::U32(0),
702 n if n <= 8 => FlagsRepr::U8,
703 n if n <= 16 => FlagsRepr::U16,
704 n => FlagsRepr::U32(sizealign::align_to(n, 32) / 32),
705 }
706 }
707}
708
709impl FlagsRepr {
710 pub fn count(&self) -> usize {
711 match self {
712 FlagsRepr::U8 => 1,
713 FlagsRepr::U16 => 1,
714 FlagsRepr::U32(n) => *n,
715 }
716 }
717}
718
719#[derive(Debug, Clone, PartialEq)]
720#[cfg_attr(feature = "serde", derive(Serialize))]
721pub struct Tuple {
722 pub types: Vec<Type>,
723}
724
725#[derive(Debug, Clone, PartialEq)]
726#[cfg_attr(feature = "serde", derive(Serialize))]
727pub struct Variant {
728 pub cases: Vec<Case>,
729}
730
731#[derive(Debug, Clone, PartialEq)]
732#[cfg_attr(feature = "serde", derive(Serialize))]
733pub struct Case {
734 pub name: String,
735 #[cfg_attr(feature = "serde", serde(rename = "type"))]
736 pub ty: Option<Type>,
737 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
738 pub docs: Docs,
739}
740
741impl Variant {
742 pub fn tag(&self) -> Int {
743 discriminant_type(self.cases.len())
744 }
745}
746
747#[derive(Debug, Clone, PartialEq)]
748#[cfg_attr(feature = "serde", derive(Serialize))]
749pub struct Enum {
750 pub cases: Vec<EnumCase>,
751}
752
753#[derive(Debug, Clone, PartialEq)]
754#[cfg_attr(feature = "serde", derive(Serialize))]
755pub struct EnumCase {
756 pub name: String,
757 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
758 pub docs: Docs,
759}
760
761impl Enum {
762 pub fn tag(&self) -> Int {
763 discriminant_type(self.cases.len())
764 }
765}
766
767fn discriminant_type(num_cases: usize) -> Int {
769 match num_cases.checked_sub(1) {
770 None => Int::U8,
771 Some(n) if n <= u8::max_value() as usize => Int::U8,
772 Some(n) if n <= u16::max_value() as usize => Int::U16,
773 Some(n) if n <= u32::max_value() as usize => Int::U32,
774 _ => panic!("too many cases to fit in a repr"),
775 }
776}
777
778#[derive(Debug, Clone, PartialEq)]
779#[cfg_attr(feature = "serde", derive(Serialize))]
780pub struct Result_ {
781 pub ok: Option<Type>,
782 pub err: Option<Type>,
783}
784
785#[derive(Clone, Default, Debug, PartialEq, Eq)]
786#[cfg_attr(feature = "serde", derive(Serialize))]
787pub struct Docs {
788 pub contents: Option<String>,
789}
790
791impl Docs {
792 pub fn is_empty(&self) -> bool {
793 self.contents.is_none()
794 }
795}
796
797#[derive(Debug, Clone, PartialEq, Eq)]
798#[cfg_attr(feature = "serde", derive(Serialize))]
799pub struct Function {
800 pub name: String,
801 pub kind: FunctionKind,
802 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_params"))]
803 pub params: Vec<(String, Type)>,
804 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
805 pub result: Option<Type>,
806 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
807 pub docs: Docs,
808 #[cfg_attr(
810 feature = "serde",
811 serde(skip_serializing_if = "Stability::is_unknown")
812 )]
813 pub stability: Stability,
814}
815
816#[derive(Debug, Clone, PartialEq, Eq)]
817#[cfg_attr(feature = "serde", derive(Serialize))]
818#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
819pub enum FunctionKind {
820 Freestanding,
828
829 AsyncFreestanding,
837
838 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
849 Method(TypeId),
850
851 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
862 AsyncMethod(TypeId),
863
864 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
874 Static(TypeId),
875
876 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
886 AsyncStatic(TypeId),
887
888 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
898 Constructor(TypeId),
899}
900
901impl FunctionKind {
902 pub fn resource(&self) -> Option<TypeId> {
904 match self {
905 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
906 FunctionKind::Method(id)
907 | FunctionKind::Static(id)
908 | FunctionKind::Constructor(id)
909 | FunctionKind::AsyncMethod(id)
910 | FunctionKind::AsyncStatic(id) => Some(*id),
911 }
912 }
913
914 pub fn resource_mut(&mut self) -> Option<&mut TypeId> {
916 match self {
917 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
918 FunctionKind::Method(id)
919 | FunctionKind::Static(id)
920 | FunctionKind::Constructor(id)
921 | FunctionKind::AsyncMethod(id)
922 | FunctionKind::AsyncStatic(id) => Some(id),
923 }
924 }
925}
926
927#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
929pub enum Mangling {
930 Standard32,
933
934 Legacy,
939}
940
941impl std::str::FromStr for Mangling {
942 type Err = anyhow::Error;
943
944 fn from_str(s: &str) -> Result<Mangling> {
945 match s {
946 "legacy" => Ok(Mangling::Legacy),
947 "standard32" => Ok(Mangling::Standard32),
948 _ => {
949 bail!(
950 "unknown name mangling `{s}`, \
951 supported values are `legacy` or `standard32`"
952 )
953 }
954 }
955 }
956}
957
958#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
960pub enum LiftLowerAbi {
961 Sync,
963
964 AsyncCallback,
967
968 AsyncStackful,
971}
972
973impl LiftLowerAbi {
974 fn import_prefix(self) -> &'static str {
975 match self {
976 Self::Sync => "",
977 Self::AsyncCallback | Self::AsyncStackful => "[async-lower]",
978 }
979 }
980
981 pub fn import_variant(self) -> AbiVariant {
983 match self {
984 Self::Sync => AbiVariant::GuestImport,
985 Self::AsyncCallback | Self::AsyncStackful => AbiVariant::GuestImportAsync,
986 }
987 }
988
989 fn export_prefix(self) -> &'static str {
990 match self {
991 Self::Sync => "",
992 Self::AsyncCallback => "[async-lift]",
993 Self::AsyncStackful => "[async-lift-stackful]",
994 }
995 }
996
997 pub fn export_variant(self) -> AbiVariant {
999 match self {
1000 Self::Sync => AbiVariant::GuestExport,
1001 Self::AsyncCallback => AbiVariant::GuestExportAsync,
1002 Self::AsyncStackful => AbiVariant::GuestExportAsyncStackful,
1003 }
1004 }
1005}
1006
1007#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1009pub enum ManglingAndAbi {
1010 Standard32,
1015
1016 Legacy(LiftLowerAbi),
1018}
1019
1020impl ManglingAndAbi {
1021 pub fn import_variant(self) -> AbiVariant {
1023 match self {
1024 Self::Standard32 => AbiVariant::GuestImport,
1025 Self::Legacy(abi) => abi.import_variant(),
1026 }
1027 }
1028
1029 pub fn export_variant(self) -> AbiVariant {
1031 match self {
1032 Self::Standard32 => AbiVariant::GuestExport,
1033 Self::Legacy(abi) => abi.export_variant(),
1034 }
1035 }
1036
1037 pub fn sync(self) -> Self {
1039 match self {
1040 Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => self,
1041 Self::Legacy(LiftLowerAbi::AsyncCallback)
1042 | Self::Legacy(LiftLowerAbi::AsyncStackful) => Self::Legacy(LiftLowerAbi::Sync),
1043 }
1044 }
1045
1046 pub fn is_async(&self) -> bool {
1048 match self {
1049 Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => false,
1050 Self::Legacy(LiftLowerAbi::AsyncCallback)
1051 | Self::Legacy(LiftLowerAbi::AsyncStackful) => true,
1052 }
1053 }
1054}
1055
1056impl Function {
1057 pub fn item_name(&self) -> &str {
1058 match &self.kind {
1059 FunctionKind::Freestanding => &self.name,
1060 FunctionKind::AsyncFreestanding => &self.name["[async]".len()..],
1061 FunctionKind::Method(_)
1062 | FunctionKind::Static(_)
1063 | FunctionKind::AsyncMethod(_)
1064 | FunctionKind::AsyncStatic(_) => &self.name[self.name.find('.').unwrap() + 1..],
1065 FunctionKind::Constructor(_) => "constructor",
1066 }
1067 }
1068
1069 pub fn parameter_and_result_types(&self) -> impl Iterator<Item = Type> + '_ {
1074 self.params.iter().map(|(_, t)| *t).chain(self.result)
1075 }
1076
1077 pub fn standard32_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1079 self.core_export_name(interface, Mangling::Standard32)
1080 }
1081
1082 pub fn legacy_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1083 self.core_export_name(interface, Mangling::Legacy)
1084 }
1085 pub fn core_export_name<'a>(
1087 &'a self,
1088 interface: Option<&str>,
1089 mangling: Mangling,
1090 ) -> Cow<'a, str> {
1091 match interface {
1092 Some(interface) => match mangling {
1093 Mangling::Standard32 => Cow::Owned(format!("cm32p2|{interface}|{}", self.name)),
1094 Mangling::Legacy => Cow::Owned(format!("{interface}#{}", self.name)),
1095 },
1096 None => match mangling {
1097 Mangling::Standard32 => Cow::Owned(format!("cm32p2||{}", self.name)),
1098 Mangling::Legacy => Cow::Borrowed(&self.name),
1099 },
1100 }
1101 }
1102 pub fn find_futures_and_streams(&self, resolve: &Resolve) -> Vec<TypeId> {
1118 let mut results = Vec::new();
1119 for (_, ty) in self.params.iter() {
1120 find_futures_and_streams(resolve, *ty, &mut results);
1121 }
1122 if let Some(ty) = self.result {
1123 find_futures_and_streams(resolve, ty, &mut results);
1124 }
1125 results
1126 }
1127}
1128
1129fn find_futures_and_streams(resolve: &Resolve, ty: Type, results: &mut Vec<TypeId>) {
1130 let Type::Id(id) = ty else {
1131 return;
1132 };
1133
1134 match &resolve.types[id].kind {
1135 TypeDefKind::Resource
1136 | TypeDefKind::Handle(_)
1137 | TypeDefKind::Flags(_)
1138 | TypeDefKind::Enum(_) => {}
1139 TypeDefKind::Record(r) => {
1140 for Field { ty, .. } in &r.fields {
1141 find_futures_and_streams(resolve, *ty, results);
1142 }
1143 }
1144 TypeDefKind::Tuple(t) => {
1145 for ty in &t.types {
1146 find_futures_and_streams(resolve, *ty, results);
1147 }
1148 }
1149 TypeDefKind::Variant(v) => {
1150 for Case { ty, .. } in &v.cases {
1151 if let Some(ty) = ty {
1152 find_futures_and_streams(resolve, *ty, results);
1153 }
1154 }
1155 }
1156 TypeDefKind::Option(ty) | TypeDefKind::List(ty) | TypeDefKind::Type(ty) => {
1157 find_futures_and_streams(resolve, *ty, results);
1158 }
1159 TypeDefKind::Result(r) => {
1160 if let Some(ty) = r.ok {
1161 find_futures_and_streams(resolve, ty, results);
1162 }
1163 if let Some(ty) = r.err {
1164 find_futures_and_streams(resolve, ty, results);
1165 }
1166 }
1167 TypeDefKind::Future(ty) => {
1168 if let Some(ty) = ty {
1169 find_futures_and_streams(resolve, *ty, results);
1170 }
1171 results.push(id);
1172 }
1173 TypeDefKind::Stream(ty) => {
1174 if let Some(ty) = ty {
1175 find_futures_and_streams(resolve, *ty, results);
1176 }
1177 results.push(id);
1178 }
1179 TypeDefKind::Unknown => unreachable!(),
1180 }
1181}
1182
1183#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1191#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize, Serialize))]
1192#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1193pub enum Stability {
1194 Unknown,
1196
1197 Unstable {
1202 feature: String,
1203 #[cfg_attr(
1204 feature = "serde",
1205 serde(
1206 skip_serializing_if = "Option::is_none",
1207 default,
1208 serialize_with = "serialize_optional_version",
1209 deserialize_with = "deserialize_optional_version"
1210 )
1211 )]
1212 deprecated: Option<Version>,
1213 },
1214
1215 Stable {
1220 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_version"))]
1221 #[cfg_attr(feature = "serde", serde(deserialize_with = "deserialize_version"))]
1222 since: Version,
1223 #[cfg_attr(
1224 feature = "serde",
1225 serde(
1226 skip_serializing_if = "Option::is_none",
1227 default,
1228 serialize_with = "serialize_optional_version",
1229 deserialize_with = "deserialize_optional_version"
1230 )
1231 )]
1232 deprecated: Option<Version>,
1233 },
1234}
1235
1236impl Stability {
1237 pub fn is_unknown(&self) -> bool {
1239 matches!(self, Stability::Unknown)
1240 }
1241}
1242
1243impl Default for Stability {
1244 fn default() -> Stability {
1245 Stability::Unknown
1246 }
1247}
1248
1249#[cfg(test)]
1250mod test {
1251 use super::*;
1252
1253 #[test]
1254 fn test_discriminant_type() {
1255 assert_eq!(discriminant_type(1), Int::U8);
1256 assert_eq!(discriminant_type(0x100), Int::U8);
1257 assert_eq!(discriminant_type(0x101), Int::U16);
1258 assert_eq!(discriminant_type(0x10000), Int::U16);
1259 assert_eq!(discriminant_type(0x10001), Int::U32);
1260 if let Ok(num_cases) = usize::try_from(0x100000000_u64) {
1261 assert_eq!(discriminant_type(num_cases), Int::U32);
1262 }
1263 }
1264
1265 #[test]
1266 fn test_find_futures_and_streams() {
1267 let mut resolve = Resolve::default();
1268 let t0 = resolve.types.alloc(TypeDef {
1269 name: None,
1270 kind: TypeDefKind::Future(Some(Type::U32)),
1271 owner: TypeOwner::None,
1272 docs: Docs::default(),
1273 stability: Stability::Unknown,
1274 });
1275 let t1 = resolve.types.alloc(TypeDef {
1276 name: None,
1277 kind: TypeDefKind::Future(Some(Type::Id(t0))),
1278 owner: TypeOwner::None,
1279 docs: Docs::default(),
1280 stability: Stability::Unknown,
1281 });
1282 let t2 = resolve.types.alloc(TypeDef {
1283 name: None,
1284 kind: TypeDefKind::Stream(Some(Type::U32)),
1285 owner: TypeOwner::None,
1286 docs: Docs::default(),
1287 stability: Stability::Unknown,
1288 });
1289 let found = Function {
1290 name: "foo".into(),
1291 kind: FunctionKind::Freestanding,
1292 params: vec![("p1".into(), Type::Id(t1)), ("p2".into(), Type::U32)],
1293 result: Some(Type::Id(t2)),
1294 docs: Docs::default(),
1295 stability: Stability::Unknown,
1296 }
1297 .find_futures_and_streams(&resolve);
1298 assert_eq!(3, found.len());
1299 assert_eq!(t0, found[0]);
1300 assert_eq!(t1, found[1]);
1301 assert_eq!(t2, found[2]);
1302 }
1303}