1use crate::abi::AbiVariant;
2use anyhow::{Context, Result, bail};
3use id_arena::{Arena, Id};
4use indexmap::IndexMap;
5use semver::Version;
6use std::borrow::Cow;
7use std::fmt;
8use std::hash::{Hash, Hasher};
9use std::path::Path;
10
11#[cfg(feature = "decoding")]
12pub mod decoding;
13#[cfg(feature = "decoding")]
14mod metadata;
15#[cfg(feature = "decoding")]
16pub use metadata::PackageMetadata;
17
18pub mod abi;
19mod ast;
20pub use ast::SourceMap;
21use ast::lex::Span;
22pub use ast::{ParsedUsePath, parse_use_path};
23mod sizealign;
24pub use sizealign::*;
25mod resolve;
26pub use resolve::*;
27mod live;
28pub use live::{LiveTypes, TypeIdVisitor};
29
30#[cfg(feature = "serde")]
31use serde_derive::Serialize;
32#[cfg(feature = "serde")]
33mod serde_;
34#[cfg(feature = "serde")]
35use serde_::*;
36
37pub fn validate_id(s: &str) -> Result<()> {
39 ast::validate_id(0, s)?;
40 Ok(())
41}
42
43pub type WorldId = Id<World>;
44pub type InterfaceId = Id<Interface>;
45pub type TypeId = Id<TypeDef>;
46
47#[derive(Clone)]
73pub struct UnresolvedPackage {
74 pub name: PackageName,
76
77 pub worlds: Arena<World>,
81
82 pub interfaces: Arena<Interface>,
89
90 pub types: Arena<TypeDef>,
97
98 pub foreign_deps: IndexMap<PackageName, IndexMap<String, AstItem>>,
107
108 pub docs: Docs,
110
111 package_name_span: Span,
112 unknown_type_spans: Vec<Span>,
113 interface_spans: Vec<InterfaceSpan>,
114 world_spans: Vec<WorldSpan>,
115 type_spans: Vec<Span>,
116 foreign_dep_spans: Vec<Span>,
117 required_resource_types: Vec<(TypeId, Span)>,
118}
119
120#[derive(Clone)]
122pub struct UnresolvedPackageGroup {
123 pub main: UnresolvedPackage,
128
129 pub nested: Vec<UnresolvedPackage>,
131
132 pub source_map: SourceMap,
134}
135
136#[derive(Clone)]
137struct WorldSpan {
138 span: Span,
139 imports: Vec<Span>,
140 exports: Vec<Span>,
141 includes: Vec<Span>,
142}
143
144#[derive(Clone)]
145struct InterfaceSpan {
146 span: Span,
147 funcs: Vec<Span>,
148}
149
150#[derive(Debug, Copy, Clone)]
151#[cfg_attr(feature = "serde", derive(Serialize))]
152#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
153pub enum AstItem {
154 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
155 Interface(InterfaceId),
156 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
157 World(WorldId),
158}
159
160#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
166#[cfg_attr(feature = "serde", derive(Serialize))]
167#[cfg_attr(feature = "serde", serde(into = "String"))]
168pub struct PackageName {
169 pub namespace: String,
171 pub name: String,
173 pub version: Option<Version>,
175}
176
177impl From<PackageName> for String {
178 fn from(name: PackageName) -> String {
179 name.to_string()
180 }
181}
182
183impl PackageName {
184 pub fn interface_id(&self, interface: &str) -> String {
187 let mut s = String::new();
188 s.push_str(&format!("{}:{}/{interface}", self.namespace, self.name));
189 if let Some(version) = &self.version {
190 s.push_str(&format!("@{version}"));
191 }
192 s
193 }
194
195 pub fn version_compat_track(version: &Version) -> Version {
208 let mut version = version.clone();
209 version.build = semver::BuildMetadata::EMPTY;
210 if !version.pre.is_empty() {
211 return version;
212 }
213 if version.major != 0 {
214 version.minor = 0;
215 version.patch = 0;
216 return version;
217 }
218 if version.minor != 0 {
219 version.patch = 0;
220 return version;
221 }
222 version
223 }
224
225 pub fn version_compat_track_string(version: &Version) -> String {
229 let version = Self::version_compat_track(version);
230 if !version.pre.is_empty() {
231 return version.to_string();
232 }
233 if version.major != 0 {
234 return format!("{}", version.major);
235 }
236 if version.minor != 0 {
237 return format!("{}.{}", version.major, version.minor);
238 }
239 version.to_string()
240 }
241}
242
243impl fmt::Display for PackageName {
244 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
245 write!(f, "{}:{}", self.namespace, self.name)?;
246 if let Some(version) = &self.version {
247 write!(f, "@{version}")?;
248 }
249 Ok(())
250 }
251}
252
253#[derive(Debug)]
254struct Error {
255 span: Span,
256 msg: String,
257 highlighted: Option<String>,
258}
259
260impl Error {
261 fn new(span: Span, msg: impl Into<String>) -> Error {
262 Error {
263 span,
264 msg: msg.into(),
265 highlighted: None,
266 }
267 }
268}
269
270impl fmt::Display for Error {
271 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
272 self.highlighted.as_ref().unwrap_or(&self.msg).fmt(f)
273 }
274}
275
276impl std::error::Error for Error {}
277
278#[derive(Debug)]
279struct PackageNotFoundError {
280 span: Span,
281 requested: PackageName,
282 known: Vec<PackageName>,
283 highlighted: Option<String>,
284}
285
286impl PackageNotFoundError {
287 pub fn new(span: Span, requested: PackageName, known: Vec<PackageName>) -> Self {
288 Self {
289 span,
290 requested,
291 known,
292 highlighted: None,
293 }
294 }
295}
296
297impl fmt::Display for PackageNotFoundError {
298 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
299 if let Some(highlighted) = &self.highlighted {
300 return highlighted.fmt(f);
301 }
302 if self.known.is_empty() {
303 write!(
304 f,
305 "package '{}' not found. no known packages.",
306 self.requested
307 )?;
308 } else {
309 write!(
310 f,
311 "package '{}' not found. known packages:\n",
312 self.requested
313 )?;
314 for known in self.known.iter() {
315 write!(f, " {known}\n")?;
316 }
317 }
318 Ok(())
319 }
320}
321
322impl std::error::Error for PackageNotFoundError {}
323
324impl UnresolvedPackageGroup {
325 pub fn parse(path: impl AsRef<Path>, contents: &str) -> Result<UnresolvedPackageGroup> {
331 let mut map = SourceMap::default();
332 map.push(path.as_ref(), contents);
333 map.parse()
334 }
335
336 pub fn parse_path(path: impl AsRef<Path>) -> Result<UnresolvedPackageGroup> {
342 let path = path.as_ref();
343 if path.is_dir() {
344 UnresolvedPackageGroup::parse_dir(path)
345 } else {
346 UnresolvedPackageGroup::parse_file(path)
347 }
348 }
349
350 pub fn parse_file(path: impl AsRef<Path>) -> Result<UnresolvedPackageGroup> {
355 let path = path.as_ref();
356 let contents = std::fs::read_to_string(path)
357 .with_context(|| format!("failed to read file {path:?}"))?;
358 Self::parse(path, &contents)
359 }
360
361 pub fn parse_dir(path: impl AsRef<Path>) -> Result<UnresolvedPackageGroup> {
368 let path = path.as_ref();
369 let mut map = SourceMap::default();
370 let cx = || format!("failed to read directory {path:?}");
371 for entry in path.read_dir().with_context(&cx)? {
372 let entry = entry.with_context(&cx)?;
373 let path = entry.path();
374 let ty = entry.file_type().with_context(&cx)?;
375 if ty.is_dir() {
376 continue;
377 }
378 if ty.is_symlink() {
379 if path.is_dir() {
380 continue;
381 }
382 }
383 let filename = match path.file_name().and_then(|s| s.to_str()) {
384 Some(name) => name,
385 None => continue,
386 };
387 if !filename.ends_with(".wit") {
388 continue;
389 }
390 map.push_file(&path)?;
391 }
392 map.parse()
393 }
394}
395
396#[derive(Debug, Clone)]
397#[cfg_attr(feature = "serde", derive(Serialize))]
398pub struct World {
399 pub name: String,
401
402 pub imports: IndexMap<WorldKey, WorldItem>,
404
405 pub exports: IndexMap<WorldKey, WorldItem>,
407
408 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_optional_id"))]
410 pub package: Option<PackageId>,
411
412 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
414 pub docs: Docs,
415
416 #[cfg_attr(
418 feature = "serde",
419 serde(skip_serializing_if = "Stability::is_unknown")
420 )]
421 pub stability: Stability,
422
423 #[cfg_attr(feature = "serde", serde(skip))]
425 pub includes: Vec<(Stability, WorldId)>,
426
427 #[cfg_attr(feature = "serde", serde(skip))]
429 pub include_names: Vec<Vec<IncludeName>>,
430}
431
432#[derive(Debug, Clone)]
433pub struct IncludeName {
434 pub name: String,
436
437 pub as_: String,
439}
440
441#[derive(Debug, Clone, Eq)]
444#[cfg_attr(feature = "serde", derive(Serialize))]
445#[cfg_attr(feature = "serde", serde(into = "String"))]
446pub enum WorldKey {
447 Name(String),
449 Interface(InterfaceId),
451}
452
453impl Hash for WorldKey {
454 fn hash<H: Hasher>(&self, hasher: &mut H) {
455 match self {
456 WorldKey::Name(s) => {
457 0u8.hash(hasher);
458 s.as_str().hash(hasher);
459 }
460 WorldKey::Interface(i) => {
461 1u8.hash(hasher);
462 i.hash(hasher);
463 }
464 }
465 }
466}
467
468impl PartialEq for WorldKey {
469 fn eq(&self, other: &WorldKey) -> bool {
470 match (self, other) {
471 (WorldKey::Name(a), WorldKey::Name(b)) => a.as_str() == b.as_str(),
472 (WorldKey::Name(_), _) => false,
473 (WorldKey::Interface(a), WorldKey::Interface(b)) => a == b,
474 (WorldKey::Interface(_), _) => false,
475 }
476 }
477}
478
479impl From<WorldKey> for String {
480 fn from(key: WorldKey) -> String {
481 match key {
482 WorldKey::Name(name) => name,
483 WorldKey::Interface(id) => format!("interface-{}", id.index()),
484 }
485 }
486}
487
488impl WorldKey {
489 #[track_caller]
491 pub fn unwrap_name(self) -> String {
492 match self {
493 WorldKey::Name(name) => name,
494 WorldKey::Interface(_) => panic!("expected a name, found interface"),
495 }
496 }
497}
498
499#[derive(Debug, Clone, PartialEq)]
500#[cfg_attr(feature = "serde", derive(Serialize))]
501#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
502pub enum WorldItem {
503 Interface {
506 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
507 id: InterfaceId,
508 #[cfg_attr(
509 feature = "serde",
510 serde(skip_serializing_if = "Stability::is_unknown")
511 )]
512 stability: Stability,
513 },
514
515 Function(Function),
517
518 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
522 Type(TypeId),
523}
524
525impl WorldItem {
526 pub fn stability<'a>(&'a self, resolve: &'a Resolve) -> &'a Stability {
527 match self {
528 WorldItem::Interface { stability, .. } => stability,
529 WorldItem::Function(f) => &f.stability,
530 WorldItem::Type(id) => &resolve.types[*id].stability,
531 }
532 }
533}
534
535#[derive(Debug, Clone)]
536#[cfg_attr(feature = "serde", derive(Serialize))]
537pub struct Interface {
538 pub name: Option<String>,
542
543 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id_map"))]
548 pub types: IndexMap<String, TypeId>,
549
550 pub functions: IndexMap<String, Function>,
552
553 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
555 pub docs: Docs,
556
557 #[cfg_attr(
559 feature = "serde",
560 serde(skip_serializing_if = "Stability::is_unknown")
561 )]
562 pub stability: Stability,
563
564 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_optional_id"))]
566 pub package: Option<PackageId>,
567}
568
569#[derive(Debug, Clone, PartialEq)]
570#[cfg_attr(feature = "serde", derive(Serialize))]
571pub struct TypeDef {
572 pub name: Option<String>,
573 pub kind: TypeDefKind,
574 pub owner: TypeOwner,
575 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
576 pub docs: Docs,
577 #[cfg_attr(
579 feature = "serde",
580 serde(skip_serializing_if = "Stability::is_unknown")
581 )]
582 pub stability: Stability,
583}
584
585#[derive(Debug, Clone, PartialEq, Hash, Eq)]
586#[cfg_attr(feature = "serde", derive(Serialize))]
587#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
588pub enum TypeDefKind {
589 Record(Record),
590 Resource,
591 Handle(Handle),
592 Flags(Flags),
593 Tuple(Tuple),
594 Variant(Variant),
595 Enum(Enum),
596 Option(Type),
597 Result(Result_),
598 List(Type),
599 FixedSizeList(Type, u32),
600 Future(Option<Type>),
601 Stream(Option<Type>),
602 Type(Type),
603
604 Unknown,
610}
611
612impl TypeDefKind {
613 pub fn as_str(&self) -> &'static str {
614 match self {
615 TypeDefKind::Record(_) => "record",
616 TypeDefKind::Resource => "resource",
617 TypeDefKind::Handle(handle) => match handle {
618 Handle::Own(_) => "own",
619 Handle::Borrow(_) => "borrow",
620 },
621 TypeDefKind::Flags(_) => "flags",
622 TypeDefKind::Tuple(_) => "tuple",
623 TypeDefKind::Variant(_) => "variant",
624 TypeDefKind::Enum(_) => "enum",
625 TypeDefKind::Option(_) => "option",
626 TypeDefKind::Result(_) => "result",
627 TypeDefKind::List(_) => "list",
628 TypeDefKind::FixedSizeList(..) => "fixed size list",
629 TypeDefKind::Future(_) => "future",
630 TypeDefKind::Stream(_) => "stream",
631 TypeDefKind::Type(_) => "type",
632 TypeDefKind::Unknown => "unknown",
633 }
634 }
635}
636
637#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
638#[cfg_attr(feature = "serde", derive(Serialize))]
639#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
640pub enum TypeOwner {
641 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
643 World(WorldId),
644 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
646 Interface(InterfaceId),
647 #[cfg_attr(feature = "serde", serde(untagged, serialize_with = "serialize_none"))]
650 None,
651}
652
653#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
654#[cfg_attr(feature = "serde", derive(Serialize))]
655#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
656pub enum Handle {
657 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
658 Own(TypeId),
659 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
660 Borrow(TypeId),
661}
662
663#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
664pub enum Type {
665 Bool,
666 U8,
667 U16,
668 U32,
669 U64,
670 S8,
671 S16,
672 S32,
673 S64,
674 F32,
675 F64,
676 Char,
677 String,
678 ErrorContext,
679 Id(TypeId),
680}
681
682#[derive(Debug, Copy, Clone, Eq, PartialEq)]
683pub enum Int {
684 U8,
685 U16,
686 U32,
687 U64,
688}
689
690#[derive(Debug, Clone, PartialEq, Hash, Eq)]
691#[cfg_attr(feature = "serde", derive(Serialize))]
692pub struct Record {
693 pub fields: Vec<Field>,
694}
695
696#[derive(Debug, Clone, PartialEq, Hash, Eq)]
697#[cfg_attr(feature = "serde", derive(Serialize))]
698pub struct Field {
699 pub name: String,
700 #[cfg_attr(feature = "serde", serde(rename = "type"))]
701 pub ty: Type,
702 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
703 pub docs: Docs,
704}
705
706#[derive(Debug, Clone, PartialEq, Hash, Eq)]
707#[cfg_attr(feature = "serde", derive(Serialize))]
708pub struct Flags {
709 pub flags: Vec<Flag>,
710}
711
712#[derive(Debug, Clone, PartialEq, Hash, Eq)]
713#[cfg_attr(feature = "serde", derive(Serialize))]
714pub struct Flag {
715 pub name: String,
716 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
717 pub docs: Docs,
718}
719
720#[derive(Debug, Clone, PartialEq)]
721pub enum FlagsRepr {
722 U8,
723 U16,
724 U32(usize),
725}
726
727impl Flags {
728 pub fn repr(&self) -> FlagsRepr {
729 match self.flags.len() {
730 0 => FlagsRepr::U32(0),
731 n if n <= 8 => FlagsRepr::U8,
732 n if n <= 16 => FlagsRepr::U16,
733 n => FlagsRepr::U32(sizealign::align_to(n, 32) / 32),
734 }
735 }
736}
737
738impl FlagsRepr {
739 pub fn count(&self) -> usize {
740 match self {
741 FlagsRepr::U8 => 1,
742 FlagsRepr::U16 => 1,
743 FlagsRepr::U32(n) => *n,
744 }
745 }
746}
747
748#[derive(Debug, Clone, PartialEq, Hash, Eq)]
749#[cfg_attr(feature = "serde", derive(Serialize))]
750pub struct Tuple {
751 pub types: Vec<Type>,
752}
753
754#[derive(Debug, Clone, PartialEq, Hash, Eq)]
755#[cfg_attr(feature = "serde", derive(Serialize))]
756pub struct Variant {
757 pub cases: Vec<Case>,
758}
759
760#[derive(Debug, Clone, PartialEq, Hash, Eq)]
761#[cfg_attr(feature = "serde", derive(Serialize))]
762pub struct Case {
763 pub name: String,
764 #[cfg_attr(feature = "serde", serde(rename = "type"))]
765 pub ty: Option<Type>,
766 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
767 pub docs: Docs,
768}
769
770impl Variant {
771 pub fn tag(&self) -> Int {
772 discriminant_type(self.cases.len())
773 }
774}
775
776#[derive(Debug, Clone, PartialEq, Hash, Eq)]
777#[cfg_attr(feature = "serde", derive(Serialize))]
778pub struct Enum {
779 pub cases: Vec<EnumCase>,
780}
781
782#[derive(Debug, Clone, PartialEq, Hash, Eq)]
783#[cfg_attr(feature = "serde", derive(Serialize))]
784pub struct EnumCase {
785 pub name: String,
786 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
787 pub docs: Docs,
788}
789
790impl Enum {
791 pub fn tag(&self) -> Int {
792 discriminant_type(self.cases.len())
793 }
794}
795
796fn discriminant_type(num_cases: usize) -> Int {
798 match num_cases.checked_sub(1) {
799 None => Int::U8,
800 Some(n) if n <= u8::max_value() as usize => Int::U8,
801 Some(n) if n <= u16::max_value() as usize => Int::U16,
802 Some(n) if n <= u32::max_value() as usize => Int::U32,
803 _ => panic!("too many cases to fit in a repr"),
804 }
805}
806
807#[derive(Debug, Clone, PartialEq, Hash, Eq)]
808#[cfg_attr(feature = "serde", derive(Serialize))]
809pub struct Result_ {
810 pub ok: Option<Type>,
811 pub err: Option<Type>,
812}
813
814#[derive(Clone, Default, Debug, PartialEq, Eq, Hash)]
815#[cfg_attr(feature = "serde", derive(Serialize))]
816pub struct Docs {
817 pub contents: Option<String>,
818}
819
820impl Docs {
821 pub fn is_empty(&self) -> bool {
822 self.contents.is_none()
823 }
824}
825
826#[derive(Debug, Clone, PartialEq, Eq)]
827#[cfg_attr(feature = "serde", derive(Serialize))]
828pub struct Function {
829 pub name: String,
830 pub kind: FunctionKind,
831 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_params"))]
832 pub params: Vec<(String, Type)>,
833 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
834 pub result: Option<Type>,
835 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))]
836 pub docs: Docs,
837 #[cfg_attr(
839 feature = "serde",
840 serde(skip_serializing_if = "Stability::is_unknown")
841 )]
842 pub stability: Stability,
843}
844
845#[derive(Debug, Clone, PartialEq, Eq)]
846#[cfg_attr(feature = "serde", derive(Serialize))]
847#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
848pub enum FunctionKind {
849 Freestanding,
857
858 AsyncFreestanding,
866
867 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
878 Method(TypeId),
879
880 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
891 AsyncMethod(TypeId),
892
893 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
903 Static(TypeId),
904
905 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
915 AsyncStatic(TypeId),
916
917 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_id"))]
927 Constructor(TypeId),
928}
929
930impl FunctionKind {
931 pub fn is_async(&self) -> bool {
933 match self {
934 FunctionKind::Freestanding
935 | FunctionKind::Method(_)
936 | FunctionKind::Static(_)
937 | FunctionKind::Constructor(_) => false,
938 FunctionKind::AsyncFreestanding
939 | FunctionKind::AsyncMethod(_)
940 | FunctionKind::AsyncStatic(_) => true,
941 }
942 }
943
944 pub fn resource(&self) -> Option<TypeId> {
946 match self {
947 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
948 FunctionKind::Method(id)
949 | FunctionKind::Static(id)
950 | FunctionKind::Constructor(id)
951 | FunctionKind::AsyncMethod(id)
952 | FunctionKind::AsyncStatic(id) => Some(*id),
953 }
954 }
955
956 pub fn resource_mut(&mut self) -> Option<&mut TypeId> {
958 match self {
959 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => None,
960 FunctionKind::Method(id)
961 | FunctionKind::Static(id)
962 | FunctionKind::Constructor(id)
963 | FunctionKind::AsyncMethod(id)
964 | FunctionKind::AsyncStatic(id) => Some(id),
965 }
966 }
967}
968
969#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
971pub enum Mangling {
972 Standard32,
975
976 Legacy,
981}
982
983impl std::str::FromStr for Mangling {
984 type Err = anyhow::Error;
985
986 fn from_str(s: &str) -> Result<Mangling> {
987 match s {
988 "legacy" => Ok(Mangling::Legacy),
989 "standard32" => Ok(Mangling::Standard32),
990 _ => {
991 bail!(
992 "unknown name mangling `{s}`, \
993 supported values are `legacy` or `standard32`"
994 )
995 }
996 }
997 }
998}
999
1000#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1002pub enum LiftLowerAbi {
1003 Sync,
1005
1006 AsyncCallback,
1009
1010 AsyncStackful,
1013}
1014
1015impl LiftLowerAbi {
1016 fn import_prefix(self) -> &'static str {
1017 match self {
1018 Self::Sync => "",
1019 Self::AsyncCallback | Self::AsyncStackful => "[async-lower]",
1020 }
1021 }
1022
1023 pub fn import_variant(self) -> AbiVariant {
1025 match self {
1026 Self::Sync => AbiVariant::GuestImport,
1027 Self::AsyncCallback | Self::AsyncStackful => AbiVariant::GuestImportAsync,
1028 }
1029 }
1030
1031 fn export_prefix(self) -> &'static str {
1032 match self {
1033 Self::Sync => "",
1034 Self::AsyncCallback => "[async-lift]",
1035 Self::AsyncStackful => "[async-lift-stackful]",
1036 }
1037 }
1038
1039 pub fn export_variant(self) -> AbiVariant {
1041 match self {
1042 Self::Sync => AbiVariant::GuestExport,
1043 Self::AsyncCallback => AbiVariant::GuestExportAsync,
1044 Self::AsyncStackful => AbiVariant::GuestExportAsyncStackful,
1045 }
1046 }
1047}
1048
1049#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1051pub enum ManglingAndAbi {
1052 Standard32,
1057
1058 Legacy(LiftLowerAbi),
1060}
1061
1062impl ManglingAndAbi {
1063 pub fn import_variant(self) -> AbiVariant {
1065 match self {
1066 Self::Standard32 => AbiVariant::GuestImport,
1067 Self::Legacy(abi) => abi.import_variant(),
1068 }
1069 }
1070
1071 pub fn export_variant(self) -> AbiVariant {
1073 match self {
1074 Self::Standard32 => AbiVariant::GuestExport,
1075 Self::Legacy(abi) => abi.export_variant(),
1076 }
1077 }
1078
1079 pub fn sync(self) -> Self {
1081 match self {
1082 Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => self,
1083 Self::Legacy(LiftLowerAbi::AsyncCallback)
1084 | Self::Legacy(LiftLowerAbi::AsyncStackful) => Self::Legacy(LiftLowerAbi::Sync),
1085 }
1086 }
1087
1088 pub fn is_async(&self) -> bool {
1090 match self {
1091 Self::Standard32 | Self::Legacy(LiftLowerAbi::Sync) => false,
1092 Self::Legacy(LiftLowerAbi::AsyncCallback)
1093 | Self::Legacy(LiftLowerAbi::AsyncStackful) => true,
1094 }
1095 }
1096
1097 pub fn mangling(&self) -> Mangling {
1098 match self {
1099 Self::Standard32 => Mangling::Standard32,
1100 Self::Legacy(_) => Mangling::Legacy,
1101 }
1102 }
1103}
1104
1105impl Function {
1106 pub fn item_name(&self) -> &str {
1107 match &self.kind {
1108 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => &self.name,
1109 FunctionKind::Method(_)
1110 | FunctionKind::Static(_)
1111 | FunctionKind::AsyncMethod(_)
1112 | FunctionKind::AsyncStatic(_) => &self.name[self.name.find('.').unwrap() + 1..],
1113 FunctionKind::Constructor(_) => "constructor",
1114 }
1115 }
1116
1117 pub fn parameter_and_result_types(&self) -> impl Iterator<Item = Type> + '_ {
1122 self.params.iter().map(|(_, t)| *t).chain(self.result)
1123 }
1124
1125 pub fn standard32_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1127 self.core_export_name(interface, Mangling::Standard32)
1128 }
1129
1130 pub fn legacy_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
1131 self.core_export_name(interface, Mangling::Legacy)
1132 }
1133 pub fn core_export_name<'a>(
1135 &'a self,
1136 interface: Option<&str>,
1137 mangling: Mangling,
1138 ) -> Cow<'a, str> {
1139 match interface {
1140 Some(interface) => match mangling {
1141 Mangling::Standard32 => Cow::Owned(format!("cm32p2|{interface}|{}", self.name)),
1142 Mangling::Legacy => Cow::Owned(format!("{interface}#{}", self.name)),
1143 },
1144 None => match mangling {
1145 Mangling::Standard32 => Cow::Owned(format!("cm32p2||{}", self.name)),
1146 Mangling::Legacy => Cow::Borrowed(&self.name),
1147 },
1148 }
1149 }
1150 pub fn find_futures_and_streams(&self, resolve: &Resolve) -> Vec<TypeId> {
1166 let mut results = Vec::new();
1167 for (_, ty) in self.params.iter() {
1168 find_futures_and_streams(resolve, *ty, &mut results);
1169 }
1170 if let Some(ty) = self.result {
1171 find_futures_and_streams(resolve, ty, &mut results);
1172 }
1173 results
1174 }
1175
1176 pub fn is_constructor_shorthand(&self, resolve: &Resolve) -> bool {
1179 let FunctionKind::Constructor(containing_resource_id) = self.kind else {
1180 return false;
1181 };
1182
1183 let Some(Type::Id(id)) = &self.result else {
1184 return false;
1185 };
1186
1187 let TypeDefKind::Handle(Handle::Own(returned_resource_id)) = resolve.types[*id].kind else {
1188 return false;
1189 };
1190
1191 return containing_resource_id == returned_resource_id;
1192 }
1193
1194 pub fn task_return_import(
1197 &self,
1198 resolve: &Resolve,
1199 interface: Option<&WorldKey>,
1200 mangling: Mangling,
1201 ) -> (String, String, abi::WasmSignature) {
1202 match mangling {
1203 Mangling::Standard32 => todo!(),
1204 Mangling::Legacy => {}
1205 }
1206 let module = match interface {
1208 Some(key) => format!("[export]{}", resolve.name_world_key(key)),
1209 None => "[export]$root".to_string(),
1210 };
1211 let name = format!("[task-return]{}", self.name);
1212
1213 let mut func_tmp = self.clone();
1214 func_tmp.params = Vec::new();
1215 func_tmp.result = None;
1216 if let Some(ty) = self.result {
1217 func_tmp.params.push(("x".to_string(), ty));
1218 }
1219 let sig = resolve.wasm_signature(AbiVariant::GuestImport, &func_tmp);
1220 (module, name, sig)
1221 }
1222
1223 }
1225
1226fn find_futures_and_streams(resolve: &Resolve, ty: Type, results: &mut Vec<TypeId>) {
1227 let Type::Id(id) = ty else {
1228 return;
1229 };
1230
1231 match &resolve.types[id].kind {
1232 TypeDefKind::Resource
1233 | TypeDefKind::Handle(_)
1234 | TypeDefKind::Flags(_)
1235 | TypeDefKind::Enum(_) => {}
1236 TypeDefKind::Record(r) => {
1237 for Field { ty, .. } in &r.fields {
1238 find_futures_and_streams(resolve, *ty, results);
1239 }
1240 }
1241 TypeDefKind::Tuple(t) => {
1242 for ty in &t.types {
1243 find_futures_and_streams(resolve, *ty, results);
1244 }
1245 }
1246 TypeDefKind::Variant(v) => {
1247 for Case { ty, .. } in &v.cases {
1248 if let Some(ty) = ty {
1249 find_futures_and_streams(resolve, *ty, results);
1250 }
1251 }
1252 }
1253 TypeDefKind::Option(ty)
1254 | TypeDefKind::List(ty)
1255 | TypeDefKind::FixedSizeList(ty, ..)
1256 | TypeDefKind::Type(ty) => {
1257 find_futures_and_streams(resolve, *ty, results);
1258 }
1259 TypeDefKind::Result(r) => {
1260 if let Some(ty) = r.ok {
1261 find_futures_and_streams(resolve, ty, results);
1262 }
1263 if let Some(ty) = r.err {
1264 find_futures_and_streams(resolve, ty, results);
1265 }
1266 }
1267 TypeDefKind::Future(ty) => {
1268 if let Some(ty) = ty {
1269 find_futures_and_streams(resolve, *ty, results);
1270 }
1271 results.push(id);
1272 }
1273 TypeDefKind::Stream(ty) => {
1274 if let Some(ty) = ty {
1275 find_futures_and_streams(resolve, *ty, results);
1276 }
1277 results.push(id);
1278 }
1279 TypeDefKind::Unknown => unreachable!(),
1280 }
1281}
1282
1283#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1291#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize, Serialize))]
1292#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1293pub enum Stability {
1294 Unknown,
1296
1297 Unstable {
1302 feature: String,
1303 #[cfg_attr(
1304 feature = "serde",
1305 serde(
1306 skip_serializing_if = "Option::is_none",
1307 default,
1308 serialize_with = "serialize_optional_version",
1309 deserialize_with = "deserialize_optional_version"
1310 )
1311 )]
1312 deprecated: Option<Version>,
1313 },
1314
1315 Stable {
1320 #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_version"))]
1321 #[cfg_attr(feature = "serde", serde(deserialize_with = "deserialize_version"))]
1322 since: Version,
1323 #[cfg_attr(
1324 feature = "serde",
1325 serde(
1326 skip_serializing_if = "Option::is_none",
1327 default,
1328 serialize_with = "serialize_optional_version",
1329 deserialize_with = "deserialize_optional_version"
1330 )
1331 )]
1332 deprecated: Option<Version>,
1333 },
1334}
1335
1336impl Stability {
1337 pub fn is_unknown(&self) -> bool {
1339 matches!(self, Stability::Unknown)
1340 }
1341
1342 pub fn is_stable(&self) -> bool {
1343 matches!(self, Stability::Stable { .. })
1344 }
1345}
1346
1347impl Default for Stability {
1348 fn default() -> Stability {
1349 Stability::Unknown
1350 }
1351}
1352
1353#[cfg(test)]
1354mod test {
1355 use super::*;
1356
1357 #[test]
1358 fn test_discriminant_type() {
1359 assert_eq!(discriminant_type(1), Int::U8);
1360 assert_eq!(discriminant_type(0x100), Int::U8);
1361 assert_eq!(discriminant_type(0x101), Int::U16);
1362 assert_eq!(discriminant_type(0x10000), Int::U16);
1363 assert_eq!(discriminant_type(0x10001), Int::U32);
1364 if let Ok(num_cases) = usize::try_from(0x100000000_u64) {
1365 assert_eq!(discriminant_type(num_cases), Int::U32);
1366 }
1367 }
1368
1369 #[test]
1370 fn test_find_futures_and_streams() {
1371 let mut resolve = Resolve::default();
1372 let t0 = resolve.types.alloc(TypeDef {
1373 name: None,
1374 kind: TypeDefKind::Future(Some(Type::U32)),
1375 owner: TypeOwner::None,
1376 docs: Docs::default(),
1377 stability: Stability::Unknown,
1378 });
1379 let t1 = resolve.types.alloc(TypeDef {
1380 name: None,
1381 kind: TypeDefKind::Future(Some(Type::Id(t0))),
1382 owner: TypeOwner::None,
1383 docs: Docs::default(),
1384 stability: Stability::Unknown,
1385 });
1386 let t2 = resolve.types.alloc(TypeDef {
1387 name: None,
1388 kind: TypeDefKind::Stream(Some(Type::U32)),
1389 owner: TypeOwner::None,
1390 docs: Docs::default(),
1391 stability: Stability::Unknown,
1392 });
1393 let found = Function {
1394 name: "foo".into(),
1395 kind: FunctionKind::Freestanding,
1396 params: vec![("p1".into(), Type::Id(t1)), ("p2".into(), Type::U32)],
1397 result: Some(Type::Id(t2)),
1398 docs: Docs::default(),
1399 stability: Stability::Unknown,
1400 }
1401 .find_futures_and_streams(&resolve);
1402 assert_eq!(3, found.len());
1403 assert_eq!(t0, found[0]);
1404 assert_eq!(t1, found[1]);
1405 assert_eq!(t2, found[2]);
1406 }
1407}