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
1047impl Function {
1048 pub fn item_name(&self) -> &str {
1049 match &self.kind {
1050 FunctionKind::Freestanding => &self.name,
1051 FunctionKind::AsyncFreestanding => &self.name["[async]".len()..],
1052 FunctionKind::Method(_)
1053 | FunctionKind::Static(_)
1054 | FunctionKind::AsyncMethod(_)
1055 | FunctionKind::AsyncStatic(_) => &self.name[self.name.find('.').unwrap() + 1..],
1056 FunctionKind::Constructor(_) => "constructor",
1057 }
1058 }
1059
1060 pub fn parameter_and_result_types(&self) -> impl Iterator<Item = Type> + '_ {
1065 self.params.iter().map(|(_, t)| *t).chain(self.result)
1066 }
1067
1068 pub fn standard32_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1070 self.core_export_name(interface, Mangling::Standard32)
1071 }
1072
1073 pub fn legacy_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1074 self.core_export_name(interface, Mangling::Legacy)
1075 }
1076 pub fn core_export_name<'a>(
1078 &'a self,
1079 interface: Option<&str>,
1080 mangling: Mangling,
1081 ) -> Cow<'a, str> {
1082 match interface {
1083 Some(interface) => match mangling {
1084 Mangling::Standard32 => Cow::Owned(format!("cm32p2|{interface}|{}", self.name)),
1085 Mangling::Legacy => Cow::Owned(format!("{interface}#{}", self.name)),
1086 },
1087 None => match mangling {
1088 Mangling::Standard32 => Cow::Owned(format!("cm32p2||{}", self.name)),
1089 Mangling::Legacy => Cow::Borrowed(&self.name),
1090 },
1091 }
1092 }
1093 pub fn find_futures_and_streams(&self, resolve: &Resolve) -> Vec<TypeId> {
1109 let mut results = Vec::new();
1110 for (_, ty) in self.params.iter() {
1111 find_futures_and_streams(resolve, *ty, &mut results);
1112 }
1113 if let Some(ty) = self.result {
1114 find_futures_and_streams(resolve, ty, &mut results);
1115 }
1116 results
1117 }
1118}
1119
1120fn find_futures_and_streams(resolve: &Resolve, ty: Type, results: &mut Vec<TypeId>) {
1121 let Type::Id(id) = ty else {
1122 return;
1123 };
1124
1125 match &resolve.types[id].kind {
1126 TypeDefKind::Resource
1127 | TypeDefKind::Handle(_)
1128 | TypeDefKind::Flags(_)
1129 | TypeDefKind::Enum(_) => {}
1130 TypeDefKind::Record(r) => {
1131 for Field { ty, .. } in &r.fields {
1132 find_futures_and_streams(resolve, *ty, results);
1133 }
1134 }
1135 TypeDefKind::Tuple(t) => {
1136 for ty in &t.types {
1137 find_futures_and_streams(resolve, *ty, results);
1138 }
1139 }
1140 TypeDefKind::Variant(v) => {
1141 for Case { ty, .. } in &v.cases {
1142 if let Some(ty) = ty {
1143 find_futures_and_streams(resolve, *ty, results);
1144 }
1145 }
1146 }
1147 TypeDefKind::Option(ty) | TypeDefKind::List(ty) | TypeDefKind::Type(ty) => {
1148 find_futures_and_streams(resolve, *ty, results);
1149 }
1150 TypeDefKind::Result(r) => {
1151 if let Some(ty) = r.ok {
1152 find_futures_and_streams(resolve, ty, results);
1153 }
1154 if let Some(ty) = r.err {
1155 find_futures_and_streams(resolve, ty, results);
1156 }
1157 }
1158 TypeDefKind::Future(ty) => {
1159 if let Some(ty) = ty {
1160 find_futures_and_streams(resolve, *ty, results);
1161 }
1162 results.push(id);
1163 }
1164 TypeDefKind::Stream(ty) => {
1165 if let Some(ty) = ty {
1166 find_futures_and_streams(resolve, *ty, results);
1167 }
1168 results.push(id);
1169 }
1170 TypeDefKind::Unknown => unreachable!(),
1171 }
1172}
1173
1174#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1182#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize, Serialize))]
1183#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1184pub enum Stability {
1185 Unknown,
1187
1188 Unstable {
1193 feature: String,
1194 #[cfg_attr(
1195 feature = "serde",
1196 serde(
1197 skip_serializing_if = "Option::is_none",
1198 default,
1199 serialize_with = "serialize_optional_version",
1200 deserialize_with = "deserialize_optional_version"
1201 )
1202 )]
1203 deprecated: Option<Version>,
1204 },
1205
1206 Stable {
1211 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_version"))]
1212 #[cfg_attr(feature = "serde", serde(deserialize_with = "deserialize_version"))]
1213 since: Version,
1214 #[cfg_attr(
1215 feature = "serde",
1216 serde(
1217 skip_serializing_if = "Option::is_none",
1218 default,
1219 serialize_with = "serialize_optional_version",
1220 deserialize_with = "deserialize_optional_version"
1221 )
1222 )]
1223 deprecated: Option<Version>,
1224 },
1225}
1226
1227impl Stability {
1228 pub fn is_unknown(&self) -> bool {
1230 matches!(self, Stability::Unknown)
1231 }
1232}
1233
1234impl Default for Stability {
1235 fn default() -> Stability {
1236 Stability::Unknown
1237 }
1238}
1239
1240#[cfg(test)]
1241mod test {
1242 use super::*;
1243
1244 #[test]
1245 fn test_discriminant_type() {
1246 assert_eq!(discriminant_type(1), Int::U8);
1247 assert_eq!(discriminant_type(0x100), Int::U8);
1248 assert_eq!(discriminant_type(0x101), Int::U16);
1249 assert_eq!(discriminant_type(0x10000), Int::U16);
1250 assert_eq!(discriminant_type(0x10001), Int::U32);
1251 if let Ok(num_cases) = usize::try_from(0x100000000_u64) {
1252 assert_eq!(discriminant_type(num_cases), Int::U32);
1253 }
1254 }
1255
1256 #[test]
1257 fn test_find_futures_and_streams() {
1258 let mut resolve = Resolve::default();
1259 let t0 = resolve.types.alloc(TypeDef {
1260 name: None,
1261 kind: TypeDefKind::Future(Some(Type::U32)),
1262 owner: TypeOwner::None,
1263 docs: Docs::default(),
1264 stability: Stability::Unknown,
1265 });
1266 let t1 = resolve.types.alloc(TypeDef {
1267 name: None,
1268 kind: TypeDefKind::Future(Some(Type::Id(t0))),
1269 owner: TypeOwner::None,
1270 docs: Docs::default(),
1271 stability: Stability::Unknown,
1272 });
1273 let t2 = resolve.types.alloc(TypeDef {
1274 name: None,
1275 kind: TypeDefKind::Stream(Some(Type::U32)),
1276 owner: TypeOwner::None,
1277 docs: Docs::default(),
1278 stability: Stability::Unknown,
1279 });
1280 let found = Function {
1281 name: "foo".into(),
1282 kind: FunctionKind::Freestanding,
1283 params: vec![("p1".into(), Type::Id(t1)), ("p2".into(), Type::U32)],
1284 result: Some(Type::Id(t2)),
1285 docs: Docs::default(),
1286 stability: Stability::Unknown,
1287 }
1288 .find_futures_and_streams(&resolve);
1289 assert_eq!(3, found.len());
1290 assert_eq!(t0, found[0]);
1291 assert_eq!(t1, found[1]);
1292 assert_eq!(t2, found[2]);
1293 }
1294}